You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by il...@apache.org on 2012/03/01 06:56:40 UTC

svn commit: r1295423 - /thrift/trunk/compiler/cpp/src/generate/t_rb_generator.cc

Author: ilyam
Date: Thu Mar  1 05:56:39 2012
New Revision: 1295423

URL: http://svn.apache.org/viewvc?rev=1295423&view=rev
Log:
THRIFT-481: indentation of ruby classes is off by a few
Compiler: Ruby
Patch: Ilya Maykov

Fixed indentation of gen-rb files by wrapping each file
output stream in a class that keeps track of the indent
level instead of using the global indent.


Modified:
    thrift/trunk/compiler/cpp/src/generate/t_rb_generator.cc

Modified: thrift/trunk/compiler/cpp/src/generate/t_rb_generator.cc
URL: http://svn.apache.org/viewvc/thrift/trunk/compiler/cpp/src/generate/t_rb_generator.cc?rev=1295423&r1=1295422&r2=1295423&view=diff
==============================================================================
--- thrift/trunk/compiler/cpp/src/generate/t_rb_generator.cc (original)
+++ thrift/trunk/compiler/cpp/src/generate/t_rb_generator.cc Thu Mar  1 05:56:39 2012
@@ -38,6 +38,26 @@
 
 using namespace std;
 
+/**
+ * A subclass of std::ofstream that includes indenting functionality.
+ */
+class t_rb_ofstream : public std::ofstream {
+  private:
+    int indent_;
+
+  public:
+    t_rb_ofstream() : std::ofstream(), indent_(0) { }
+    explicit t_rb_ofstream(const char* filename, ios_base::openmode mode = ios_base::out, int indent = 0) :
+      std::ofstream(filename, mode), indent_(indent) { }
+
+  t_rb_ofstream& indent() {
+    for (int i = 0; i < indent_; ++i) { *this << "  "; }
+    return *this;
+  }
+
+  void indent_up() { indent_++; }
+  void indent_down() { indent_--; }
+};
 
 /**
  * Ruby code generator.
@@ -76,23 +96,23 @@ class t_rb_generator : public t_oop_gene
   void generate_xception    (t_struct*   txception);
   void generate_service     (t_service*  tservice);
 
-  std::string render_const_value(t_type* type, t_const_value* value);
+  t_rb_ofstream& render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value);
 
   /**
    * Struct generation code
    */
 
-  void generate_rb_struct(std::ofstream& out, t_struct* tstruct, bool is_exception);
-  void generate_rb_struct_required_validator(std::ofstream& out, t_struct* tstruct);
-  void generate_rb_union(std::ofstream& out, t_struct* tstruct, bool is_exception);
-  void generate_rb_union_validator(std::ofstream& out, t_struct* tstruct);
+  void generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_rb_struct_required_validator(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception);
+  void generate_rb_union_validator(t_rb_ofstream& out, t_struct* tstruct);
   void generate_rb_function_helpers(t_function* tfunction);
