Ruby Data Type Check with Metaprogramming

Ruby Data Type Check

##
# Provides functionality for checking if given object is of a specific data type.
# ---
# Currently supporting the following data types:
#   * Array
#   * String
#   * Integer
#
# = Example
#  users = ['jack', 'joe', 'john', 'anotherJname']
#  puts "This will happen, as it's true" if users.is_array?
#
#  str = "Hello world!"
#  puts "This too will happen" if str.is_string?
#
#  puts "Oh, and this is going to happen" if 10.is_int?
#
class Object
  @@typeConv = {
    :array    => 'Array',
    :string   => 'String',
    :int      => 'Integer'
  }

  def method_missing(method, *args, &block)
    if method.to_s =~ /is_(\w+)\?/ && @@typeConv[$1.to_sym]
      type = $1.to_sym
      is = false

      self.tap do |o|
        is = o.kind_of?(eval(@@typeConv[type]))
      end

      is
    else
      super
    end
  end
end

How often do you find yourself checking to see whether an object in array?  Or a string or an integer?  And when you do, you’re using is_a? or kind_of?, right?

I ran into a little project on Github called Simple. Simple is a Ruby script that provides some basic functionality developers may find useful. In this script I saw that the author had defined three methods:

1
2
3
4
5
6
7
8
9
10
11
def is_array(simple_data_type)
  return simple_data_type.kind_of?(Array)
end
 
def is_int(simple_data_type)
  return simple_data_type.kind_of?(Integer)
end
 
def is_string(simple_data_type)
  return simple_data_type.kind_of?(String)
end

Not a big deal, but using them is clunky:

if is_string("Hello world")
  # Do something
end

My first reaction was just to apply some basic Rubyism and submit it as a pull request. Basically, I would’ve just dropped the returns and appended a question mark to the method names. But I realized very quickly that this could be a great opportunity to employ some metaprogramming.

Enter the code above.

What I’ve done is I’ve overwritten the method_missing method of Object. This way I catch any and all method calls that shouldn’t exist (as our new methods shouldn’t). And I check to see if it’s a method we’re looking for (is_array?, is_string? or is_int?).

If the method lines up then we perform a tap. I’ve opted to use tap so that I can more easily capture the caller of the method. Tap will, by its nature, return the caller. This isn’t what we want, so I toggle a boolean variable to match the data type check and return that at the end of the method.

Notice lines 35 and 36. They may be the most important. It’s imperative that our code not have side effects outside of its own scope. If we did not include lines 35 and 36 (which are just saying “if it’s not a method we want to capture then do your normal routine) then errors would be suppressed when they really shouldn’t be.

Metaprogramming is great in what tools it provides for us. But always remember to be responsible!

Bob Hensley

IT Manager | Webmaster | Social Media Strategist | SEO Specialist | Copywriter at Fairfield's Auto Group
Bob Hensley is an IT Manager, Webmaster and all-around advertising guy by day; database theory junkie by night.Born and raised in New England, he lives just a couple hours outside of Boston with his lovely wife and one year old son.He's a technologist, and thoroughly enjoys finding new ways to use technology to better efficiency and work flows.

Latest posts by Bob Hensley (see all)

Leave a Reply

Your email address will not be published. Required fields are marked *

*