MetaGreg

writes code that writes code for food

Archive for the ‘programming’ tag

DHH’s RailsConf 2010 Keynote Video

without comments

The keynote is about Rails 3.0 and the many enhancements it bring to make web application development more fun. The improvements in writing database queries (via ActiveRelation), routes, ActionMailer are really neat and I believe would make it easier for developers to get on board with Rails.

The official release will be available in a few weeks but the current version is already good enough for production use according to DHH.

Written by Greg Moreno

June 11th, 2010 at 3:59 pm

Posted in Sideways

Tagged with , ,

Ruby 101: Make your class behave like a Ruby built-in

without comments

I got re-acquianted with this scenario while working on the OpenAmplify gem – a wrapper for the OpenAmplify API. When you give the api a text like a blog comment, it will return a list of common terms, opinion scores, named locations, and other information that can be used for text mining operations.

The OpenAmplify returns key-value pairs in an XML string by default, but it can also be in JSON, CSV, or RDF format. From a Ruby client’s point of view, we want it in Hash. You can choose to use an XML library like Nokogiri but in my opinion, working with a Hash fits nicely with Ruby.

Anyway, back to the problem. I have an instance variable that holds the data. One approach is to give clients access to the instance variable.

class Response
  attr_reader :data

  def initialize
    @data = {}
  end
end

data = response.data
topics = data[‘Topics’]

One major issue with this approach is you’re exposing the internals of your class. What if you decided to rename the variable into ‘@results_in_hash_form’? Then, all programs that uses your code will break. Worse, you will be limited from enhancing the behavior of your class like lazy loading of the data. You can wrap the access to your data inside a method but that still presents the problem of exposing the internals of your class. Also, that’s an unnecessary extra line of code :)

My suggestion is to make ‘Response’ behave like a Hash so we can do these:

topics = response[‘Topics’]
response.has_key?(‘Topics’)

# And still have our own methods:
response.some_method_we_defined

So, how can we do this? The trick is to delegate the calls to the instance variable. One approach is to define the Hash methods you want to support:

class Response

  [‘[]’, ‘has_key?’, ‘fetch’, ‘empty?’, ‘keys’].each do |method_name|
    class_eval <<-EOS
      def #{method}(*args)
         @data.send(‘#{method_name}’, *args)
      end
    EOS
  end

end

The code above is a shortcut to writing every method by hand. If you want to support all Hash methods, that would be a lot of typing.

A better approach is to just take advantage of Ruby’s ‘method_missing’ which is called every time an undefined method is called.

class Response

  def method_missing(name, *args, &amp;block)
    @data.send(name, *args, &amp;block)
  end

end

Of course, how your ‘method_missing’ will look like depends on your requirements. In our simple case, we can simply delegate to @data.

This approach is called a “Dynamic Proxy” from the book Metaprogramming Ruby by Paolo Perrota. If you want to take your Ruby skills to the next level, I highly recommend this book.

Written by Greg Moreno

June 9th, 2010 at 7:10 pm

Posted in Geekiness

Tagged with ,

Ruby 101: Hash initialization gotcha

with 2 comments

I have a code that counts how many times a word occurs – a perfect fit for Hash.

def word_counts(words)
  counts = Hash.new(0)
  words.each do |word|
    counts[word] += 1
  end
end

categories = {
  :a => word_counts(‘some text’)
  :b => word_counts(‘another set of text’)
}

Somewhere, I use the hash returned by the word_counts method to do some calculation.

def score(word_scores, words)
  words.each do |word|
    v = word_scores[word]
    v = 0.1 if v.nil?

    score += Math.log( v / some_value )
  end
end

categories.each do |category, word_counts|
  score(word_counts, %w{some random text})
end

When I run the score, I always get an ‘Infinity’. After some debugging, the problem is this piece of code:

v = word_scores[word]
v = 0.1 if v.nil?

‘word_scores’ returns 0 if ‘word’ doesn’t exist; not nil which is the default behavior. Later, I realized I initialized it via Hash.new(0) which makes 0 the default value. In fact, it is not even necessary to check for nil or 0. All we want is to retrieve the value referenced by the key, and if the key does not exist, give me 0.1.

v = word_counts.fetch word, 0.1

By the way, the code is from a simple exercise on Naive Bayes algorithm to classify text.

Written by Greg Moreno

May 11th, 2010 at 5:32 pm

Posted in Geekiness

Tagged with ,

Ruby 101: How to filter an Array using proc

with one comment

Over at the PhRUG, a Ruby developer community based in the Philippines, we conduct code review sessions via our mailing list. A code is posted and members share alternative implementations. So far, it’s been effective and newbies and veterans alike are learning new things in Ruby. Here’s a recent code that filters an array based on several conditions.

matches = []
(0..9).each do |i|
 if (i > 5) && (i % 2).zero? &&  (i % 3).zero?
   matches << i
 end
end

The first improvement made by Bong is to use ‘select’.

 matches = (0..9).select {|i| (i > 5) && (i % 2).zero? &&  (i % 3).zero?}
  

What if you are going to include another condition? Of course, you can argue to simply hard code the new condition but that wouldn’t be fun :) The solution by Tim and Neil is to use procs which I’m sure would make Matz very happy.

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

  elements = (1..10).to_a

  matches = elements.select do |i|
    conditions.all? { |c| c[i] }
  end

  puts matches.join(',')

We can even add this filtering to the Array class, just in case we need to use this across our application.

  class Array
    def matches(*conditions)
      select do |i|
        conditions.all? { |c| c[i] }
      end
    end
  end

  matches = elements.matches(*conditions)
  puts matches.join(',')

  matches = elements.matches( proc{ |i| i > 5 })
  puts matches.join(',')

  matches = elements.matches( proc{ |i| i > 5 }, proc{ |i| (i%3).zero? })
  puts matches.join(',')

Written by Greg Moreno

April 26th, 2010 at 4:54 pm

Posted in Geekiness

Tagged with ,

Ruby 101: How to add methods to a Ruby class

without comments

Let’s add a method that checks whether an Array has many elements.

    a = [1,2,3]
    a.many?  # NoMethodError: undefined method `many?'

Let’s fix this by adding a new method to the class Array.

    class Array
      def many?
        size > 1
      end
    end

    a = [1,2,3]
    a.many?   # true

    b = [1]
    b.many? # false

    c = []
    b.many? # false


Let’s implement Rails’ fancy ‘days.ago’ method:

    5.days.ago # NoMethodError: undefined method `days' for 3:Fixnum

Now, add the days and ago methods to Fixnum.

    class Fixnum
      def days
         self * 60 * 60 * 24   # we store seconds in a day
      end

      def ago
        Time.now - self
      end
    end

Written by Greg Moreno

April 24th, 2010 at 6:58 pm

Posted in Geekiness

Tagged with ,