Archive for the ‘Ruby’ Category

StrongRuby : gradual typing for Duby.

Abstract :

 

Static and dynamic type systems have well-known strengths and weaknesses. Statically typed programming languages incorporate a built-in static type system. Every legal program must successfully typecheck according to the rules of the type system.

 

Gradual typing provides the benefits of both static and dynamic checking in a single language by allowing the programmer to control whether a portion of the program is type checked at compile-time or run-time by adding or removing type annotations on variables. , that have no effect on the dynamic semantics of the language.

 

The complete proposal here : strongruby.pdf

Ruby idioms : Avoid check class membership

Avoid use class, is_a? and kind_of? to check class membership. Replace these statement with a message to the object that respond to the message. The code below is an anti-pattern.

if mortgage.class==FixRateMortgage
   mortgage.change_rate_not_allowed
else
   mortgage.rate=rate
end

The code below is more idiomatic in Ruby.

class Mortgage
  attr_accessor :rate
end 

class FixedRateMortgage < Mortgage
  def initialize()
    @rate=5
  end
  def rate=(rate)
    change_rate_not_allowed
  end

  def change_rate_not_allowed
     puts "The rate in a fixed rate mortage can not be change"
  end
end

Sending the method rate= to either kind of classes will result in the appropriate behaviour.

Commons bugs in ruby: blocks and local variables

Originally blocks did not have truly local variables. The block
parameters were really local variables in the enclosing method.

x=0
1.upto 100 do |z|
  x = x+z
end       
x  #=> 5050 

Commons bugs in ruby: Changing collection while iterating over it

You should never, never, never iterate over a collection which the iteration loop somehow modifies. Elements of the collection will be moved during the iteration. Elements might be missed or handled twice.

 b=(1..10).collect # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 b.each do |elem|
   b.delete elem
 end #=> [2, 4, 6, 8, 10]

Ruby idioms : Add a method to a concrete instance.

Sometimes can be useful to add a method in a specific instance of a class. We can do that with the next code :

 class Person
 end 

 pedro = Person.new
 peter = Person.new

 # inject a method in the instances
 def pedro.hello_world; puts "Hola Mundo"; end

 def peter.hello_world; puts "Hello World"; end 
 
 pedro.hello_world #=> Hola Mundo
 peter.hello_world #=> Hello World

A more useful example, an Array that represent a list of employees that must be sortable by any of the employee attributes : (via Neal Ford)

  employees  = []
  def employees.sort_by_attribute(sym)
    sort {|x, y| x.send(sym) <=> y.send(sym)}
  end

Dynamics finders in ActiveRecord using AOP.

Yesterday, I have been playing with Aquarium, an AOP framework for ruby. I decided hack a little bit. I try to refactor the dynamics finders of ActiveRecord, using an AOP approach.

First lets try to understand what are and how dynamics finders works.

This are queries are equvalent :

User.find(:first, :conditions => ["name = ?", name])
User.find_by_name(name)

User.find(:all, :conditions => ["city = ?", city])
User.find_all_by_city(city)

User.find(:all, :conditions => ["street = ? AND city IN (?)", street, cities])
User.find_all_by_street_and_city(street, cities)

And how this cool methods are generated? They are not generated, ActiveRecords use a bit of the method_missing magic to parse the method_name to find a pattern. A simplify version of the method_missing :

def method_missing(method_id, *arguments)
  if match = /find_(all_by|by)_([_a-zA-Z]\w*)/.match(method_id.to_s)
    # find...
  elsif match = /find_or_create_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
    # find_or_create...
  else
    super
  end
end

Now its time to introduce the AOP in the recipe. We create two advices, the pointcut is the method missing. This two advices perform as a chain, first the last defined.

class Base
    before :method=>:method_missing do |this, execution_point, *args|
        if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(args.fir st.to_s)
            # find_by_xxx... #do something smart and break the flow
        end
    end

    before :method=>:method_missing do |this, execution_point, *args|
        if match = /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/. match(args.first.to_s)
          # find_or_xxx #do something smart and break the flow
        end
    end

  # And so on, until you have a minimum common behaviour or an empty method_missing.   
end

We can extract more behaviour from the method missing, We can repeat this process until we have the minimum common behaviour or a empty method_missing. Sometimes we neer to break the chain at some point. In this cases we can uses around.

