More Ruby tips and tricks

String to number conversion gotcha

>> Float('3.14159')
=> 3.14159 
>> '3.14159'.to_f
=> 3.14159 

# However, Float() method will return an exception if given
# a bad input while to_f() will ignore everything from the 
# offending character.

>> Float('3.x14159')
ArgumentError: invalid value for Float(): "3.x14159"
	from (irb):4:in 'Float'
	from (irb):4

>> '3.x14159'.to_f
=> 3.0


# Similar case with to_i() and Integer().

>> Integer('19x69')
ArgumentError: invalid value for Integer(): "19x69"
	from (irb):15:in 'Integer'
	from (irb):15
	from /Users/greg/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in '<main>'

>> '19x69'.to_i
=> 19 

Case insensitive regular expression

# Regex is case sensitive by default. 
# Adding 'i' for insensitive match
puts 'matches' if  /AM/i =~ 'am'

Hash is ordered in 1.9

# new syntax in 1.9
h = {first: 'a', second: 'b', third: 'c'}

# hashes in 1.9 are ordered
h.each do |e|
  pp e
end

Filter a list using several conditions

conditions = [
    proc { |i| i > 5 },
    proc { |i| (i % 2).zero? },
    proc { |i| (i % 3).zero? }
  ]

matches = (1..100).select do |i|
  conditions.all? { |c| c[i] }
end

Randomly pick an element from an array

>> [1,2,3,4,5].sample
=> 2 
>> [1,2,3,4,5].sample
=> 1 

# pick 2 random elements

>> [1,2,3,4,5].sample(2)
=> [1, 5]

List methods unique to a class

# List all instance methods that starts with 're' 
# including those inherited by String.

>> String.instance_methods.grep /^re/
=> [:replace, :reverse, :reverse!, :respond_to?, :respond_to_missing?] 

# List methods unique to String, i.e. not include 
# those defined by its ancestors.

>> String.instance_methods(false).grep /^re/
=> [:replace, :reverse, :reverse!]

Globbing key-value pairs

>> h = Hash['a', 1, 'b', 2]
=> {"a"=>1, "b"=>2}

>> h = Hash[ [ ['a', 1], ['b', 2] ] ] 
=> {"a"=>1, "b"=>2}

>> h = Hash[ 'a' => 1, 'b' => 2 ]
=> {"a"=>1, "b"=>2}

# The first form is very useful for globbing key-value pairs in Rails’ routes. For example, if you have the following:

# route definition in Rails 3
match 'items/*specs' => 'items#specs'

# sample url
http://localhost:3000/items/year/1969/month/7/day/21

# params[:specs] will be set

>> params[:specs]
=> "year/1969/month/7/day/21"

>> h = Hash[*params[:specs].split('/')]
=> {"year"=>"1969", "month"=>"7", "day"=>"21"}

Scala loops

Today, I finally got to play with Scala. I’ve been using mainly Ruby (and loving it) for most of my projects but I promised myself (in one of my new year’s resolution) that I will learn a new programming language this year. So from time to time, I will sprinkle this blog with some Scala love.

Now, for some mandatory hello world program. Nah. The code below simply prints the arguments to your Scala program.

var i = 0
while (i < args.length) {
  println("hello " + args(i) + "!")
  i += 1
}

// Assuming you have saved the code in hello.scala, do the following to run the code:
// scala hello.scala arg1 arg2 arg3

The code above is an imperative style used normally in languages like C or C++. Most new programmers are exposed to this style.

Being a Ruby developer, I quickly wondered if there is something similar to “.each” method? Yes, there is.

args.foreach(arg => println(arg))
args.foreach(println)

Above is a functional style and is something you will be comfortable with as you improve your programming skill. In Scala, the second line is possible if the function accepts a single argument.

Since ‘println’ is just a function, you could just replace it with your own function.

def printer(x: String) = {
  println(x.toUpperCase)
}

args.foreach(arg => printer(arg))

Yes, you guessed right. You can also define anonymous function.

args.foreach(arg => { println(arg.toUpperCase) })

