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()