One of the benefits of this approach is that will be more easy to introduce new finder in rails. Currently to create a new finder we need to create a plugin in the vendor folder. For example we are going to create a find_like finder. We write our code in the vendor/plugins/find_like/lib/find_like.rb :

module ActiveRecord
  class Base
    class << self
      private
      alias_method :previous_method_missing, :method_missing
     def method_missing(method_id, *arguments)
        if match = /find_(all_like|like)_([_a-zA-Z]\wo*)/.match(method_id.to_s)
           # do something smart 
        else
          previous_method_missing(method_id, *arguments)
        end
      end
    end
  end
end

If we use the AOP approach we need to write, also our code in the vendor/plugins/find_like/lib :

module FinderLike
 # A custom finder finder_like_xxx
 before :types => :Base, :methods =>:method_missing do |execution_point,  *args|
   if match = /find_(all_like|like)_([_a-zA-Z]\w*)/.match(args.first.to_s)
     # Do something smart and break the flow     
   end
 end
end

I Don’t know if this is a good design in this particular case. But at least was a funny Kata.

blocks parameters list and metaprogramming

I have been playing with a Aquarium, the new AOP framework in Ruby. A point advice is create for example :

before :type=>A, :method=>:foo do |execution_point, *args|
  self.some_method() # call a class method from A
  other_method()     # call other class method from A
  # call a method from the caller object
  execution_point.context.advised_object.bar()  
end 

The DSL is nice but i found the access to the caller object is a tedious. I prefer something like this :

before :type=>A, :method=>:foo do |execution_point,this , *args|
  self.some_method() # call a class method from A
  other_method()     # call other class method from A
  # call a method from the caller object
  this.bar()  
end 

Dean Wampier think thats would be great if the user could specify combinations
like these:

|join_point, the_self, *method_args|
|join_point|
|the_self|
|the_self, *method_args|
|join_point, the_self|
|join_point, *method_args|

But the point is that the advices is create in the “definition time class” using some code generation at
runtime. How can i know the arity of the argument list.

module Kernel  
  def before (name, &block) 
    define_method(name){ 
      if block.arity == 1
        yield :only_one
      elsif  block.arity == 2
        yield :one,:two
      elsif block.arity == -2
        yield :one, :a , :splater, :argument
      end
    }
  end
end

class A  
  before :foo do |first|   
    puts first
  end
end

a = A.new 
a.foo

class A
  before :foo do |first , second|
    puts second
  end
end

a2 = A.new 
a2.foo

class A
  before :foo do |first , *splat_arg| 
    puts splat_arg
  end
end

a3 = A.new 
a3.foo

Thats great, the block can be acceded because its a Proc class. Now we can predict the number of parameter of that the user has write and create a more friendly DSL.

Default values and Hash parameters

I had talked before about it. We can use a hash to pass parameter to our method, and que can merge with another hash that contain the defaults values. Why to do that :

  • Set Default Values in Methods : Avoid unexpected behaviour.
  • Simple Hash as Default Method Parameter : This form allows you to add functionality to methods without breaking existing calls
def add_book(p_arg)

  p_arg = {:title=>"no title", 
           :author=>"anonymous",
           :language=>"esperanto"}.merge! p_arg

end
add_book :title=>"El Qujote",
         :author=>"Miguel De Cervantes",
         :language=>"spanish"

=> {:language=>"spanish", :title=>"El Qujote", :author=>"Miguel De Cervantes"}
add_book :title=>"El Qujote",
         :author=>"Miguel De Cervantes"

=> {:language=>"esperanto", :title=>"El Qujote", :author=>"Miguel De Cervantes"}
add_book :title=>"El Qujote",
         :author=>"Miguel De Cervantes"
         :foo=>:bar

=> {:language=>"esperanto", :foo=>"bar" ,:title=>"El Qujote", :author=>"Miguel De Cervantes"}

Ramdon tips for Rails

  • MVC as a constraint
  • Over do MVC
  • Don’t put any code in the view
  • Don’t do any DB operation in the controller
  • Set Default Values in Methods : Avoid unexpected behaviour.
  • Simple Hash as Default Method Parameter : This form allows you to add functionality to methods without breaking existing calls
  • Helpers are hard to test, its will turn Rails into PHP

Multiples assignmets in a for loop clause.

1
2
3
4
5
 for hello, world in [ [:Hola, :Mundo],
                       [:Hallo, :Welt], 
                       [:Foo, :Bar]    ]
   puts "#{hello} #{world}"
 end
Follow

Get every new post delivered to your Inbox.