When I first heard that Scala is somewhat related to Java, my first thought was it is going to be another verbose language. Well, I was wrong 🙂 It appears to be a fun and powerful language worth learning.

24 Ruby tips and tricks

Peter Cooper will share more tips in his book to be released later this year. Stay tune and don’t forget to leave your email address to get updates at http://rubyreloaded.com/trickshots/

Here are some of the tips in the video.

Generate random numbers within a given range

irb(main):019:0> rand(10..20)
=> 12
irb(main):020:0> rand(10...20) # works with exclusive range
=> 16

Dump your object using awesome_print

# Install the gem first
gem install awesome_print

irb(main):001:0> require 'ap'
=> true
irb(main):002:0> ap :a => 1, :b => 'greg', :c => [1,2,3]
{
    :a => 1,
    :b => "greg",
    :c => [
        [0] 1,
        [1] 2,
        [2] 3
    ]
}
=> {:a=>1, :b=>"greg", :c=>[1, 2, 3]}

Concatenating strings

irb(main):005:0> "abc" + "def"
=> "abcdef"
irb(main):006:0> "abc".concat("def")
=> "abcdef"
irb(main):007:0> x = "abc" "def"
=> "abcdef"

Include modules in a single line

class MyClass
  include Module1, Module2, Module3
  # However, the modules are included in reverse order. Confusing eh!
end

Instance variable interpolation

irb(main):008:0> @name = "greg"
=> "greg"
irb(main):009:0> "my name is #{@name}"
=> "my name is greg"
irb(main):010:0> "my name is #@name"
=> "my name is greg"

I still prefer the use curly braces.

Syntax checking

➜  ruby -c facu.rb 
facu.rb:12: syntax error, unexpected keyword_end, expecting $end

Zipping arrays

irb(main):027:0> names = %w(fred jess john)
=> ["fred", "jess", "john"]
irb(main):028:0> ages = [38, 47,91]
=> [38, 47, 91]
irb(main):029:0> locations = %w(spain france usa)
=> ["spain", "france", "usa"]
irb(main):030:0> names.zip(ages)
=> [["fred", 38], ["jess", 47], ["john", 91]]
irb(main):031:0> names.zip(ages, locations)
=> [["fred", 38, "spain"], ["jess", 47, "france"], ["john", 91, "usa"]]

Range into arrays

