The details for the next meeting of the Cape Town Ruby Brigade are
More information at the meeting page.
In the first post in our series ‘Unlocking the Power of Casey Equality’ we talked about adding case equality to Procs. In this post we’ll talk about how we can extend Enumerable to take advantage of the case equality operator ‘===’ to write even cleaner and more elegant code than using the regular block syntax.
Enumerable is one of Ruby’s more powerful modules. By simply implementing ‘each’, which successively yields each element in a collection, and including the Enumerable module, your collection gains the methods in Enumerable which include workhorses like ‘map’, ‘inject’ and ‘to_a’. Builtin classes like Array and Hash have Enumerable included automatically.
Of the included methods let’s look at one particular method: ‘grep’. ‘grep’ takes a a single argument called the pattern, and that pattern only needs to respond to ‘===’ (see where we’re going here?). Each element is compared to the pattern with ‘===’ and if the comparison is successful the element is included in the results array. The following code shows how a Range or Class, which both implement ===, can be used with ‘grep’.
1 [1,2,3,4,5,6,7].grep( 3..5 ) # => [3,4,5] 2 ["1",1,"2",2,"3",3].grep( String ) # => ["1","2","3"]
Now compare line 2 to the following code snippet using block syntax, which checks if every element in an array is a String:
1 ["1",1,"2",2,"3",3].all? { |e| e.instance_of? String } # => false
If we could apply the ‘grep’-style of passing objects that respond to ‘===’ to a function like ‘all?’ we could have code that looks like:
1 ["1",1,"2",2,"3",3].all? String # => false
Which looks a lot cleaner and nicer than using a block and having to explicitly call ‘instance_of?’. Reading the snippet above it’s functionality is still quite apparent: ’Are all the elements of the array strings?".
When a pattern and a block are both present they are both applied to the element and their results are combined with &&.
1 [1,2,3,4].all?( Integer ){ |i| i < 5 } # => true
Implementing the modifications would seem to require minimal changes to existing code. For instance ‘all?’ is implemented in C in the Ruby API but the modified code for the Rubinius VM would be:
1 module Enumerable 2 def all?( pattern = Object, &prc ) 3 prc = Proc.new{ |o| o } unless block_given? 4 each{ |o| return false unless ( pattern === o ) && prc.call( o )} 5 true 6 end 7 end
We set the default value of the pattern to Object because every instantiated object has the Object class in it’s ancestry and so ‘object.kind_of?( Object ) is true and therefore ’Object === object’ will always return true.
The following methods in Enumerable would be candidates to be modified to take a pattern argument along with a block:
Some example usage:
1 ["1",2,"3",4,"5"].count String # => 3 2 ["aaa","aab","aac"].detect /ac/ # => "aac" 3 [100,50,25].one? 20..30 # => true
I don’t think these proposed changes would ever get into the Ruby API (at least not in the near future), but it does go to show there is still room to make things even more concise and elegant.
The ‘===’ operator is known as the case equality operator and is used when testing cases in case statements. Many classes take advantage of this by implementing their own versions of ‘===’ to enable developers to write neat, compact code. It’s use could potentially be expanded even further. For instance in the following case statement:
1 case number 2 when 1: puts "One" 3 when 2..10: puts "Between two and ten" 4 when String: puts "Not a number" 5 end
for each ‘when’ statement the ‘===’ operator is called on the when argument (1,2..10,String) and the case argument (number) is used as the RHS of the comparison. For line 2 the comparison done will be ‘1 === number’.
For most classes ‘===’ is just an alias to ‘==’ however some classes redefine ‘===’ to allow for better functionality in case statements. Range redefines ‘1..10 === 5’ to ‘1..10.include?(5)’ and Regex redefines ‘/abcdef/ === “abcdef”’ to ‘/abcdef/ =~ “abcdef”’ (the Regexp matching operator). Consider also the fact that Range, Regexp and Class can match multiple parameter values against the same object with ‘===’. Any integer from 1 to 10 will cause ‘1..10 === num’ to evaluate to true. Similarily “aaa”, “baaab” and “caaac” all satisfy the RHS of ‘/aaa/ === str’ and 1,2 and 3 will satisfy the RHS of ‘Integer === number’.
But what about Proc? In Ruby a Proc is a block of executable code, an anonymous function which can be passed around as if it were data. Like ‘===’, a Proc can map a number of arguments to either a true or false value (although in Ruby it could have a number of outputs but only ‘nil’ and ‘false’ will be considered false). So there is justification that Proc should have an ‘===’ operator.
For instance given two Proc objects as follows:
1 multiple_of_3 = lambda do |number| 2 number.modulo(3).zero? 3 end 4 multiple_of_7 = lambda do |number| 5 number.modulo(7).zero? 6 end
we want
1 multiple_of_3 === 14 # => false 2 multiple_of_7 === 14 # => true
so that
1 case 14 2 when multiple_of_3: puts "Multiple of 3" 3 when multiple_of_7: puts "Multiple of 7" 4 end
will satisfy the expression on line 3 and output “Multiple of 7” to the screen.
Implementing this in Ruby is easy, we simply take the parameter to === and pass it as the parameter to Proc#call:
1 class Proc 2 def ===( *parameters ) 3 self.call( *parameters ) 4 end 5 end
Using the splat operator allows for Proc to use ‘===’ with multiple parameters, you merely specify the parameters in an array. So given the following Proc:
1 multiples_of_5 = Proc.new{|*parameters| parameters.all?{|i| i.modulo(5).zero?}}
then line 2 will be satisfied
1 case [5,10,15] 2 when multiples_of_3: puts "Multuples of 5" 3 when multuples_of_5: puts "Multiples of 7" 4 end
Now creating Procs for each case is a bit tiresome and doesn’t seem to save any keystrokes but using Ruby’s ability to dynamically create Procs we can define a function to do it for us:
1 def multiple_of(factor) 2 Proc.new{|product| product.modulo(factor).zero?} 3 end 4 5 case number 6 when multiple_of(3): puts "Multiple of 3" 7 when multiple_of(7): puts "Multuple of 7" 8 end
Put the ‘multiple_of’ function in a utility library and your resultant code looks pretty neat and tidy.
In our next posting in the “Unlocking The Power Of Case Equality” series of posts we’ll talk about how Enumerable could take advantage of case equality.
Dave Thomas (of Pragmatic Programmers fame) describes some new Ruby 1.9 syntax:
first, *, last = 1,2,3,4,5 puts first puts last
will produce
1 5
The same syntax also works for method definitions
def test( first, *, last) puts first puts last end test( 1, 2, 3, 4, 5 )
will produce the same output as above.
Sequel 2.0 Release Candidate has just been released. All deprecated methods have been removed so it’s probably a good idea to check your existing code before porting over.
Don’t forget the next meeting of the Cape Town Ruby Brigade takes place at 19:00 this Wednesday 14th May at the Bandwidth Barn in Cape Town. This months topic will be a report back on the Scotland on Rails conference. More details at the Cape Town Ruby Brigade Google group meeting page.
One nice thing about Sequel::Model is that it allows both hash and block instantiation of models.
1 values = { :name => "Bob Roberts" } 2 organisation = Organisation.new( values ) do |o| 3 o.name ||= random_organisation_name 4 o.email_address ||= random_organisation_email 5 o.phone_number ||= random_phone_number 6 end
The call to Organisation.new( values ) sets the
attributes from the hash and then using Ruby’s ||=
operator (remember a ||= b is equivalent to a = a ||
b) in the block we set any attributes not present in the hash.
One of the biggest gripes with Ruby on Rails has been the pain it can cause when it comes to deployment. Since Rails was released there have been an evolution from
which is a bit more effort than for instance trying to setup PHP which requires just Apache and mod_php.
Luckily Passenger has been released by the guys at Phusion. Put simply Passenger is mod_rails for Apache. You configure your application directory in your Apache config file and simply drop your application in that directory and Passenger will pick it up and execute it. According to initial benchmarks released it provides excellent performance as well.
At the moment it’s a Rails only plugin, but I wouldn’t expect there to be to long before it’s widened to other frameworks. In particular providing support for Rack would allow for a whole host of new and exciting frameworks.
Please note we have a new address for this blog’s RSS feed. Other Aimred RSS feeds are available on our RSS Homepage.