{"id":1370,"date":"2014-02-15T05:35:34","date_gmt":"2014-02-15T05:35:34","guid":{"rendered":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=1370"},"modified":"2014-02-15T05:55:24","modified_gmt":"2014-02-15T05:55:24","slug":"using-ruby-and-code-generation-to-save-time","status":"publish","type":"post","link":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/using-ruby-and-code-generation-to-save-time\/","title":{"rendered":"Using Ruby and Code Generation To Save Time"},"content":{"rendered":"\n<!-- Facebook Like Button v1.9.6 BEGIN [http:\/\/blog.bottomlessinc.com] -->\n<iframe src=\"http:\/\/www.facebook.com\/plugins\/like.php?href=http%3A%2F%2Finspiredtoeducate.net%2Finspiredtoeducate%2Fusing-ruby-and-code-generation-to-save-time%2F&amp;layout=standard&amp;show_faces=false&amp;width=450&amp;action=like&amp;colorscheme=light\" scrolling=\"no\" frameborder=\"0\" allowTransparency=\"true\" style=\"border:none; overflow:hidden; width:450px; height: 30px; align: left; margin: 2px 0px 2px 0px\"><\/iframe>\n<!-- Facebook Like Button END -->\n<p><a href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-content\/uploads\/2014\/02\/speed.jpg\"><img loading=\"lazy\" src=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-content\/uploads\/2014\/02\/speed.jpg\" alt=\"Speed\" title=\"speed\" width=\"500\" height=\"285\" class=\"alignnone size-full wp-image-1371\" srcset=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-content\/uploads\/2014\/02\/speed.jpg 500w, http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-content\/uploads\/2014\/02\/speed-300x171.jpg 300w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/a><\/p>\n<p>Working in information systems as a programmer, you often find yourself writing boring repetitious code over and over again.   Think about it.   Let\u2019s imagine you are writing code to access the following table.   How many times will you type those property names?<\/p>\n<p><code><br \/>\nCREATE TABLE user(<br \/>\nid VARCHAR(50) ,<br \/>\nuser_name VARCHAR(50) ,<br \/>\nfirst_name VARCHAR(140) ,<br \/>\nlast_name VARCHAR(140) ,<br \/>\nzip VARCHAR(20) ,<br \/>\nemail VARCHAR(140) ,<br \/>\nenable_flag INT ,<br \/>\npassword VARCHAR(140) ,<br \/>\ncreated_by VARCHAR(50) ,<br \/>\nupdated_by VARCHAR(50) ,<br \/>\ncreated_at INT ,<br \/>\nupdated_at INT ,<br \/>\nPRIMARY KEY ( id )<br \/>\n);<br \/>\n<\/code><\/p>\n<p>In typical business applications, you will repeat the column names of this table in a data transfer object, a repository class, unit test code, validation code and controller classes.  It&#8217;s not the most exciting code, it, however, needs to get done.  Inspired by <a href=\"http:\/\/hanselminutes.com\/152\/code-generation-and-t4-with-kathleen-dollard\" target=\"_blank\">talks by Kathleen Dollard<\/a>, consultant and code generation promoter in the .NET community, I decided to build a small code generation tool for myself that would help save me time.   I wanted to share parts of my code generation experiments with you.  I hope the case study helps you in designing your own code generation strategy.<\/p>\n<p><strong>Building a Simple Code Generation Tool<\/strong><\/p>\n<p>To give myself a simple start, I decided to express my entities using <a href=\"http:\/\/www.w3schools.com\/schema\/\" target=\"_blank\">XML Schema Definition(XSD)<\/a>, an open XML standard for describing the structure of information.  XSD is pretty easy to code by hand.   In the .NET world, it&#8217;s pretty simple to generate <a href=\"http:\/\/stackoverflow.com\/questions\/298660\/getting-xml-schema-from-ms-sql-database\" target=\"_blank\">a XSD from your database using DataAdapters or other methods<\/a>.  <\/p>\n<p><code><br \/>\n<?xml version=\"1.0\"?><br \/>\n<xs:schema xmlns:xs=\"http:\/\/www.w3.org\/2001\/XMLSchema\"><br \/>\n<xs:element name=\"user\"><br \/>\n  <xs:complexType><br \/>\n    <xs:sequence><br \/>\n\t  <xs:element name=\"id\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"user_name\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"first_name\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"last_name\" type=\"xs:string\"\/><br \/>\n\t  <xs:element name=\"zip\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"email\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"enable_flag\" type=\"xs:int\"\/><br \/>\n      <xs:element name=\"password\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"created_by\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"updated_by\" type=\"xs:string\"\/><br \/>\n      <xs:element name=\"created_at\" type=\"xs:dateTime\"\/><br \/>\n      <xs:element name=\"updated_at\" type=\"xs:dateTime\"\/><br \/>\n\t  <\/xs:sequence><br \/>\n  <\/xs:complexType><br \/>\n<\/xs:element><br \/>\n<\/code><\/p>\n<p>For this example, we will store the XSD in a file called &#8220;user.xsd.&#8221;<\/p>\n<p><a href=\"http:\/\/ironruby.codeplex.com\/\" target=\"_blank\">Using IronRuby<\/a>, I created a class that would convert an entity expressed in XSD into code.  IronRuby is an open source implementation of the Ruby language for the .NET framework.   The IronRuby project enables programmers to blend the capabilities of the .NET framework and Ruby.   When the &#8220;CodeGen&#8221; class is constructed, you provide a schema file, table name, a template, and namespace references.  <\/p>\n<p><code><br \/>\n#!\/usr\/bin\/env ruby<br \/>\nload_assembly \"System.Data\"<br \/>\ninclude System::Data<br \/>\nrequire 'erb'<\/p>\n<p>class CodeGen<br \/>\n  def camel_case(s)<br \/>\n\ts.gsub(\/(?<=_|^)(\\w)\/){$1.upcase}.gsub(\/(?:_)(\\w)\/,'\\1')\n  end\n\n  def initialize(schema_file, table_name, template_file, ui_namespace, model_namespace)\n    if schema_file == NIL\n      raise ArgumentError.new(\"schema_file is NIL\")\n    end\n\n    if table_name == NIL\n      raise ArgumentError.new(\"table_name is NIL\")\n    end\n\n    if template_file == NIL\n      raise ArgumentError.new(\"template_file is NIL\")\n    end\n\t\n\tif ui_namespace == NIL\n\t\traise ArgumentError.new(\"ui_namespace is required.\")\n\tend\n\n\tif model_namespace == NIL\n\t\traise ArgumentError.new(\"model_namespace is required.\")\n\tend\n\t    \n    if !File.exists?(schema_file)\n      raise ArgumentError.new(\"Schema file does not exist: #{schema_file}\" )\n    end\n\n    if !File.exists?(template_file)\n      raise ArgumentError.new(\"template_file does not exist: #{template_file}\" )\n    end\n\n    # read schema file....\n    @data_set = System::Data::DataSet.new()\n    @data_set.ReadXml(schema_file)\n    \n    #get table ref....\n    @table = @data_set.Tables[table_name]\n\t@entity_name = @table.TableName.capitalize\n\t@table_name = @table.TableName\n    @ui_namespace = ui_namespace\n\t@model_namespace = model_namespace\n\t@last_col = @table.Columns[@table.Columns.Count - 1].ColumnName\n\t\n\t\n    #load ERB templates ....\n    # http:\/\/stackoverflow.com\/questions\/980547\/how-do-i-execute-ruby-template-files-erb-without-a-web-server-from-command-line    \n    @template = ERB.new File.new(template_file).read, nil, \">\"<\/p>\n<p>\tend<\/p>\n<p>  def generate()<br \/>\n      return @template.result(binding)<br \/>\n  end<\/p>\n<p>  def get_human_db_ref(strDbRef)<br \/>\n\tstrDbRef.capitalize.gsub(\"_\",\" \")<br \/>\n  end<\/p>\n<p>end<br \/>\n<\/code><\/p>\n<p>I do acknowledge that we could have built this code generation framework using other technologies like <a href=\"http:\/\/www.hanselman.com\/blog\/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx\" target=\"_blank\">T4, another template technology available for .NET<\/a>.   I, however, enjoyed getting to learn Ruby and ERB.  Ruby is just a fun dynamic language!  It&#8217;s nice that you can quickly edit the templates without compiling.<\/p>\n<p>In the following lines, we create a &#8220;DataSet&#8221; object to read the schema data into memory.  This enables the code generation templates to know the columns defined for the entity and their respective data types.<\/p>\n<p><code><br \/>\n@data_set = System::Data::DataSet.new()<br \/>\n@data_set.ReadXml(schema_file)<br \/>\n<\/code><\/p>\n<p>Our templates that we will write depend upon several pieces of data: the schema data, entity name, table name, and other properties.  We store these elements as properties on the &#8220;CodeGen&#8221; object.   By doing this, the properties become available to the <a href=\"http:\/\/www.stuartellis.eu\/articles\/erb\/\" target=\"_blank\">ERB template system<\/a>.\t<\/p>\n<p><code><br \/>\n@table = @data_set.Tables[table_name]<br \/>\n@entity_name = @table.TableName.capitalize<br \/>\n@table_name = @table.TableName<br \/>\n...<br \/>\n<\/code><\/p>\n<p>In the following line, we use a ERB template to convert the table data into code.  <\/p>\n<p><code><br \/>\n@template = ERB.new File.new(template_file).read, nil, \">\"<br \/>\n<\/code><\/p>\n<p>The following code, shows a code template for generation an entity class in C#.  The ERB template utilizes the standard ADO.NET methods available on a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.data.datatable(v=vs.110).aspx\" target=\"_blank\">DataTable <\/a>class.<\/p>\n<p><code>using System;<\/p>\n<p>namespace <%=@model_namespace%><br \/>\n{<br \/>\n\tpublic class <%= @entity_name %><br \/>\n\t{<\/p>\n<p>\t\t<% for col in @table.Columns %><br \/>\n\t\t<%= col.DataType.to_s() %> <%= camel_case(col.ColumnName.to_s()) %>{get; set; }<br \/>\n\t\t<% end %>\t\t<\/p>\n<p>\t\tpublic <%= @entity_name %> ()<br \/>\n\t\t{<\/p>\n<p>\t\t}<br \/>\n\t}<br \/>\n}<br \/>\n<\/code><\/p>\n<p><code>#!\/usr\/bin\/env ruby<br \/>\nrequire 'CodeGen'<br \/>\nrequire 'fileutils'<\/p>\n<p>def rscg(schema_file, table_name, template_file, output_file, ui_namespace, model_namespace)<br \/>\n  code_gen = CodeGen.new(schema_file, table_name, template_file, ui_namespace, model_namespace)<br \/>\n  output = code_gen.generate()<br \/>\n  aFile = File.new(output_file, \"w\")<br \/>\n  aFile.write(output)<br \/>\n  aFile.close<br \/>\nend<\/p>\n<p>rscg(\"user.xsd\", \"user\", \"buildEntity.erb\", \"c:\\\\output\\\\#{table}.cs\", \"MyUINameSpace\", \"MyModelNameSpace\")<br \/>\n<\/code><br \/>\nRSCG stands for &#8220;real simple code generation.&#8221;   To execute the code generation process on one entity, you need to provide the XSD file, a table name, a template file name, an output file, and name space references.<\/p>\n<p><code>rscg(\"user.xsd\", \"user\", \"buildEntity.erb\", \"c:\\\\output\\\\#{table}.cs\", \"MyUINameSpace\", \"MyModelNameSpace\")<br \/>\n<\/code><\/p>\n<p>In researching this blog post, I discovered many more potential code generation solutions.  The listing include commercial offerings and open source options.   <\/p>\n<p><a href=\"http:\/\/en.wikipedia.org\/wiki\/Comparison_of_code_generation_tools\" title=\"Comparison of Code Generation Tools\" target=\"_blank\">http:\/\/en.wikipedia.org\/wiki\/Comparison_of_code_generation_tools<br \/>\n<\/a><\/p>\n<p>On my weekend programming projects, this simple code generation idea has saved me lots of time.   I&#8217;m currently adjusting my framework to generate unit test stubs, repository classes, entity classes, user interface, I hope you find the ideas helpful on your own projects.<\/p>\n<p><strong style=\"font-size: 13px; line-height: 19px;\">Featured Posts on InspiredToEducate.NET<\/strong><\/p>\n<ul>\n<li><a href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=1238\"  target=\"_blank\">17 Fun Tools To Teach Kids To Code by @ChrisBetcher<\/a><\/li>\n<li><a title=\"Benefits of Teaching Kids To Code That No One Is Talking About\" href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=623\" >Benefits of Teaching Kids To Code That No One Is Talking About<\/a><\/li>\n<li><a title=\"7 Reasons Why The Makers Movement Is Revolutionary\" href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=942\" >7 Reasons Why The Makers Movement Is Revolutionary<\/a><\/li>\n<li><a title=\"10 Free Resources for Learning JavaScript and HTML5\" href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=1285\" >10 Free Resources for Learning JavaScript and HTML5<\/a><\/li>\n<li><a title=\"Easy Data Visualization with Google Charts and JavaScript\" href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=1319\" >Easy Data Visualization with Google Charts and JavaScript<\/a><\/li>\n<li><a title=\"Maker Camp: Free Virtual Summer Camp for Teens\" href=\"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/?p=961\" >Maker Camp: Free Virtual Summer Camp For Teens<\/a><\/li>\n<\/ul>\n<p>Photo from <a href=\"http:\/\/netdna.webdesignerdepot.com\/uploads\/2013\/02\/featured20@wdd2x.jpg\" target=\"_blank\">http:\/\/netdna.webdesignerdepot.com\/uploads\/2013\/02\/featured20@wdd2x.jpg<\/a><\/p>\n\n<!-- Facebook Like Button v1.9.6 BEGIN [http:\/\/blog.bottomlessinc.com] -->\n<iframe src=\"http:\/\/www.facebook.com\/plugins\/like.php?href=http%3A%2F%2Finspiredtoeducate.net%2Finspiredtoeducate%2Fusing-ruby-and-code-generation-to-save-time%2F&amp;layout=standard&amp;show_faces=false&amp;width=450&amp;action=like&amp;colorscheme=light\" scrolling=\"no\" frameborder=\"0\" allowTransparency=\"true\" style=\"border:none; overflow:hidden; width:450px; height: 30px; align: left; margin: 2px 0px 2px 0px\"><\/iframe>\n<!-- Facebook Like Button END -->\n","protected":false},"excerpt":{"rendered":"<p>Working in information systems as a programmer, you often find yourself writing boring repetitious code over and over again. Think about it. Let\u2019s imagine you are writing code to access the following table. How many times will you type those property names? CREATE TABLE user( id VARCHAR(50) , user_name VARCHAR(50) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16,23],"tags":[],"_links":{"self":[{"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/posts\/1370"}],"collection":[{"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/comments?post=1370"}],"version-history":[{"count":6,"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/posts\/1370\/revisions"}],"predecessor-version":[{"id":1378,"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/posts\/1370\/revisions\/1378"}],"wp:attachment":[{"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/media?parent=1370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/categories?post=1370"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/inspiredtoeducate.net\/inspiredtoeducate\/wp-json\/wp\/v2\/tags?post=1370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}