irb(main):034:0> (10..20).to_a  # what I used to do
=> [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
irb(main):035:0> [*10..20]
=> [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Using parameter as default value

irb(main):047:0> def method(a, b=a); "#{a} #{b}"; end
=> nil
irb(main):048:0> method 1
=> "1 1"
irb(main):049:0> method 1, 2
=> "1 2"

Put regex match in a variable

irb(main):058:0> s = "Greg Moreno"
=> "Greg Moreno"
irb(main):059:0> /(?<first>\w+) (?<second>\w+)/ =~ s
=> 0
irb(main):060:0> first
=> "Greg"
irb(main):061:0> second
=> "Moreno"

Ruby 101: method_missing gotchas

Forgetting ‘super’ with ‘method_missing’

method_missing is a hallmark of Ruby metaprogramming. It is one of those coding techniques that you need to master if you want to move from white belt to black belt. Aside from that, it is also fun to use.

  class RadioActive
    def initialize(path)
      ...
    end

    def to_format(format)
      ...
    end
  end
  
  
  d = RadioActive.new('/path/to/uranium')
  d.to_format('xml')

It works but you want explicit methods for each format. So you tap into your Ruby skills and implement your own method_missing.

  class RadioActive
    def method_missing(name, *args)
      if name.to_s =~ /^to_(\w+)$/
        to_format($1)
      end
    end
  end
  
  
  d = RadioActive.new('/path/to/uranium')
  d.to_xml            # WORKS
  d.to_format('xml')  # WORKS
  d.undefined_method  # FAILS

Unfortunately, the last call to ‘undefined_method’ fails. Actually, you would not know it fails because Ruby will not fire any exception. In case there is an undefined method, let us see how Ruby handles it.

  >> s = 'uranium'
   => "uranium" 
  >> s.to_xml
  NoMethodError: undefined method `to_xml' for "uranium":String

There you go. But there is no need to raise the ‘NoMethodError’ in your code. Instead, simply call ‘super’ if you are not handling the method. Whether you have your own class or inheriting from another, do not forget to call ‘super’ with your ‘method_missing’

  class RadioActive
    def method_missing(name, *args)
      if name.to_s =~ /^to_(\w+)$/
        to_format($1)
      else
        super
      end
    end
  end
  
  d = RadioActive.new('/path/to/uranium')
  d.undefined_method
  # => in `method_missing': undefined method `undefined_method' for # (NoMethodError)

Calling ‘super’ is not just for ‘missing_method’. You also need to do the same for the other hook methods like ‘const_missing’, ‘append_features’, ‘method_added’.

Forgetting respond_to?

If you modify ‘method_missing’, it will also affect the behavior of ‘respond_to?’ because what you are adding in as methods do not actually exist — they are ghost methods. If you check the list of instance methods for our class, it will only show 2.

  >> RadioActive.instance_methods(false)
  => ["method_missing", "to_format"]
 
  >> d.respond_to?('to_format')
  => true
  >> d.respond_to?('to_xml')
  => false
  

Every time you modify ‘method_missing’, you also need to update ‘respond_to?’

  class RadioActive
    def respond_to?(name)
      !!(name.to_s =~ /^to_/ || super)
    end
  end
  

Preventing model explosion via Rails serialization

A great thing about ActiveRecord is you can easily add a new model to your application and play around with it as you progress. However, this power can easily be overused leading to unnecessary overhead in your code.

Consider the case where you have preferences for each user. For example, a user may opt to show or hide his email address, adjust his timezone, or language. One solution is to simply add new columns to the users table that correspond to each preference type. For example, you can have a ‘show_email’, ‘timezone’, ‘locale’ columns in the ‘users’ table, which can make your table become wide as you add more preferences options. Another option is to use a separate ‘preferences’ table.

  class User < ActiveRecord::Base
    has_many :preferences
  end

  class Preferences < ActiveRecord::Base
    belongs_to :user

    # name  - preference name
    # value - preference value
  end
  

Note there is no user interface to add or remove ‘preferences’, i.e. the kinds of preferences are fixed. Of course, in the future you may add a new kind of preference but this kind of work is better done outside of the user interface. Since that is the case, there is no need to represent ‘preferences’ as a separate model.

One better alternative is to use Rails serialization to store the different kinds and user-specific values. The code would look like this:

  class User < ActiveRecord::Base
    serialize :preferences, Hash
  end

  u = User.new
  u.preferences = {:show_email => true, :locale => :en }
  u.save

  # somewhere in your view using haml
  - if @user.preferences[:show_email]
    = @user.email
  

Using ‘serialize’ results in less code, fewer tables, and less overall complexity. However, with serialization you lose the ability to efficiently search the preferences data. The million-dollar question is do you need to query these preferences? Do you need a finder that returns all users who wants to show their email?

One issue I had with ‘serialize’ is that by using it, I expose the implementation details. In the display example above, it is obvious I had it stored as a Hash. I would rather hide this detail and present the preferences attributes as user attributes instead. I also want default values for every user.

For example:

  u = User.new  # automatically assigns the default preferences
  u.preferences
  => {:show_email => false, :locale => :en}

  u.show_email = true  # I can change it like an attribute via @user.update_attributes(params[:user])
  u.preferences
  => {:show_email => true, :locale => :en}
  

I have created a module to support this. It is not a unique problem so others may have probably released a gem or plugin to do this. (I actually never bothered to search for one.) Nevertheless, it was a good exercise in metaprogramming.

To use my implementation, simply call ‘serializeable’ with the column you want to serialize and the default values.

  class User < ActiveRecord::Base
    serializeable :preferences, :show_email => true, :locale => :en
  end
  

Below is the implementation of ‘serializeable’. The convention is to save it under your ‘lib’ folder and include it in your ‘config/application.rb’ if you are using Rails 3.

  module AttributeSerializer
  
    module ActiveRecordExtensions
      
      module ClassMethods
  
        def serializeable(serialized, serialized_accessors={})  
          serialize serialized, serialized_accessors.class
  
          serialized_attr_accessor serialized, serialized_accessors
          default_serialized_attr serialized,  serialized_accessors
        end
  
        # Creates the accessors
        def serialized_attr_accessor(serialized, accessors)
          accessors.keys.each do |k|
            define_method("#{k}") do
              self[serialized] && self[serialized][k]
            end
  
            define_method("#{k}=") do |value|
              self[serialized][k] = value
            end
          end
        end
  
        # Sets the default value of the serialized field
        def default_serialized_attr(serialized, accessors)
          method_name =  "set_default_#{serialized}"
          after_initialize method_name 
  
          define_method(method_name) do
            self[serialized] = accessors if self[serialized].nil?
          end
        end
  
      end
  
    end
  
  end
  
  class ActiveRecord::Base
    extend AttributeSerializer::ActiveRecordExtensions::ClassMethods
  end
  

ActiveRecord is both easy and powerful. It can also lead to misuse and abuse. Even though you are adding just one model, remember that it is not just the model class itself. You are also adding the database migrations, unit tests, factories, finders, and validations that go along with the model. Next time you have a new requirement, see if serialization can do a better job.

Update: Adam Cuppy converted this code into a Rails plugin while Jay added dynamic finder methods. I also moved this into a gem I called ‘fancy_serializer‘.

Ruby 101: Improving your code by defining methods dynamically

Let’s say you have a user and you want to check its role.


  class User
    attr_accessor :role
  end
  
  u = User.new
  u.role = 'admin'
  
  # somewhere in your code you check the role
  
  if u.role == 'admin'
    puts 'admin'
  elsif u.role == 'moderator'
    puts 'moderator'
  elsif u.role == 'guest'
    puts 'guest'
  end

  

Using a string value is bad code and you can improve this by using constants instead. But still, this is bad code becauses it exposes implementation details of your User class.

For our first improvement, we define methods that check the user’s role and hide the implementation of the role checking inside the User class.


  class User
  
    attr_accessor :role
  
    def is_admin?
      self.role == 'admin'
    end
  
    def is_moderator?
      self.role == 'moderator'
    end
  
    def is_guest?
      self.role == 'guest'
    end
  
  end
  
  u = User.new
  u.role = 'guest'
  
  
  if u.is_admin?
    puts 'admin'
  elsif u.is_moderator?
    puts 'moderator'
  elsif u.is_guest?
    puts 'guest'
  end

  

Our first improvement is definitely better than the original but there are duplicate code in the role checking. You can eliminate the duplicate code by delegating the role checking to a single method.

  class User
  
    attr_accessor :role
  
    def is_admin?
      is_role? 'admin'
    end
  
    def is_moderator?
      is_role? 'moderator'
    end
  
    def is_guest?
      is_role? 'guest'
    end
  
  protected
  
    def is_role?(name)
      self.role == name
    end
  
  end

  

Our second improvement is a classic refactoring technique and common in any modern programming language. In other words, there is nothing “Ruby” about it. Before you get bored, I will now show the Ruby version.

The Ruby version uses ‘define_method()’ to further eliminate duplicate code.


  class User
  
    attr_accessor :role
  
    def self.has_role(name)
      define_method("is_#{name}?") do
        self.role == "#{name}"
      end
    end
  
    has_role :admin
    has_role :moderator
    has_role :guest
  
  end

  

By using ‘define_method()’, we were able to add instance methods to our class User. You can check the new instance methods via irb.


  ruby-1.9.2-p0 > User.instance_methods.grep /^is/
  => [:is_admin?, :is_moderator?, :is_guest?, :is_a?] 

  

Note that ‘has_role()’ is just another method and as such you can modify it to accept several parameters, an array, or other class. For example, we can make ‘has_role’ accept a list of roles.

  class User
  
    attr_accessor :role
  
    def self.has_roles(*names)
      names.each do |name|
        define_method("is_#{name}?") do
          self.role == "#{name}"
        end
      end
    end
  
    has_roles :admin, :moderator, :guest
  
  end