[et_pb_section bb_built=”1″ fullwidth=”on” specialty=”off” _builder_version=”3.0.64″ next_background_color=”#000000″][et_pb_fullwidth_post_title admin_label=”Blog Post Header” _builder_version=”3.17.2″ title=”off” meta=”off” categories=”off” comments=”off” featured_placement=”background” text_orientation=”center” module_class=”blog_post_header” title_font_size=”60px” background_blend=”saturation” title_font=”Raleway|on|||” title_text_color=”#274060″ title_letter_spacing=”2px” meta_font=”Raleway||||” meta_font_size=”20″ meta_text_color=”#274060″ meta_letter_spacing=”2px” /][/et_pb_section][et_pb_section bb_built=”1″ _builder_version=”3.0.63″ prev_background_color=”#000000″][et_pb_row _builder_version=”3.0.63″][et_pb_column type=”4_4″][et_pb_text admin_label=”Blog Post” _builder_version=”3.0.90″ background_layout=”light” saved_tabs=”all” global_module=”30698″ module_alignment=”left” text_font=”||||” header_font=”||||” max_width_tablet=”50px”]

Originally published: IT Jungle on 4/21/15

When I started with Ruby I was immediately drawn in by its syntax – simple, elegant, and easy to peruse. At the time I didn’t know this was an intentional mantra of the language put in place by Yukihiro “Matz” Matsumoto, Ruby’s creator. Matz said that he was “trying to make Ruby natural, not simple,” in a way that mirrors life. Further, Matz stated “Ruby is simple in appearance, but is very complex inside, just like our human body.” Let’s take this out of metaphor-land and into tangible code by introducing the DSL, or Domain Specific Language, aspect of Ruby.

First, what is a Domain Specific Language (DSL)? Martin Fowler describes it as “…a computer language that’s targeted to a particular kind of problem, rather than a general purpose language that’s aimed at any kind of software problem.” DSLs have existed for decades and you’ve probably been using them without even knowing it. For example, jQuery is an example of a DSL because it uses the Javascript language to define easier ways to do things specific things, like make AJAX calls. The SQL syntax is also a DSL because it is giving you a higher-level syntax with which to query the database.

In A Ruby and RPG Conversation, we introduced the xmlservice Gem and provided the following callable RPG program and corresponding Ruby invocation code.

--- MYLIB/PGM1 ---
 dcl-pr pgm1 extpgm; 
   char1 char(1);
   dec1 packed(7:4);
 dcl-pi pgm1;
   char1 char(1);
   dec1 packed(7:4);

 char1 = 'C';
 dec1 = 321.1234;
pgm1 = XMLService::I_PGM.new("PGM1", 'MYLIB') <<
       XMLService::I_a.new('mychar1', 1, 'a') <<
       XMLService::I_p.new('mydec1', 7, 4, 11.1111) 

One goal the xmlservice Gem team had was to create a DSL making it simpler and less verbose to make a call to programs. Looking at the above code we can see the “XMLService::” and “.new” text is repeated multiple times. What if we could get rid of that redundancy? We can. Below is a DSL to make program invocation simpler.

Author’s Note: The xmlservice Gem is now jointly maintained by IBM and the KrengelTech Litmis open source team at bitbucket.org/litmis/ruby-itoolkit

First we get an instance of the I_PGM Ruby object, which exists in the XMLService Ruby module. Next the DSL beauty comes into play when we invoke the input_parms method and pass in a Ruby block of the parameter definitions and initializing values.

pgm1 = XMLService::I_PGM.new('PGM1','AARONLIB')
pgm1.input_parms do
  char 'mychar1', 1, 'a'
  dec 'mydec1', 7, 4, 11.1111

What’s a Ruby block? In broader programming nomenclature it is a closure. Think of it as code that is sent to the method and invoked at a later point in time; in this case with what’s called the instance_eval method. Below is the input_parms method’s source code. Notice the &block being received into input_parms and subsequently used on the call to self.instance_eval. The instance_eval then evaluates the code and runs it in the context of itself, meaning, in this scenario, it looks for methods char and dec in this same Ruby program and invokes them.

def input_parms(&block)
  @xml_isParm = true

Below is the char method definition from the xmlservice Gem. Notice how it still, in the end, invokes I_a.new as we saw in the original more verbose version of the Ruby code? This is how the DSL wrapped the more complex and verbose code to come up with the concise new syntax.

def char(var, size, data=" ")
  el = I_a.new(var,size,data)
  if @xml_isParm

Ruby blocks and DSLs are used very frequently and in-favor over other language features. For example, the below shows a Ruby hash being iterated over using a Ruby DSL and block.

my_hash = { one:   "value 1", 
            two:   "value 2", 
            three: "value 3"}

my_hash.each do |key, value|
  puts "#{key} is #{value}"

The same iteration could have been accomplished using Ruby’s for statement.

for key, value in my_hash
  puts "#{key} is #{value}"

When I bring up the topic Ruby blocks during speaking engagements I always tell people “don’t worry if you don’t yet understand how the innards work, just be a good imitator of someone else’s code and copy/paste”. Or said another way: don’t worry if you don’t understand how Ruby blocks work under the covers and instead understand how to be a user of them. Here is another community reference on how DSLs in Ruby work if you’d like more in-depth examples. Stay tuned for more articles on all-things open source!

[/et_pb_text][/et_pb_column][/et_pb_row][et_pb_row][et_pb_column type=”4_4″][et_pb_text admin_label=”Contact Form Title” _builder_version=”3.0.90″ background_layout=”dark” saved_tabs=”all” global_module=”30700″ text_font=”Raleway|on|||” text_text_color=”#f45d01″ text_font_size=”26″ text_letter_spacing=”2px” module_alignment=”left” header_font=”||||” max_width_tablet=”50px”]

Need help with Ruby code? We’ve got you covered!

[/et_pb_text][/et_pb_column][/et_pb_row][et_pb_row admin_label=”Litmis Article Footer” _builder_version=”3.0.62″ background_position_1=”top_left” background_repeat_1=”no-repeat”][et_pb_column type=”4_4″][et_pb_text admin_label=”Contact Form” _builder_version=”3.0.64″ background_layout=”light” text_orientation=”left” border_style=”solid” saved_tabs=”all” global_module=”30748″]

  • This field is for validation purposes and should be left unchanged.