Lots of Ruby code generation improvements
Summary: Submitted by Kevin Clark, Ruby guru from Powerset
Reviewed By: mcslee
Test Plan: He updated the tests in trunk/test/rb/
Notes: The code is now officially "ruby-ish" and idiomatic
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665151 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index 4c7d15f..98d0008 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -17,8 +17,8 @@
src/generate/t_perl_generator.cc \
src/generate/t_erl_generator.cc
-thrift_CXXFLAGS = -Wall -Isrc
-thrift_LDFLAGS = -Wall
+thrift_CXXFLAGS = -Wall -Isrc $(BOOST_CPPFLAGS)
+thrift_LDFLAGS = -Wall $(BOOST_LDFLAGS)
thrift_LDADD = @LEXLIB@
diff --git a/compiler/cpp/bootstrap.sh b/compiler/cpp/bootstrap.sh
index 3189372..67b6eea 100755
--- a/compiler/cpp/bootstrap.sh
+++ b/compiler/cpp/bootstrap.sh
@@ -2,7 +2,7 @@
./cleanup.sh
autoscan
-aclocal
+aclocal -I ../../lib/cpp/aclocal
libtoolize --automake
touch NEWS README AUTHORS ChangeLog
autoconf
diff --git a/compiler/cpp/configure.ac b/compiler/cpp/configure.ac
index f6aa0f5..2e4b603 100644
--- a/compiler/cpp/configure.ac
+++ b/compiler/cpp/configure.ac
@@ -10,6 +10,8 @@
AC_CHECK_HEADERS([stddef.h])
+AX_BOOST_BASE([1.33.1])
+
AC_CHECK_FUNCS([mkdir])
AC_CHECK_FUNCS([realpath])
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
index 9932afd..bb88465 100644
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -33,12 +33,15 @@
rb_autogen_comment() << endl <<
rb_imports() << endl <<
render_includes() << endl;
+ begin_namespace(f_types_, ruby_modules(program_));
f_consts_ <<
rb_autogen_comment() << endl <<
rb_imports() << endl <<
"require '" << program_name_ << "_types'" << endl <<
endl;
+ begin_namespace(f_consts_, ruby_modules(program_));
+
}
/**
@@ -81,6 +84,8 @@
*/
void t_rb_generator::close_generator() {
// Close types file
+ end_namespace(f_types_, ruby_modules(program_));
+ end_namespace(f_consts_, ruby_modules(program_));
f_types_.close();
f_consts_.close();
}
@@ -99,7 +104,7 @@
* @param tenum The enumeration
*/
void t_rb_generator::generate_enum(t_enum* tenum) {
- f_types_ <<
+ indent(f_types_) <<
"module " << tenum->get_name() << endl;
indent_up();
@@ -123,9 +128,8 @@
}
indent_down();
- f_types_ <<
- "end" << endl <<
- endl;
+ indent(f_types_) <<
+ "end" << endl << endl;
}
/**
@@ -254,7 +258,7 @@
* Generates a ruby struct
*/
void t_rb_generator::generate_struct(t_struct* tstruct) {
- generate_rb_struct(tstruct, false);
+ generate_rb_struct(f_types_, tstruct, false);
}
/**
@@ -264,232 +268,109 @@
* @param txception The struct definition
*/
void t_rb_generator::generate_xception(t_struct* txception) {
- generate_rb_struct(txception, true);
+ generate_rb_struct(f_types_, txception, true);
}
/**
* Generates a ruby struct
*/
-void t_rb_generator::generate_rb_struct(t_struct* tstruct,
- bool is_exception) {
- generate_rb_struct_definition(f_types_, tstruct, is_exception);
-}
-
-/**
- * Generates a struct definition for a thrift data type. This is nothing in PHP
- * where the objects are all just associative arrays (unless of course we
- * decide to start using objects for them...)
- *
- * @param tstruct The struct definition
- */
-void t_rb_generator::generate_rb_struct_definition(ofstream& out,
- t_struct* tstruct,
- bool is_exception,
- bool is_result) {
- const vector<t_field*>& members = tstruct->get_members();
- vector<t_field*>::const_iterator m_iter;
-
- indent(out) <<
- "class " << type_name(tstruct);
+void t_rb_generator::generate_rb_struct(std::ofstream& out, t_struct* tstruct, bool is_exception = false) {
+ indent(out) << "class " << type_name(tstruct);
if (is_exception) {
out << " < StandardError";
}
- out << endl;
- indent_up();
-
- out << endl;
-
- if (members.size() > 0) {
- indent(out) << "attr_writer ";
- bool first = true;
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- if (first) {
- first = false;
- } else {
- out << ", ";
- }
- out << ":" << (*m_iter)->get_name();
- }
- out << endl;
- indent(out) << "attr_reader ";
- first = true;
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- if (first) {
- first = false;
- } else {
- out << ", ";
- }
- out << ":" << (*m_iter)->get_name();
- }
- out << endl;
- out << endl;
- }
-
- out <<
- indent() << "def initialize(d=nil)" << endl;
- indent_up();
-
- if (members.size() > 0) {
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- if ((*m_iter)->get_value() != NULL) {
- indent(out) << declare_field(*m_iter) << endl;
- }
- }
- indent(out) <<
- "if (d != nil)" << endl;
- indent_up();
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- out <<
- indent() << "if (d.has_key?('" << (*m_iter)->get_name() << "'))" << endl <<
- indent() << " @" << (*m_iter)->get_name() << " = d['" << (*m_iter)->get_name() << "']" << endl <<
- indent() << "end" << endl;
- }
- indent_down();
- indent(out) << "end" << endl;
- }
+ out << endl;
- indent_down();
- indent(out) << "end" << endl;
-
- out << endl;
-
- generate_rb_struct_reader(out, tstruct);
- generate_rb_struct_writer(out, tstruct);
+ indent_up();
+ indent(out) << "include ThriftStruct" << endl;
+
+ generate_accessors(out, tstruct);
+ generate_field_defns(out, tstruct);
indent_down();
indent(out) << "end" << endl << endl;
}
-/**
- * Generates the read method for a struct
- */
-void t_rb_generator::generate_rb_struct_reader(ofstream& out,
- t_struct* tstruct) {
- const vector<t_field*>& fields = tstruct->get_members();
- vector<t_field*>::const_iterator f_iter;
-
- indent(out) <<
- "def read(iprot)" << endl;
- indent_up();
+void t_rb_generator::generate_accessors(std::ofstream& out, t_struct* tstruct) {
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
- indent(out) <<
- "iprot.readStructBegin()" << endl;
-
- // Loop over reading in fields
- indent(out) <<
- "while true" << endl;
- indent_up();
-
- // Read beginning field marker
- indent(out) <<
- "fname, ftype, fid = iprot.readFieldBegin()" << endl;
-
- // Check for field STOP marker and break
- indent(out) <<
- "if (ftype === TType::STOP)" << endl;
- indent_up();
- indent(out) <<
- "break" << endl;
- indent_down();
- if (fields.size() > 0) {
- indent(out) <<
- "end" << endl;
- }
-
- // Switch statement on the field we are reading
- bool first = true;
-
- // Generate deserialization code for known cases
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- if (first) {
- first = false;
- out <<
- indent() << "if ";
- } else {
- out <<
- indent() << "elsif ";
+ if (members.size() > 0) {
+ indent(out) << "attr_accessor ";
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if (m_iter != members.begin()) {
+ out << ", ";
}
- out << "(fid == " << (*f_iter)->get_key() << ")" << endl;
- indent_up();
- indent(out) << "if (ftype === " << type_to_enum((*f_iter)->get_type()) << ")" << endl;
- indent_up();
- generate_deserialize_field(out, *f_iter, "@");
- indent_down();
- out <<
- indent() << "else" << endl <<
- indent() << " iprot.skip(ftype)" << endl <<
- indent() << "end" << endl;
- indent_down();
+ out << ":" << (*m_iter)->get_name();
}
-
- // In the default case we skip the field
- out <<
- indent() << "else" << endl <<
- indent() << " iprot.skip(ftype)" << endl <<
- indent() << "end" << endl;
-
- // Read field end marker
- indent(out) <<
- "iprot.readFieldEnd()" << endl;
-
- indent_down();
- indent(out) << "end" << endl;
-
- indent(out) <<
- "iprot.readStructEnd()" << endl;
-
- indent_down();
- indent(out) << "end" << endl;
- out << endl;
+ out << endl;
+ }
}
-void t_rb_generator::generate_rb_struct_writer(ofstream& out,
- t_struct* tstruct) {
- string name = tstruct->get_name();
+void t_rb_generator::generate_field_defns(std::ofstream& out, t_struct* tstruct) {
const vector<t_field*>& fields = tstruct->get_members();
vector<t_field*>::const_iterator f_iter;
-
- indent(out) <<
- "def write(oprot)" << endl;
- indent_up();
- indent(out) <<
- "oprot.writeStructBegin('" << name << "')" << endl;
-
+ indent(out) << "FIELDS = {" << endl;
+ indent_up();
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- // Write field header
- indent(out) <<
- "if (@" << (*f_iter)->get_name() << " != nil)" << endl;
+ if (f_iter != fields.begin()) {
+ out << "," << endl;
+ }
+
+ indent(out) <<
+ (*f_iter)->get_key() << " => ";
+
+ generate_field_data(out, (*f_iter)->get_type(), (*f_iter)->get_name());
+ }
+ indent_down();
+ out << endl;
+ indent(out) << "}" << endl;
+}
+
+void t_rb_generator::generate_field_data(std::ofstream& out, t_type* field_type, const std::string& field_name = "") {
+ // Begin this field's defn
+ out << "{:type => " << type_to_enum(field_type);
+
+ if (!field_name.empty())
+ out << ", :name => '" << field_name << "'";
+
+ if (! field_type->is_base_type()) {
+ if (field_type->is_struct()) {
+ out << ", :class => " << type_name(((t_struct*)field_type));
+ } else if (field_type->is_list()) {
+ out << ", :element => ";
+ generate_field_data(out, ((t_list*)field_type)->get_elem_type());
+ } else if (field_type->is_map()) {
+ out << ", :key => ";
+ generate_field_data(out, ((t_map*)field_type)->get_key_type());
+ out << ", :value => ";
+ generate_field_data(out, ((t_map*)field_type)->get_val_type());
+ } else if (field_type->is_set()) {
+ out << ", :element => ";
+ generate_field_data(out, ((t_set*)field_type)->get_elem_type());
+ }
+ }
+
+ // End of this field's defn
+ out << "}";
+}
+
+void t_rb_generator::begin_namespace(std::ofstream& out, vector<std::string> modules) {
+ for (vector<std::string>::iterator m_iter = modules.begin(); m_iter != modules.end(); ++m_iter) {
+ indent(out) << "module " << *m_iter << endl;
indent_up();
- indent(out) <<
- "oprot.writeFieldBegin(" <<
- "'" << (*f_iter)->get_name() << "', " <<
- type_to_enum((*f_iter)->get_type()) << ", " <<
- (*f_iter)->get_key() << ")" << endl;
+ }
+}
- // Write field contents
- generate_serialize_field(out, *f_iter, "@");
-
- // Write field closer
- indent(out) <<
- "oprot.writeFieldEnd()" << endl;
-
+void t_rb_generator::end_namespace(std::ofstream& out, vector<std::string> modules) {
+ for (vector<std::string>::reverse_iterator m_iter = modules.rbegin(); m_iter != modules.rend(); ++m_iter) {
indent_down();
indent(out) << "end" << endl;
}
-
- // Write the struct map
- out <<
- indent() << "oprot.writeFieldStop()" << endl <<
- indent() << "oprot.writeStructEnd()" << endl;
-
- indent_down();
- indent(out) << "end" << endl;
-
- out <<
- endl;
}
+
/**
* Generates a thrift service.
*
@@ -513,18 +394,21 @@
"require '" << program_name_ << "_types'" << endl <<
endl;
- f_service_ << "module " << tservice->get_name() << endl;
+ begin_namespace(f_service_, ruby_modules(tservice->get_program()));
+
+ indent(f_service_) << "module " << tservice->get_name() << endl;
indent_up();
// Generate the three main parts of the service (well, two for now in PHP)
- generate_service_interface(tservice);
generate_service_client(tservice);
generate_service_server(tservice);
generate_service_helpers(tservice);
indent_down();
- f_service_ << "end" << endl <<
+ indent(f_service_) << "end" << endl <<
endl;
+
+ end_namespace(f_service_, ruby_modules(tservice->get_program()));
// Close service file
f_service_.close();
@@ -544,7 +428,7 @@
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
t_struct* ts = (*f_iter)->get_arglist();
- generate_rb_struct_definition(f_service_, ts, false);
+ generate_rb_struct(f_service_, ts);
generate_rb_function_helpers(*f_iter);
}
}
@@ -567,33 +451,7 @@
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
result.append(*f_iter);
}
- generate_rb_struct_definition(f_service_, &result, false, true);
-}
-
-/**
- * Generates a service interface definition.
- *
- * @param tservice The service to generate a header definition for
- */
-void t_rb_generator::generate_service_interface(t_service* tservice) {
- f_service_ <<
- indent() << "module Iface" << endl;
- indent_up();
-
- if (tservice->get_extends() != NULL) {
- string extends = type_name(tservice->get_extends());
- indent(f_service_) << "include " << extends << "::Iface" << endl;
- }
-
- vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
- for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
- f_service_ <<
- indent() << "def " << function_signature(*f_iter) << "" << endl <<
- indent() << "end" << endl << endl;
- }
- indent_down();
- indent(f_service_) << "end" << endl << endl;
+ generate_rb_struct(f_service_, &result);
}
/**
@@ -614,24 +472,8 @@
indent_up();
indent(f_service_) <<
- "include Iface" << endl << endl;
+ "include ThriftClient" << endl << endl;
- // Constructor function
- f_service_ <<
- indent() << "def initialize(iprot, oprot=nil)" << endl;
- if (extends.empty()) {
- f_service_ <<
- indent() << " @iprot = @oprot = iprot" << endl <<
- indent() << " if (oprot != nil)" << endl <<
- indent() << " @oprot = oprot" << endl <<
- indent() << " end" << endl <<
- indent() << " @seqid = 0" << endl;
- } else {
- f_service_ <<
- indent() << " super(iprot, oprot)" << endl;
- }
- indent(f_service_) << "end" << endl << endl;
-
// Generate client method implementations
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::const_iterator f_iter;
@@ -677,23 +519,13 @@
std::string argsname = capitalize((*f_iter)->get_name() + "_args");
- // Serialize the request header
- f_service_ <<
- indent() << "@oprot.writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, @seqid)" << endl;
-
- f_service_ <<
- indent() << "args = " << argsname << ".new()" << endl;
-
+ indent(f_service_) << "send_message('" << funname << "', " << argsname;
+
for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
- f_service_ <<
- indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << endl;
- }
-
- // Write to the stream
- f_service_ <<
- indent() << "args.write(@oprot)" << endl <<
- indent() << "@oprot.writeMessageEnd()" << endl <<
- indent() << "@oprot.trans.flush()" << endl;
+ f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name();
+ }
+
+ f_service_ << ")" << endl;
indent_down();
indent(f_service_) << "end" << endl;
@@ -714,35 +546,21 @@
// TODO(mcslee): Validate message reply here, seq ids etc.
f_service_ <<
- indent() << "fname, mtype, rseqid = @iprot.readMessageBegin()" << endl <<
- indent() << "if mtype == TMessageType::EXCEPTION" << endl <<
- indent() << " x = TApplicationException.new()" << endl <<
- indent() << " x.read(@iprot)" << endl <<
- indent() << " @iprot.readMessageEnd()" << endl <<
- indent() << " raise x" << endl <<
- indent() << "end" << endl;
-
- f_service_ <<
- indent() << "result = " << resultname << ".new()" << endl <<
- indent() << "result.read(@iprot)" << endl <<
- indent() << "@iprot.readMessageEnd()" << endl;
-
+ indent() << "result = receive_message(" << resultname << ")" << endl;
+
// Careful, only return _result if not a void function
if (!(*f_iter)->get_returntype()->is_void()) {
f_service_ <<
- indent() << "if result.success != nil" << endl <<
- indent() << " return result.success" << endl <<
- indent() << "end" << endl;
+ indent() << "return result.success unless result.success.nil?" << endl;
}
t_struct* xs = (*f_iter)->get_xceptions();
const std::vector<t_field*>& xceptions = xs->get_members();
vector<t_field*>::const_iterator x_iter;
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
- f_service_ <<
- indent() << "if result." << (*x_iter)->get_name() << " != nil" << endl <<
- indent() << " raise result." << (*x_iter)->get_name() << "" << endl <<
- indent() << "end" << endl;
+ indent(f_service_) <<
+ "raise result." << (*x_iter)->get_name() <<
+ " unless result." << (*x_iter)->get_name() << ".nil?" << endl;
}
// Careful, only return _result if not a void function
@@ -787,60 +605,9 @@
indent_up();
f_service_ <<
- indent() << "include Iface" << endl <<
indent() << "include TProcessor" << endl <<
endl;
- indent(f_service_) <<
- "def initialize(handler)" << endl;
- indent_up();
- if (extends.empty()) {
- f_service_ <<
- indent() << "@handler = handler" << endl <<
- indent() << "@processMap = {}" << endl;
- } else {
- f_service_ <<
- indent() << "super(handler)" << endl;
- }
- for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
- f_service_ <<
- indent() << "@processMap['" << (*f_iter)->get_name() << "'] = method(:process_" << (*f_iter)->get_name() << ")" << endl;
- }
- indent_down();
- indent(f_service_) << "end" << endl << endl;
-
- // Generate the server implementation
- indent(f_service_) <<
- "def process(iprot, oprot)" << endl;
- indent_up();
-
- f_service_ <<
- indent() << "name, type, seqid = iprot.readMessageBegin()" << endl;
-
- // TODO(mcslee): validate message
-
- // HOT: dictionary function lookup
- f_service_ <<
- indent() << "if (@processMap.has_key?(name))" << endl <<
- indent() << " @processMap[name].call(seqid, iprot, oprot)" << endl <<
- indent() << "else" << endl <<
- indent() << " iprot.skip(TType::STRUCT)" << endl <<
- indent() << " iprot.readMessageEnd()" << endl <<
- indent() << " x = TApplicationException.new(TApplicationException::UNKNOWN_METHOD, 'Unknown function '+name)" << endl <<
- indent() << " oprot.writeMessageBegin(name, TMessageType::EXCEPTION, seqid)" << endl <<
- indent() << " x.write(oprot)" << endl <<
- indent() << " oprot.writeMessageEnd()" << endl <<
- indent() << " oprot.trans.flush()" << endl <<
- indent() << " return" << endl <<
- indent() << "end" << endl;
-
- // Read end of args field, the T_STOP, and the struct close
- f_service_ <<
- indent() << "return true" << endl;
-
- indent_down();
- indent(f_service_) << "end" << endl << endl;
-
// Generate the process subfunctions
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
generate_process_function(tservice, *f_iter);
@@ -867,9 +634,7 @@
string resultname = capitalize(tfunction->get_name()) + "_result";
f_service_ <<
- indent() << "args = " << argsname << ".new()" << endl <<
- indent() << "args.read(iprot)" << endl <<
- indent() << "iprot.readMessageEnd()" << endl;
+ indent() << "args = read_args(iprot, " << argsname << ")" << endl;
t_struct* xs = tfunction->get_xceptions();
const std::vector<t_field*>& xceptions = xs->get_members();
@@ -935,10 +700,7 @@
}
f_service_ <<
- indent() << "oprot.writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, seqid)" << endl <<
- indent() << "result.write(oprot)" << endl <<
- indent() << "oprot.writeMessageEnd()" << endl <<
- indent() << "oprot.trans.flush()" << endl;
+ indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" << endl;
// Close function
indent_down();
@@ -946,385 +708,6 @@
}
/**
- * Deserializes a field of any type.
- */
-void t_rb_generator::generate_deserialize_field(ofstream &out,
- t_field* tfield,
- string prefix,
- bool inclass) {
- t_type* type = tfield->get_type();
- while (type->is_typedef()) {
- type = ((t_typedef*)type)->get_type();
- }
-
- if (type->is_void()) {
- throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
- prefix + tfield->get_name();
- }
-
- string name = prefix + tfield->get_name();
-
- if (type->is_struct() || type->is_xception()) {
- generate_deserialize_struct(out,
- (t_struct*)type,
- name);
- } else if (type->is_container()) {
- generate_deserialize_container(out, type, name);
- } else if (type->is_base_type() || type->is_enum()) {
- indent(out) <<
- name << " = iprot.";
-
- if (type->is_base_type()) {
- t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
- switch (tbase) {
- case t_base_type::TYPE_VOID:
- throw "compiler error: cannot serialize void field in a struct: " +
- name;
- break;
- case t_base_type::TYPE_STRING:
- out << "readString();";
- break;
- case t_base_type::TYPE_BOOL:
- out << "readBool();";
- break;
- case t_base_type::TYPE_BYTE:
- out << "readByte();";
- break;
- case t_base_type::TYPE_I16:
- out << "readI16();";
- break;
- case t_base_type::TYPE_I32:
- out << "readI32();";
- break;
- case t_base_type::TYPE_I64:
- out << "readI64();";
- break;
- case t_base_type::TYPE_DOUBLE:
- out << "readDouble();";
- break;
- default:
- throw "compiler error: no PHP name for base type " + tbase;
- }
- } else if (type->is_enum()) {
- out << "readI32();";
- }
- out << endl;
-
- } else {
- printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
- tfield->get_name().c_str(), type->get_name().c_str());
- }
-}
-
-/**
- * Generates an unserializer for a struct, calling read()
- */
-void t_rb_generator::generate_deserialize_struct(ofstream &out,
- t_struct* tstruct,
- string prefix) {
- out <<
- indent() << prefix << " = " << type_name(tstruct) << ".new()" << endl <<
- indent() << prefix << ".read(iprot)" << endl;
-}
-
-/**
- * Serialize a container by writing out the header followed by
- * data and then a footer.
- */
-void t_rb_generator::generate_deserialize_container(ofstream &out,
- t_type* ttype,
- string prefix) {
- string size = tmp("_size");
- string ktype = tmp("_ktype");
- string vtype = tmp("_vtype");
- string etype = tmp("_etype");
-
- t_field fsize(g_type_i32, size);
- t_field fktype(g_type_byte, ktype);
- t_field fvtype(g_type_byte, vtype);
- t_field fetype(g_type_byte, etype);
-
- // Declare variables, read header
- if (ttype->is_map()) {
- out <<
- indent() << prefix << " = {}" << endl <<
- indent() << "(" << ktype << ", " << vtype << ", " << size << " ) = iprot.readMapBegin() " << endl;
- } else if (ttype->is_set()) {
- out <<
- indent() << prefix << " = {}" << endl <<
- indent() << "(" << etype << ", " << size << ") = iprot.readSetBegin()" << endl;
- } else if (ttype->is_list()) {
- out <<
- indent() << prefix << " = []" << endl <<
- indent() << "(" << etype << ", " << size << ") = iprot.readListBegin()" << endl;
- }
-
- // For loop iterates over elements
- string i = tmp("_i");
- indent(out) <<
- "for " << i << " in (1.." << size << ")" << endl;
-
- indent_up();
-
- if (ttype->is_map()) {
- generate_deserialize_map_element(out, (t_map*)ttype, prefix);
- } else if (ttype->is_set()) {
- generate_deserialize_set_element(out, (t_set*)ttype, prefix);
- } else if (ttype->is_list()) {
- generate_deserialize_list_element(out, (t_list*)ttype, prefix);
- }
-
- indent_down();
- indent(out) << "end" << endl;
-
- // Read container end
- if (ttype->is_map()) {
- indent(out) << "iprot.readMapEnd()" << endl;
- } else if (ttype->is_set()) {
- indent(out) << "iprot.readSetEnd()" << endl;
- } else if (ttype->is_list()) {
- indent(out) << "iprot.readListEnd()" << endl;
- }
-}
-
-
-/**
- * Generates code to deserialize a map
- */
-void t_rb_generator::generate_deserialize_map_element(ofstream &out,
- t_map* tmap,
- string prefix) {
- string key = tmp("_key");
- string val = tmp("_val");
- t_field fkey(tmap->get_key_type(), key);
- t_field fval(tmap->get_val_type(), val);
-
- generate_deserialize_field(out, &fkey);
- generate_deserialize_field(out, &fval);
-
- indent(out) <<
- prefix << "[" << key << "] = " << val << endl;
-}
-
-/**
- * Write a set element
- */
-void t_rb_generator::generate_deserialize_set_element(ofstream &out,
- t_set* tset,
- string prefix) {
- string elem = tmp("_elem");
- t_field felem(tset->get_elem_type(), elem);
-
- generate_deserialize_field(out, &felem);
-
- indent(out) <<
- prefix << "[" << elem << "] = true" << endl;
-}
-
-/**
- * Write a list element
- */
-void t_rb_generator::generate_deserialize_list_element(ofstream &out,
- t_list* tlist,
- string prefix) {
- string elem = tmp("_elem");
- t_field felem(tlist->get_elem_type(), elem);
-
- generate_deserialize_field(out, &felem);
-
- indent(out) <<
- prefix << ".push(" << elem << ")" << endl;
-}
-
-
-/**
- * Serializes a field of any type.
- *
- * @param tfield The field to serialize
- * @param prefix Name to prepend to field name
- */
-void t_rb_generator::generate_serialize_field(ofstream &out,
- t_field* tfield,
- string prefix) {
- t_type* type = tfield->get_type();
- while (type->is_typedef()) {
- type = ((t_typedef*)type)->get_type();
- }
-
- // Do nothing for void types
- if (type->is_void()) {
- throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
- prefix + tfield->get_name();
- }
-
- if (type->is_struct() || type->is_xception()) {
- generate_serialize_struct(out,
- (t_struct*)type,
- prefix + tfield->get_name());
- } else if (type->is_container()) {
- generate_serialize_container(out,
- type,
- prefix + tfield->get_name());
- } else if (type->is_base_type() || type->is_enum()) {
-
- string name = prefix + tfield->get_name();
-
- indent(out) <<
- "oprot.";
-
- if (type->is_base_type()) {
- t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
- switch (tbase) {
- case t_base_type::TYPE_VOID:
- throw
- "compiler error: cannot serialize void field in a struct: " + name;
- break;
- case t_base_type::TYPE_STRING:
- out << "writeString(" << name << ")";
- break;
- case t_base_type::TYPE_BOOL:
- out << "writeBool(" << name << ")";
- break;
- case t_base_type::TYPE_BYTE:
- out << "writeByte(" << name << ")";
- break;
- case t_base_type::TYPE_I16:
- out << "writeI16(" << name << ")";
- break;
- case t_base_type::TYPE_I32:
- out << "writeI32(" << name << ")";
- break;
- case t_base_type::TYPE_I64:
- out << "writeI64(" << name << ")";
- break;
- case t_base_type::TYPE_DOUBLE:
- out << "writeDouble(" << name << ")";
- break;
- default:
- throw "compiler error: no PHP name for base type " + tbase;
- }
- } else if (type->is_enum()) {
- out << "writeI32(" << name << ")";
- }
- out << endl;
- } else {
- printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
- prefix.c_str(),
- tfield->get_name().c_str(),
- type->get_name().c_str());
- }
-}
-
-/**
- * Serializes all the members of a struct.
- *
- * @param tstruct The struct to serialize
- * @param prefix String prefix to attach to all fields
- */
-void t_rb_generator::generate_serialize_struct(ofstream &out,
- t_struct* tstruct,
- string prefix) {
- indent(out) <<
- prefix << ".write(oprot)" << endl;
-}
-
-void t_rb_generator::generate_serialize_container(ofstream &out,
- t_type* ttype,
- string prefix) {
- if (ttype->is_map()) {
- indent(out) <<
- "oprot.writeMapBegin(" <<
- type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
- type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
- prefix << ".length)" << endl;
- } else if (ttype->is_set()) {
- indent(out) <<
- "oprot.writeSetBegin(" <<
- type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
- prefix << ".length)" << endl;
- } else if (ttype->is_list()) {
- indent(out) <<
- "oprot.writeListBegin(" <<
- type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
- prefix << ".length)" << endl;
- }
-
- if (ttype->is_map()) {
- string kiter = tmp("kiter");
- string viter = tmp("viter");
- indent(out) <<
- prefix << ".each do |" << kiter << ", " << viter << "|" << endl;
- indent_up();
- generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
- indent_down();
- indent(out) << "end" << endl;
- } else if (ttype->is_set()) {
- string iter = tmp("iter");
- string t = tmp("true");
- indent(out) <<
- prefix << ".each do |" << iter << ", " << t << "|" << endl;
- indent_up();
- generate_serialize_set_element(out, (t_set*)ttype, iter);
- indent_down();
- indent(out) << "end" << endl;
- } else if (ttype->is_list()) {
- string iter = tmp("iter");
- indent(out) <<
- prefix << ".each do |" << iter << "|" << endl;
- indent_up();
- generate_serialize_list_element(out, (t_list*)ttype, iter);
- indent_down();
- indent(out) << "end" << endl;
- }
-
- if (ttype->is_map()) {
- indent(out) <<
- "oprot.writeMapEnd()" << endl;
- } else if (ttype->is_set()) {
- indent(out) <<
- "oprot.writeSetEnd()" << endl;
- } else if (ttype->is_list()) {
- indent(out) <<
- "oprot.writeListEnd()" << endl;
- }
-}
-
-/**
- * Serializes the members of a map.
- *
- */
-void t_rb_generator::generate_serialize_map_element(ofstream &out,
- t_map* tmap,
- string kiter,
- string viter) {
- t_field kfield(tmap->get_key_type(), kiter);
- generate_serialize_field(out, &kfield, "");
-
- t_field vfield(tmap->get_val_type(), viter);
- generate_serialize_field(out, &vfield, "");
-}
-
-/**
- * Serializes the members of a set.
- */
-void t_rb_generator::generate_serialize_set_element(ofstream &out,
- t_set* tset,
- string iter) {
- t_field efield(tset->get_elem_type(), iter);
- generate_serialize_field(out, &efield, "");
-}
-
-/**
- * Serializes the members of a list.
- */
-void t_rb_generator::generate_serialize_list_element(ofstream &out,
- t_list* tlist,
- string iter) {
- t_field efield(tlist->get_elem_type(), iter);
- generate_serialize_field(out, &efield, "");
-}
-
-/**
* Declares a field, which may include initialization as necessary.
*
* @param ttype The type
diff --git a/compiler/cpp/src/generate/t_rb_generator.h b/compiler/cpp/src/generate/t_rb_generator.h
index f766de9..61a1d30 100644
--- a/compiler/cpp/src/generate/t_rb_generator.h
+++ b/compiler/cpp/src/generate/t_rb_generator.h
@@ -11,6 +11,7 @@
#include <fstream>
#include <iostream>
#include <vector>
+#include <boost/tokenizer.hpp>
#include "t_oop_generator.h"
@@ -37,12 +38,12 @@
* Program-level generation functions
*/
- void generate_typedef (t_typedef* ttypedef);
- void generate_enum (t_enum* tenum);
- void generate_const (t_const* tconst);
- void generate_struct (t_struct* tstruct);
- void generate_xception (t_struct* txception);
- void generate_service (t_service* tservice);
+ void generate_typedef (t_typedef* ttypedef);
+ void generate_enum (t_enum* tenum);
+ void generate_const (t_const* tconst);
+ void generate_struct (t_struct* tstruct);
+ void generate_xception (t_struct* txception);
+ void generate_service (t_service* tservice);
std::string render_const_value(t_type* type, t_const_value* value);
@@ -50,11 +51,13 @@
* Struct generation code
*/
- void generate_rb_struct(t_struct* tstruct, bool is_exception);
- void generate_rb_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
+ void generate_rb_struct(std::ofstream& out, t_struct* tstruct, bool is_exception);
void generate_rb_struct_reader(std::ofstream& out, t_struct* tstruct);
void generate_rb_struct_writer(std::ofstream& out, t_struct* tstruct);
void generate_rb_function_helpers(t_function* tfunction);
+ void generate_accessors (std::ofstream& out, t_struct* tstruct);
+ void generate_field_defns (std::ofstream& out, t_struct* tstruct);
+ void generate_field_data (std::ofstream& out, t_type* field_type, const std::string& field_name);
/**
* Service-level generation functions
@@ -137,6 +140,26 @@
in[0] = toupper(in[0]);
return in;
}
+
+ std::string ruby_namespace(t_program* p) {
+ std::string ns = p->get_ruby_namespace();
+ return ns.size() ? ns : "";
+ }
+
+ std::vector<std::string> ruby_modules(t_program* p) {
+ std::string ns = p->get_ruby_namespace();
+ boost::tokenizer<> tok(ns);
+ std::vector<std::string> modules;
+
+ for(boost::tokenizer<>::iterator beg=tok.begin(); beg != tok.end(); ++beg) {
+ modules.push_back(*beg);
+ }
+
+ return modules;
+ }
+
+ void begin_namespace(std::ofstream&, std::vector<std::string>);
+ void end_namespace(std::ofstream&, std::vector<std::string>);
private:
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index f39852d..8b4f59c 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -145,6 +145,14 @@
return xsd_namespace_;
}
+ void set_ruby_namespace(std::string ruby_namespace) {
+ ruby_namespace_ = ruby_namespace;
+ }
+
+ const std::string& get_ruby_namespace() const {
+ return ruby_namespace_;
+ }
+
void set_perl_namespace(std::string perl_namespace) {
perl_namespace_ = perl_namespace;
}
@@ -193,6 +201,9 @@
// XSD namespace
std::string xsd_namespace_;
+ // Ruby namespace
+ std::string ruby_namespace_;
+
// Perl namespace
std::string perl_namespace_;
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index 3100c6a..803f786 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -63,42 +63,43 @@
{symbol} { return yytext[0]; }
-"namespace" { return tok_namespace; }
-"cpp_namespace" { return tok_cpp_namespace; }
-"cpp_include" { return tok_cpp_include; }
-"cpp_type" { return tok_cpp_type; }
-"java_package" { return tok_java_package; }
-"php_namespace" { return tok_php_namespace; }
-"xsd_all" { return tok_xsd_all; }
-"xsd_optional" { return tok_xsd_optional; }
-"xsd_nillable" { return tok_xsd_nillable; }
-"xsd_namespace" { return tok_xsd_namespace; }
-"xsd_attrs" { return tok_xsd_attrs; }
-"include" { return tok_include; }
+"namespace" { return tok_namespace; }
+"cpp_namespace" { return tok_cpp_namespace; }
+"cpp_include" { return tok_cpp_include; }
+"cpp_type" { return tok_cpp_type; }
+"java_package" { return tok_java_package; }
+"php_namespace" { return tok_php_namespace; }
+"ruby_namespace" { return tok_ruby_namespace; }
+"xsd_all" { return tok_xsd_all; }
+"xsd_optional" { return tok_xsd_optional; }
+"xsd_nillable" { return tok_xsd_nillable; }
+"xsd_namespace" { return tok_xsd_namespace; }
+"xsd_attrs" { return tok_xsd_attrs; }
+"include" { return tok_include; }
-"void" { return tok_void; }
-"bool" { return tok_bool; }
-"byte" { return tok_byte; }
-"i16" { return tok_i16; }
-"i32" { return tok_i32; }
-"i64" { return tok_i64; }
-"double" { return tok_double; }
-"string" { return tok_string; }
-"binary" { return tok_binary; }
-"slist" { return tok_slist; }
-"senum" { return tok_senum; }
-"map" { return tok_map; }
-"list" { return tok_list; }
-"set" { return tok_set; }
-"async" { return tok_async; }
-"typedef" { return tok_typedef; }
-"struct" { return tok_struct; }
-"exception" { return tok_xception; }
-"extends" { return tok_extends; }
-"throws" { return tok_throws; }
-"service" { return tok_service; }
-"enum" { return tok_enum; }
-"const" { return tok_const; }
+"void" { return tok_void; }
+"bool" { return tok_bool; }
+"byte" { return tok_byte; }
+"i16" { return tok_i16; }
+"i32" { return tok_i32; }
+"i64" { return tok_i64; }
+"double" { return tok_double; }
+"string" { return tok_string; }
+"binary" { return tok_binary; }
+"slist" { return tok_slist; }
+"senum" { return tok_senum; }
+"map" { return tok_map; }
+"list" { return tok_list; }
+"set" { return tok_set; }
+"async" { return tok_async; }
+"typedef" { return tok_typedef; }
+"struct" { return tok_struct; }
+"exception" { return tok_xception; }
+"extends" { return tok_extends; }
+"throws" { return tok_throws; }
+"service" { return tok_service; }
+"enum" { return tok_enum; }
+"const" { return tok_const; }
"abstract" { thrift_reserved_keyword(yytext); }
"and" { thrift_reserved_keyword(yytext); }
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index 23b9fa0..fe64e85 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -79,6 +79,7 @@
%token tok_xsd_nillable
%token tok_xsd_namespace
%token tok_xsd_attrs
+%token tok_ruby_namespace
/**
* Base datatype keywords
@@ -234,6 +235,13 @@
g_program->set_php_namespace($2);
}
}
+| tok_ruby_namespace tok_identifier
+ {
+ pdebug("Header -> tok_ruby_namespace tok_identifier");
+ if (g_parse_mode == PROGRAM) {
+ g_program->set_ruby_namespace($2);
+ }
+ }
| tok_java_package tok_identifier
{
pdebug("Header -> tok_java_package tok_identifier");
diff --git a/lib/rb/lib/thrift/protocol/tprotocol.rb b/lib/rb/lib/thrift/protocol/tprotocol.rb
index da079d1..fb43705 100644
--- a/lib/rb/lib/thrift/protocol/tprotocol.rb
+++ b/lib/rb/lib/thrift/protocol/tprotocol.rb
@@ -114,6 +114,56 @@
def readString(); nil; end
+ def write_field(name, type, fid, value)
+ writeFieldBegin(name, type, fid)
+ write_type(type, value)
+ writeFieldEnd
+ end
+
+ def write_type(type, value)
+ case type
+ when TType::BOOL
+ writeBool(value)
+ when TType::BYTE
+ writeByte(value)
+ when TType::DOUBLE
+ writeDouble(value)
+ when TType::I16
+ writeI16(value)
+ when TType::I32
+ writeI32(value)
+ when TType::I64
+ writeI64(value)
+ when TType::STRING
+ writeString(value)
+ when TType::STRUCT
+ value.write(self)
+ else
+ raise NotImplementedError
+ end
+ end
+
+ def read_type(type)
+ case type
+ when TType::BOOL
+ readBool
+ when TType::BYTE
+ readByte
+ when TType::DOUBLE
+ readDouble
+ when TType::I16
+ readI16
+ when TType::I32
+ readI32
+ when TType::I64
+ readI64
+ when TType::STRING
+ readString
+ else
+ raise NotImplementedError
+ end
+ end
+
def skip(type)
if type === TType::STOP
nil
diff --git a/lib/rb/lib/thrift/thrift.rb b/lib/rb/lib/thrift/thrift.rb
index 2b9ebbb..d8e77a1 100644
--- a/lib/rb/lib/thrift/thrift.rb
+++ b/lib/rb/lib/thrift/thrift.rb
@@ -32,7 +32,40 @@
end
module TProcessor
- def process(iprot, oprot); nil; end
+ def initialize(handler)
+ @handler = handler
+ end
+
+ def process(iprot, oprot)
+ name, type, seqid = iprot.readMessageBegin()
+ if respond_to?("process_#{name}")
+ send("process_#{name}", seqid, iprot, oprot)
+ return true
+ else
+ iprot.skip(TType::STRUCT)
+ iprot.readMessageEnd()
+ x = TApplicationException.new(TApplicationException::UNKNOWN_METHOD, 'Unknown function '+name)
+ oprot.writeMessageBegin(name, TMessageType::EXCEPTION, seqid)
+ x.write(oprot)
+ oprot.writeMessageEnd()
+ oprot.trans.flush()
+ return
+ end
+ end
+
+ def read_args(iprot, args_class)
+ args = args_class.new
+ args.read(iprot)
+ iprot.readMessageEnd
+ args
+ end
+
+ def write_result(result, oprot, name, seqid)
+ oprot.writeMessageBegin(name, TMessageType::REPLY, seqid)
+ result.write(oprot)
+ oprot.writeMessageEnd()
+ oprot.trans.flush()
+ end
end
class TException < StandardError
@@ -104,3 +137,176 @@
end
end
+
+module ThriftClient
+ def initialize(iprot, oprot=nil)
+ @iprot = iprot
+ @oprot = oprot || iprot
+ @seqid = 0
+ end
+
+ def send_message(name, args_class, args = {})
+ @oprot.writeMessageBegin(name, TMessageType::CALL, @seqid)
+ data = args_class.new
+ args.each do |k, v|
+ data.send("#{k.to_s}=", v)
+ end
+ data.write(@oprot)
+ @oprot.writeMessageEnd()
+ @oprot.trans.flush()
+ end
+
+ def receive_message(result_klass)
+ fname, mtype, rseqid = @iprot.readMessageBegin()
+ handle_exception(mtype)
+ result = result_klass.new
+ result.read(@iprot)
+ @iprot.readMessageEnd()
+ return result
+ end
+
+ def handle_exception(mtype)
+ if mtype == TMessageType::EXCEPTION
+ x = TApplicationException.new()
+ x.read(@iprot)
+ @iprot.readMessageEnd()
+ raise x
+ end
+ end
+end
+
+module ThriftStruct
+ def initialize(d={})
+ each_field do |fid, type, name|
+ instance_variable_set("@#{name}", d[name.to_s])
+ end
+ end
+
+ def fields
+ self.class.const_get(:FIELDS)
+ end
+
+ def each_field
+ fields.each do |fid, data|
+ yield fid, data[:type], data[:name]
+ end
+ end
+
+ def read(iprot)
+ iprot.readStructBegin()
+ loop do
+ fname, ftype, fid = iprot.readFieldBegin()
+ break if (ftype === TType::STOP)
+ handle_message(iprot, fid, ftype)
+ iprot.readFieldEnd()
+ end
+ iprot.readStructEnd()
+ end
+
+ def write(oprot)
+ oprot.writeStructBegin(self.class.name)
+ each_field do |fid, type, name|
+ if (value = instance_variable_get("@#{name}"))
+ if is_container? type
+ oprot.writeFieldBegin(name, type, fid)
+ write_container(oprot, value, fields[fid])
+ oprot.writeFieldEnd
+ else
+ oprot.write_field(name, type, fid, value)
+ end
+ end
+ end
+ oprot.writeFieldStop()
+ oprot.writeStructEnd()
+ end
+
+ protected
+
+ def handle_message(iprot, fid, ftype)
+ field = fields[fid]
+ if field && field[:type] == ftype
+ value = read_field(iprot, field)
+ instance_variable_set("@#{field[:name]}", value)
+ else
+ iprot.skip(ftype)
+ end
+ end
+
+ def read_field(iprot, field = {})
+ if field[:type] == TType::STRUCT
+ value = field[:class].new
+ value.read(iprot)
+ elsif field[:type] == TType::MAP
+ key_type, val_type, size = iprot.readMapBegin
+ value = {}
+ size.times do
+ k = read_field(iprot, field_info(field[:key]))
+ v = read_field(iprot, field_info(field[:value]))
+ value[k] = v
+ end
+ iprot.readMapEnd
+ elsif field[:type] == TType::LIST
+ e_type, size = iprot.readListBegin
+ value = Array.new(size) do |n|
+ read_field(iprot, field_info(field[:element]))
+ end
+ iprot.readListEnd
+ elsif field[:type] == TType::SET
+ e_type, size = iprot.readSetBegin
+ value = {}
+ size.times do
+ element = read_field(iprot, field_info(field[:element]))
+ value[element] = true
+ end
+ iprot.readSetEnd
+ else
+ value = iprot.read_type(field[:type])
+ end
+ value
+ end
+
+ def write_data(oprot, value, field)
+ if is_container? field[:type]
+ write_container(oprot, value, field)
+ else
+ oprot.write_type(field[:type], value)
+ end
+ end
+
+ def write_container(oprot, value, field = {})
+ if field[:type] == TType::MAP
+ oprot.writeMapBegin(field[:key][:type], field[:value][:type], value.size)
+ value.each do |k, v|
+ write_data(oprot, k, field[:key])
+ write_data(oprot, v, field[:value])
+ end
+ oprot.writeMapEnd
+ elsif field[:type] == TType::LIST
+ oprot.writeListBegin(field[:element][:type], value.size)
+ value.each do |elem|
+ write_data(oprot, elem, field[:element])
+ end
+ oprot.writeListEnd
+ elsif field[:type] == TType::SET
+ oprot.writeSetBegin(field[:element][:type], value.size)
+ value.each do |k, v|
+ write_data(oprot, k, field[:element])
+ end
+ oprot.writeSetEnd
+ else
+ raise "Not a container type: #{field[:type]}"
+ end
+ end
+
+ def is_container?(type)
+ [TType::LIST, TType::MAP, TType::SET].include? type
+ end
+
+ def field_info(field)
+ { :type => field[:type],
+ :class => field[:class],
+ :key => field[:key],
+ :value => field[:value],
+ :element => field[:element] }
+ end
+end
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index d4b0a4d..92a3d21 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -1,5 +1,6 @@
java_package thrift.test
cpp_namespace thrift.test
+ruby_namespace Thrift.Test
enum Numberz
{
diff --git a/test/rb/TestClient.rb b/test/rb/TestClient.rb
index fedb818..1adb5c7 100755
--- a/test/rb/TestClient.rb
+++ b/test/rb/TestClient.rb
@@ -9,7 +9,7 @@
s = TSocket.new('localhost', 9090)
p = TBinaryProtocol.new(s)
-c = ThriftTest::Client.new(p)
+c = Thrift::Test::ThriftTest::Client.new(p)
s.open()
@@ -25,10 +25,12 @@
puts c.testMap({1 => 1, 2 => 2, 3 => 3})
puts c.testList([1,2,3,4,5])
puts c.testSet({1 => true, 2 => true, 3 => true})
-
-struct = Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+struct = Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
puts c.testStruct(struct)
-puts c.testNest(Xtruct2.new({'struct_thing' => struct, 'i32_thing' => 10}))
+puts c.testNest(Thrift::Test::Xtruct2.new({'struct_thing' => struct, 'i32_thing' => 10}))
+insane = Thrift::Test::Insanity.new({'userMap' => { Thrift::Test::Numberz::ONE => 44 }, 'xtructs' => [struct, Thrift::Test::Xtruct.new({'string_thing' => 'hi again', 'i32_thing' => 12})]})
+puts c.testInsanity(insane)
+puts c.testMapMap(4).inspect
s.close()
diff --git a/test/rb/TestServer.rb b/test/rb/TestServer.rb
index c0d7b59..892037e 100755
--- a/test/rb/TestServer.rb
+++ b/test/rb/TestServer.rb
@@ -9,8 +9,6 @@
require 'ThriftTest'
class TestHandler
- include ThriftTest::Iface
-
def testVoid()
print "testVoid()\n"
end
@@ -42,6 +40,7 @@
def testStruct(thing)
print "testStruct(#{thing})\n"
+ print " with attrs: #{thing.string_thing}, #{thing.byte_thing}, #{thing.i32_thing}"
return thing
end
@@ -69,11 +68,33 @@
end
return thing
end
+
+ def testNest(thing)
+ print "testNest(#{thing})\n"
+ puts " i32_thing: #{thing.i32_thing}"
+ puts " with struct: "
+ %w{ string_thing byte_thing i32_thing }.each do |t|
+ puts " #{t}: #{thing.struct_thing.send(t)}"
+ end
+ return thing
+ end
+
+ def testInsanity(thing)
+ puts "insanity:"
+ puts " #{thing.inspect}"
+ num, uid = thing.userMap.find { true }
+ return {uid => {num => thing}}
+ end
+
+ def testMapMap(thing)
+ puts "got: #{thing}"
+ return {thing => {thing => thing}}
+ end
end
handler = TestHandler.new()
-processor = ThriftTest::Processor.new(handler)
+processor = Thrift::Test::ThriftTest::Processor.new(handler)
transport = TServerSocket.new(9090)
server = TSimpleServer.new(processor, transport)
server.serve()