-  void generate_rb_simple_constructor(std::ofstream& out, t_struct* tstruct);
-  void generate_rb_simple_exception_constructor(std::ofstream& out, t_struct* tstruct);
-  void generate_field_constants (std::ofstream& out, t_struct* tstruct);
-  void generate_field_constructors (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, t_const_value* field_value, bool optional);
+  void generate_rb_simple_constructor(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_constants (t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_constructors (t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_defns (t_rb_ofstream& out, t_struct* tstruct);
+  void generate_field_data  (t_rb_ofstream& out, t_type* field_type, const std::string& field_name, t_const_value* field_value, bool optional);
 
   /**
    * Service-level generation functions
@@ -108,57 +128,57 @@ class t_rb_generator : public t_oop_gene
    * Serialization constructs
    */
 
-  void generate_deserialize_field        (std::ofstream &out,
+  void generate_deserialize_field        (t_rb_ofstream &out,
                                           t_field*    tfield,
                                           std::string prefix="",
                                           bool inclass=false);
 
-  void generate_deserialize_struct       (std::ofstream &out,
+  void generate_deserialize_struct       (t_rb_ofstream &out,
                                           t_struct*   tstruct,
                                           std::string prefix="");
 
-  void generate_deserialize_container    (std::ofstream &out,
+  void generate_deserialize_container    (t_rb_ofstream &out,
                                           t_type*     ttype,
                                           std::string prefix="");
 
-  void generate_deserialize_set_element  (std::ofstream &out,
+  void generate_deserialize_set_element  (t_rb_ofstream &out,
                                           t_set*      tset,
                                           std::string prefix="");
 
-  void generate_deserialize_map_element  (std::ofstream &out,
+  void generate_deserialize_map_element  (t_rb_ofstream &out,
                                           t_map*      tmap,
                                           std::string prefix="");
 
-  void generate_deserialize_list_element (std::ofstream &out,
+  void generate_deserialize_list_element (t_rb_ofstream &out,
                                           t_list*     tlist,
                                           std::string prefix="");
 
-  void generate_serialize_field          (std::ofstream &out,
+  void generate_serialize_field          (t_rb_ofstream &out,
                                           t_field*    tfield,
                                           std::string prefix="");
 
-  void generate_serialize_struct         (std::ofstream &out,
+  void generate_serialize_struct         (t_rb_ofstream &out,
                                           t_struct*   tstruct,
                                           std::string prefix="");
 
-  void generate_serialize_container      (std::ofstream &out,
+  void generate_serialize_container      (t_rb_ofstream &out,
                                           t_type*     ttype,
                                           std::string prefix="");
 
-  void generate_serialize_map_element    (std::ofstream &out,
+  void generate_serialize_map_element    (t_rb_ofstream &out,
                                           t_map*      tmap,
                                           std::string kiter,
                                           std::string viter);
 
-  void generate_serialize_set_element    (std::ofstream &out,
+  void generate_serialize_set_element    (t_rb_ofstream &out,
                                           t_set*      tmap,
                                           std::string iter);
 
-  void generate_serialize_list_element   (std::ofstream &out,
+  void generate_serialize_list_element   (t_rb_ofstream &out,
                                           t_list*     tlist,
                                           std::string iter);
 
-  void generate_rdoc                     (std::ofstream& out, 
+  void generate_rdoc                     (t_rb_ofstream& out, 
                                           t_doc* tdoc);
 
   /**
@@ -198,8 +218,8 @@ class t_rb_generator : public t_oop_gene
     return modules;
   }
 
-  void begin_namespace(std::ofstream&, std::vector<std::string>);
-  void end_namespace(std::ofstream&, std::vector<std::string>);
+  void begin_namespace(t_rb_ofstream&, std::vector<std::string>);
+  void end_namespace(t_rb_ofstream&, std::vector<std::string>);
 
  private:
 
@@ -207,9 +227,9 @@ class t_rb_generator : public t_oop_gene
    * File streams
    */
 
-  std::ofstream f_types_;
-  std::ofstream f_consts_;
-  std::ofstream f_service_;
+  t_rb_ofstream f_types_;
+  t_rb_ofstream f_consts_;
+  t_rb_ofstream f_service_;
 
   /** If true, add a "require 'rubygems'" line to the top of each gen-rb file. */
   bool require_rubygems_;
@@ -312,9 +332,9 @@ void t_rb_generator::generate_typedef(t_
  * @param tenum The enumeration
  */
 void t_rb_generator::generate_enum(t_enum* tenum) {
-  indent(f_types_) <<
+  f_types_.indent() <<
     "module " << capitalize(tenum->get_name()) << endl;
-  indent_up();
+  f_types_.indent_up();
 
   vector<t_enum_value*> constants = tenum->get_constants();
   vector<t_enum_value*>::iterator c_iter;
@@ -327,11 +347,11 @@ void t_rb_generator::generate_enum(t_enu
     string name = capitalize((*c_iter)->get_name());
 
     generate_rdoc(f_types_, *c_iter);
-    indent(f_types_) << name << " = " << value << endl;
+    f_types_.indent() << name << " = " << value << endl;
   }
   
   // Create a hash mapping values back to their names (as strings) since ruby has no native enum type
-  indent(f_types_) << "VALUE_MAP = {";
+  f_types_.indent() << "VALUE_MAP = {";
   bool first = true;
   for(c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
     // Populate the hash
@@ -342,7 +362,7 @@ void t_rb_generator::generate_enum(t_enu
   f_types_ << "}" << endl;
   
   // Create a set with valid values for this enum
-  indent(f_types_) << "VALID_VALUES = Set.new([";
+  f_types_.indent() << "VALID_VALUES = Set.new([";
   first = true;
   for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
     // Populate the set
@@ -351,8 +371,8 @@ void t_rb_generator::generate_enum(t_enu
   }
   f_types_ << "]).freeze" << endl;
 
-  indent_down();
-  indent(f_types_) <<
+  f_types_.indent_down();
+  f_types_.indent() <<
     "end" << endl << endl;
 }
 
@@ -366,8 +386,8 @@ void t_rb_generator::generate_const(t_co
 
   name[0] = toupper(name[0]);
 
-  indent(f_consts_) << name << " = " << render_const_value(type, value);
-  f_consts_ << endl << endl;
+  f_consts_.indent() << name << " = ";
+  render_const_value(f_consts_, type, value) << endl << endl;
 }
 
 /**
@@ -375,9 +395,8 @@ void t_rb_generator::generate_const(t_co
  * is NOT performed in this function as it is always run beforehand using the
  * validate_types method in main.cc
  */
-string t_rb_generator::render_const_value(t_type* type, t_const_value* value) {
+t_rb_ofstream& t_rb_generator::render_const_value(t_rb_ofstream& out, t_type* type, t_const_value* value) {
   type = get_true_type(type);
-  std::ostringstream out;
   if (type->is_base_type()) {
     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
     switch (tbase) {
@@ -404,10 +423,10 @@ string t_rb_generator::render_const_valu
       throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
     }
   } else if (type->is_enum()) {
-    indent(out) << value->get_integer();
+    out.indent() << value->get_integer();
   } else if (type->is_struct() || type->is_xception()) {
     out << full_type_name(type) << ".new({" << endl;
-    indent_up();
+    out.indent_up();
     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
     vector<t_field*>::const_iterator f_iter;
     const map<t_const_value*, t_const_value*>& val = value->get_map();
@@ -422,30 +441,26 @@ string t_rb_generator::render_const_valu
       if (field_type == NULL) {
         throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
       }
-      out << indent();
-      out << render_const_value(g_type_string, v_iter->first);
-      out << " => ";
-      out << render_const_value(field_type, v_iter->second);
-      out << "," << endl;
+      out.indent();
+      render_const_value(out, g_type_string, v_iter->first) << " => ";
+      render_const_value(out, field_type, v_iter->second) << "," << endl;
     }
-    indent_down();
-    indent(out) << "})";
+    out.indent_down();
+    out.indent() << "})";
   } else if (type->is_map()) {
     t_type* ktype = ((t_map*)type)->get_key_type();
     t_type* vtype = ((t_map*)type)->get_val_type();
     out << "{" << endl;
-    indent_up();
+    out.indent_up();
     const map<t_const_value*, t_const_value*>& val = value->get_map();
     map<t_const_value*, t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << indent();
-      out << render_const_value(ktype, v_iter->first);
-      out << " => ";
-      out << render_const_value(vtype, v_iter->second);
-      out << "," << endl;
+      out.indent();
+      render_const_value(out, ktype, v_iter->first) << " => ";
+      render_const_value(out, vtype, v_iter->second) << "," << endl;
     }
-    indent_down();
-    indent(out) << "}";
+    out.indent_down();
+    out.indent() << "}";
   } else if (type->is_list() || type->is_set()) {
     t_type* etype;
     if (type->is_list()) {
@@ -458,24 +473,23 @@ string t_rb_generator::render_const_valu
     } else {
       out << "[" << endl;
     }
-    indent_up();
+    out.indent_up();
     const vector<t_const_value*>& val = value->get_list();
     vector<t_const_value*>::const_iterator v_iter;
     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
-      out << indent();
-      out << render_const_value(etype, *v_iter);
-      out << "," << endl;
+      out.indent();
+      render_const_value(out, etype, *v_iter) << "," << endl;
     }
-    indent_down();
+    out.indent_down();
     if (type->is_set()) {
-      indent(out) << "])";
+      out.indent() << "])";
     } else {
-      indent(out) << "]";
+      out.indent() << "]";
     }
   } else {
     throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
   }
-  return out.str();
+  return out;
 }
 
 /**
@@ -502,16 +516,16 @@ void t_rb_generator::generate_xception(t
 /**
  * Generates a ruby struct
  */
-void t_rb_generator::generate_rb_struct(std::ofstream& out, t_struct* tstruct, bool is_exception = false) {
+void t_rb_generator::generate_rb_struct(t_rb_ofstream& out, t_struct* tstruct, bool is_exception = false) {
   generate_rdoc(out, tstruct);
-  indent(out) << "class " << type_name(tstruct);
+  out.indent() << "class " << type_name(tstruct);
   if (is_exception) {
     out << " < ::Thrift::Exception";
   }
   out << endl;
 
-  indent_up();
-  indent(out) << "include ::Thrift::Struct, ::Thrift::Struct_Union" << endl;
+  out.indent_up();
+  out.indent() << "include ::Thrift::Struct, ::Thrift::Struct_Union" << endl;
 
   if (is_exception) {
     generate_rb_simple_exception_constructor(out, tstruct);
@@ -521,23 +535,23 @@ void t_rb_generator::generate_rb_struct(
   generate_field_defns(out, tstruct);
   generate_rb_struct_required_validator(out, tstruct);
 
-  indent(out) << "::Thrift::Struct.generate_accessors self" << endl;
+  out.indent() << "::Thrift::Struct.generate_accessors self" << endl;
 
-  indent_down();
-  indent(out) << "end" << endl << endl;
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
 }
 
 
 /**
  * Generates a ruby union
  */
-void t_rb_generator::generate_rb_union(std::ofstream& out, t_struct* tstruct, bool is_exception = false) {
+void t_rb_generator::generate_rb_union(t_rb_ofstream& out, t_struct* tstruct, bool is_exception = false) {
   (void) is_exception;
   generate_rdoc(out, tstruct);
-  indent(out) << "class " << type_name(tstruct) << " < ::Thrift::Union" << endl;
+  out.indent() << "class " << type_name(tstruct) << " < ::Thrift::Union" << endl;
 
-  indent_up();
-  indent(out) << "include ::Thrift::Struct_Union" << endl;
+  out.indent_up();
+  out.indent() << "include ::Thrift::Struct_Union" << endl;
 
   generate_field_constructors(out, tstruct);
 
@@ -545,16 +559,16 @@ void t_rb_generator::generate_rb_union(s
   generate_field_defns(out, tstruct);
   generate_rb_union_validator(out, tstruct);
 
-  indent(out) << "::Thrift::Union.generate_accessors self" << endl;
+  out.indent() << "::Thrift::Union.generate_accessors self" << endl;
 
-  indent_down();
-  indent(out) << "end" << endl << endl;
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
 }
 
-void t_rb_generator::generate_field_constructors(std::ofstream& out, t_struct* tstruct) {
+void t_rb_generator::generate_field_constructors(t_rb_ofstream& out, t_struct* tstruct) {
 
-  indent(out) << "class << self" << endl;
-  indent_up();
+  out.indent() << "class << self" << endl;
+  out.indent_up();
 
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
@@ -565,18 +579,18 @@ void t_rb_generator::generate_field_cons
     }
     std::string field_name = (*f_iter)->get_name();
 
-    indent(out) << "def " << field_name << "(val)" << endl;
-    indent(out) << "  " << tstruct->get_name() << ".new(:" << field_name << ", val)" << endl;
-    indent(out) << "end" << endl;
+    out.indent() << "def " << field_name << "(val)" << endl;
+    out.indent() << "  " << tstruct->get_name() << ".new(:" << field_name << ", val)" << endl;
+    out.indent() << "end" << endl;
   }
   
-  indent_down();
-  indent(out) << "end" << endl;
+  out.indent_down();
+  out.indent() << "end" << endl;
 
   out << endl;
 }
 
-void t_rb_generator::generate_rb_simple_exception_constructor(std::ofstream& out, t_struct* tstruct) {
+void t_rb_generator::generate_rb_simple_exception_constructor(t_rb_ofstream& out, t_struct* tstruct) {
   const vector<t_field*>& members = tstruct->get_members();
 
   if (members.size() == 1) {
@@ -585,21 +599,21 @@ void t_rb_generator::generate_rb_simple_
     if ((*m_iter)->get_type()->is_string()) {
       string name = (*m_iter)->get_name();
 
-      indent(out) << "def initialize(message=nil)" << endl;
-      indent_up();
-      indent(out) << "super()" << endl;
-      indent(out) << "self." << name << " = message" << endl;
-      indent_down();
-      indent(out) << "end" << endl << endl;
+      out.indent() << "def initialize(message=nil)" << endl;
+      out.indent_up();
+      out.indent() << "super()" << endl;
+      out.indent() << "self." << name << " = message" << endl;
+      out.indent_down();
+      out.indent() << "end" << endl << endl;
 
       if (name != "message") {
-        indent(out) << "def message; " << name << " end" << endl << endl;
+        out.indent() << "def message; " << name << " end" << endl << endl;
       }
     }
   }
 }
 
-void t_rb_generator::generate_field_constants(std::ofstream& out, t_struct* tstruct) {
+void t_rb_generator::generate_field_constants(t_rb_ofstream& out, t_struct* tstruct) {
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
 
@@ -607,17 +621,17 @@ void t_rb_generator::generate_field_cons
     std::string field_name = (*f_iter)->get_name();
     std::string cap_field_name = upcase_string(field_name);
     
-    indent(out) << cap_field_name << " = " << (*f_iter)->get_key() << endl;
+    out.indent() << cap_field_name << " = " << (*f_iter)->get_key() << endl;
   }
   out << endl;
 }
 
-void t_rb_generator::generate_field_defns(std::ofstream& out, t_struct* tstruct) {
+void t_rb_generator::generate_field_defns(t_rb_ofstream& out, t_struct* tstruct) {
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
 
-  indent(out) << "FIELDS = {" << endl;
-  indent_up();
+  out.indent() << "FIELDS = {" << endl;
+  out.indent_up();
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     if (f_iter != fields.begin()) {
       out << "," << endl;
@@ -626,21 +640,20 @@ void t_rb_generator::generate_field_defn
     // generate the field docstrings within the FIELDS constant. no real better place...
     generate_rdoc(out, *f_iter);
 
-    indent(out) <<
-      upcase_string((*f_iter)->get_name()) << " => ";
+    out.indent() << upcase_string((*f_iter)->get_name()) << " => ";
 
     generate_field_data(out, (*f_iter)->get_type(), (*f_iter)->get_name(), (*f_iter)->get_value(), 
       (*f_iter)->get_req() == t_field::T_OPTIONAL);
   }
-  indent_down();
+  out.indent_down();
   out << endl;
-  indent(out) << "}" << endl << endl;
+  out.indent() << "}" << endl << endl;
   
-  indent(out) << "def struct_fields; FIELDS; end" << endl << endl;
+  out.indent() << "def struct_fields; FIELDS; end" << endl << endl;
   
 }
 
-void t_rb_generator::generate_field_data(std::ofstream& out, t_type* field_type,
+void t_rb_generator::generate_field_data(t_rb_ofstream& out, t_type* field_type,
     const std::string& field_name = "", t_const_value* field_value = NULL, bool optional = false) {
   field_type = get_true_type(field_type);
 
@@ -652,7 +665,8 @@ void t_rb_generator::generate_field_data
   }
 
   if (field_value != NULL) {
-    out << ", :default => " << render_const_value(field_type, field_value);
+    out << ", :default => ";
+    render_const_value(out, field_type, field_value);
   }
 
   if (!field_type->is_base_type()) {
@@ -688,17 +702,17 @@ void t_rb_generator::generate_field_data
   out << "}";
 }
 
-void t_rb_generator::begin_namespace(std::ofstream& out, vector<std::string> modules) {
+void t_rb_generator::begin_namespace(t_rb_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();
+    out.indent() << "module " << *m_iter << endl;
+    out.indent_up();
   }
 }
 
-void t_rb_generator::end_namespace(std::ofstream& out, vector<std::string> modules) {
+void t_rb_generator::end_namespace(t_rb_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;
+    out.indent_down();
+    out.indent() << "end" << endl;
   }
 }
 
@@ -726,17 +740,16 @@ void t_rb_generator::generate_service(t_
 
   begin_namespace(f_service_, ruby_modules(tservice->get_program()));
 
-  indent(f_service_) << "module " << capitalize(tservice->get_name()) << endl;
-  indent_up();
+  f_service_.indent() << "module " << capitalize(tservice->get_name()) << endl;
+  f_service_.indent_up();
 
   // Generate the three main parts of the service (well, two for now in PHP)
   generate_service_client(tservice);
   generate_service_server(tservice);
   generate_service_helpers(tservice);
 
-  indent_down();
-  indent(f_service_) << "end" << endl <<
-    endl;
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
 
   end_namespace(f_service_, ruby_modules(tservice->get_program()));
 
@@ -753,8 +766,7 @@ void t_rb_generator::generate_service_he
   vector<t_function*> functions = tservice->get_functions();
   vector<t_function*>::iterator f_iter;
 
-  indent(f_service_) <<
-    "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+  f_service_.indent() << "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
 
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     t_struct* ts = (*f_iter)->get_arglist();
@@ -797,12 +809,10 @@ void t_rb_generator::generate_service_cl
     extends_client = " < " + extends + "::Client ";
   }
 
-  indent(f_service_) <<
-    "class Client" << extends_client << endl;
-  indent_up();
+  f_service_.indent() << "class Client" << extends_client << endl;
+  f_service_.indent_up();
 
-  indent(f_service_) <<
-    "include ::Thrift::Client" << endl << endl;
+  f_service_.indent() << "include ::Thrift::Client" << endl << endl;
 
   // Generate client method implementations
   vector<t_function*> functions = tservice->get_functions();
@@ -814,10 +824,9 @@ void t_rb_generator::generate_service_cl
     string funname = (*f_iter)->get_name();
 
     // Open function
-    indent(f_service_) <<
-      "def " << function_signature(*f_iter) << endl;
-    indent_up();
-      indent(f_service_) <<
+    f_service_.indent() << "def " << function_signature(*f_iter) << endl;
+    f_service_.indent_up();
+      f_service_.indent() <<
         "send_" << funname << "(";
 
       bool first = true;
@@ -832,24 +841,24 @@ void t_rb_generator::generate_service_cl
       f_service_ << ")" << endl;
 
       if (!(*f_iter)->is_oneway()) {
-        f_service_ << indent();
+        f_service_.indent();
         if (!(*f_iter)->get_returntype()->is_void()) {
           f_service_ << "return ";
         }
         f_service_ <<
           "recv_" << funname << "()" << endl;
       }
-    indent_down();
-    indent(f_service_) << "end" << endl;
+    f_service_.indent_down();
+    f_service_.indent() << "end" << endl;
     f_service_ << endl;
 
-    indent(f_service_) <<
+    f_service_.indent() <<
       "def send_" << function_signature(*f_iter) << endl;
-    indent_up();
+    f_service_.indent_up();
 
       std::string argsname = capitalize((*f_iter)->get_name() + "_args");
 
-      indent(f_service_) << "send_message('" << funname << "', " << argsname;
+      f_service_.indent() << "send_message('" << funname << "', " << argsname;
 
       for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
         f_service_ << ", :" << (*fld_iter)->get_name() << " => " << (*fld_iter)->get_name();
@@ -857,8 +866,8 @@ void t_rb_generator::generate_service_cl
 
       f_service_ << ")" << endl;
 
-    indent_down();
-    indent(f_service_) << "end" << endl;
+    f_service_.indent_down();
+    f_service_.indent() << "end" << endl;
 
     if (!(*f_iter)->is_oneway()) {
       std::string resultname = capitalize((*f_iter)->get_name() + "_result");
@@ -868,48 +877,46 @@ void t_rb_generator::generate_service_cl
                                string("recv_") + (*f_iter)->get_name(),
                                &noargs);
       // Open function
-      f_service_ <<
-        endl <<
-        indent() << "def " << function_signature(&recv_function) << endl;
-      indent_up();
+      f_service_ << endl;
+      f_service_.indent() << "def " << function_signature(&recv_function) << endl;
+      f_service_.indent_up();
 
       // TODO(mcslee): Validate message reply here, seq ids etc.
 
-      f_service_ <<
-        indent() << "result = receive_message(" << resultname << ")" << endl;
+      f_service_.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() << "return result.success unless result.success.nil?" << endl;
+        f_service_.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) {
-        indent(f_service_) <<
+        f_service_.indent() <<
           "raise result." << (*x_iter)->get_name() <<
             " unless result." << (*x_iter)->get_name() << ".nil?" << endl;
       }
 
       // Careful, only return _result if not a void function
       if ((*f_iter)->get_returntype()->is_void()) {
-        indent(f_service_) <<
+        f_service_.indent() <<
           "return" << endl;
       } else {
-        f_service_ <<
-          indent() << "raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, '" << (*f_iter)->get_name() << " failed: unknown result')" << endl;
+        f_service_.indent() <<
+          "raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, '" <<
+          (*f_iter)->get_name() << " failed: unknown result')" << endl;
       }
 
       // Close function
-      indent_down();
-      indent(f_service_) << "end" << endl << endl;
+      f_service_.indent_down();
+      f_service_.indent() << "end" << endl << endl;
     }
   }
 
-  indent_down();
-  indent(f_service_) << "end" << endl << endl;
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
 }
 
 /**
@@ -930,21 +937,19 @@ void t_rb_generator::generate_service_se
   }
 
   // Generate the header portion
-  indent(f_service_) <<
+  f_service_.indent() <<
     "class Processor" << extends_processor << endl;
-  indent_up();
+  f_service_.indent_up();
 
-  f_service_ <<
-    indent() << "include ::Thrift::Processor" << endl <<
-    endl;
+  f_service_.indent() << "include ::Thrift::Processor" << endl << endl;
 
   // Generate the process subfunctions
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     generate_process_function(tservice, *f_iter);
   }
 
-  indent_down();
-  indent(f_service_) << "end" << endl << endl;
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
 }
 
 /**
@@ -956,16 +961,15 @@ void t_rb_generator::generate_process_fu
                                                t_function* tfunction) {
   (void) tservice;
   // Open function
-  indent(f_service_) <<
+  f_service_.indent() <<
     "def process_" << tfunction->get_name() <<
     "(seqid, iprot, oprot)" << endl;
-  indent_up();
+  f_service_.indent_up();
 
   string argsname = capitalize(tfunction->get_name()) + "_args";
   string resultname = capitalize(tfunction->get_name()) + "_result";
 
-  f_service_ <<
-    indent() << "args = read_args(iprot, " << argsname << ")" << endl;
+  f_service_.indent() << "args = read_args(iprot, " << argsname << ")" << endl;
 
   t_struct* xs = tfunction->get_xceptions();
   const std::vector<t_field*>& xceptions = xs->get_members();
@@ -973,15 +977,13 @@ void t_rb_generator::generate_process_fu
 
   // Declare result for non oneway function
   if (!tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "result = " << resultname << ".new()" << endl;
+    f_service_.indent() << "result = " << resultname << ".new()" << endl;
   }
 
   // Try block for a function with exceptions
   if (xceptions.size() > 0) {
-    f_service_ <<
-      indent() << "begin" << endl;
-    indent_up();
+    f_service_.indent() << "begin" << endl;
+    f_service_.indent_up();
   }
 
   // Generate the function call
@@ -989,7 +991,7 @@ void t_rb_generator::generate_process_fu
   const std::vector<t_field*>& fields = arg_struct->get_members();
   vector<t_field*>::const_iterator f_iter;
 
-  f_service_ << indent();
+  f_service_.indent();
   if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
     f_service_ << "result.success = ";
   }
@@ -1007,35 +1009,32 @@ void t_rb_generator::generate_process_fu
   f_service_ << ")" << endl;
 
   if (!tfunction->is_oneway() && xceptions.size() > 0) {
-    indent_down();
+    f_service_.indent_down();
     for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ <<
-        indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => " << (*x_iter)->get_name() << endl;
+      f_service_.indent() << "rescue " << full_type_name((*x_iter)->get_type()) << " => " <<
+        (*x_iter)->get_name() << endl;
       if (!tfunction->is_oneway()) {
-        indent_up();
-        f_service_ <<
-          indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
-        indent_down();
+        f_service_.indent_up();
+        f_service_.indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << endl;
+        f_service_.indent_down();
       }
     }
-    indent(f_service_) << "end" << endl;
+    f_service_.indent() << "end" << endl;
   }
 
   // Shortcut out here for oneway functions
   if (tfunction->is_oneway()) {
-    f_service_ <<
-      indent() << "return" << endl;
-    indent_down();
-    indent(f_service_) << "end" << endl << endl;
+    f_service_.indent() << "return" << endl;
+    f_service_.indent_down();
+    f_service_.indent() << "end" << endl << endl;
     return;
   }
 
-  f_service_ <<
-    indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" << endl;
+  f_service_.indent() << "write_result(result, oprot, '" << tfunction->get_name() << "', seqid)" << endl;
 
   // Close function
-  indent_down();
-  indent(f_service_) << "end" << endl << endl;
+  f_service_.indent_down();
+  f_service_.indent() << "end" << endl << endl;
 }
 
 /**
@@ -1135,17 +1134,18 @@ string t_rb_generator::type_to_enum(t_ty
 }
 
 
-void t_rb_generator::generate_rdoc(std::ofstream& out, t_doc* tdoc) {
+void t_rb_generator::generate_rdoc(t_rb_ofstream& out, t_doc* tdoc) {
   if (tdoc->has_doc()) {
+    out.indent();
     generate_docstring_comment(out,
       "", "# ", tdoc->get_doc(), "");
   }
 }
 
-void t_rb_generator::generate_rb_struct_required_validator(std::ofstream& out, 
+void t_rb_generator::generate_rb_struct_required_validator(t_rb_ofstream& out, 
                                                            t_struct* tstruct) {
-  indent(out) << "def validate" << endl;
-  indent_up();
+  out.indent() << "def validate" << endl;
+  out.indent_up();
 
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
@@ -1153,7 +1153,9 @@ void t_rb_generator::generate_rb_struct_
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     t_field* field = (*f_iter);
     if (field->get_req() == t_field::T_REQUIRED) {
-      indent(out) << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field " << field->get_name() << " is unset!')";
+      out.indent() <<
+        "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field " <<
+        field->get_name() << " is unset!')";
       if (field->get_type()->is_bool()) {
         out << " if @" << field->get_name() << ".nil?";
       } else {
@@ -1168,41 +1170,49 @@ void t_rb_generator::generate_rb_struct_
     t_field* field = (*f_iter);
 
     if (field->get_type()->is_enum()){      
-      indent(out) << "unless @" << field->get_name() << ".nil? || " << full_type_name(field->get_type()) << "::VALID_VALUES.include?(@" << field->get_name() << ")" << endl;
-      indent_up();
-      indent(out) << "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " << field->get_name() << "!')" << endl;  
-      indent_down();
-      indent(out) << "end" << endl;
+      out.indent() << "unless @" << field->get_name() << ".nil? || " <<
+        full_type_name(field->get_type()) << "::VALID_VALUES.include?(@" <<
+        field->get_name() << ")" << endl;
+      out.indent_up();
+      out.indent() <<
+        "raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " <<
+        field->get_name() << "!')" << endl;  
+      out.indent_down();
+      out.indent() << "end" << endl;
     }
   }
 
-  indent_down();
-  indent(out) << "end" << endl << endl;
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
 }
 
-void t_rb_generator::generate_rb_union_validator(std::ofstream& out, 
+void t_rb_generator::generate_rb_union_validator(t_rb_ofstream& out, 
                                                  t_struct* tstruct) {
-  indent(out) << "def validate" << endl;
-  indent_up();
+  out.indent() << "def validate" << endl;
+  out.indent_up();
 
   const vector<t_field*>& fields = tstruct->get_members();
   vector<t_field*>::const_iterator f_iter;
 
-  indent(out) << "raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?" << endl;
+  out.indent() <<
+    "raise(StandardError, 'Union fields are not set.') if get_set_field.nil? || get_value.nil?" << endl;
 
   // if field is an enum, check that its value is valid
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     const t_field* field = (*f_iter);
 
     if (field->get_type()->is_enum()){      
-      indent(out) << "if get_set_field == :" << field->get_name() << endl;
-      indent(out) << "  raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " << field->get_name() << "!') unless " << full_type_name(field->get_type()) << "::VALID_VALUES.include?(get_value)" << endl;  
-      indent(out) << "end" << endl;
+      out.indent() << "if get_set_field == :" << field->get_name() << endl;
+      out.indent() <<
+        "  raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field " <<
+        field->get_name() << "!') unless " << full_type_name(field->get_type()) <<
+        "::VALID_VALUES.include?(get_value)" << endl;  
+      out.indent() << "end" << endl;
     }
   }
 
-  indent_down();
-  indent(out) << "end" << endl << endl;
+  out.indent_down();
+  out.indent() << "end" << endl << endl;
 }
 
 THRIFT_REGISTER_GENERATOR(rb, "Ruby",