Our Daily Method #13: Object#mymethods

Geplaatst door Michiel de Mare do, 21 feb 2008 08:00:00 GMT

I always have an irb or rails console session open, and I love methods to see what an object is capable of, but it certainly returns an exceptional amount of unsorted crap, especially in Rails.

Therefore, mymethods:


class Object
  def mymethods
    (methods - Object.instance_methods).sort
  end
end

(1..2).methods.size # => 150
(1..2).mymethods.size # => 46

Recommend Michiel de Mare

Geplaatst in , ,  | 1 reactie

2008.rubyenrails.nl

Geplaatst door Michiel de Mare wo, 20 feb 2008 11:12:00 GMT

On June 5th the third edition of the RubyEnRails conference will take place in Amsterdam. Last year, about a third of the sessions were in English. It’s not yet possible to register, but we’re looking for speakers.

If you’re interested in giving a presentation about a cool Rails or Ruby subject, let us know.

Some suggestions:
  • Ruby 1.9
  • Experiences with Rails deployment
  • Build a Facebook application in 45 minutes with Rails
  • Tools for Rails – IDEs, editors, debuggers, etc.

Use the rubyenrails2008(ape)rubyenrails.nl email-address to apply.

Geplaatst in , ,  | Tags  | geen reacties

Our Daily Method #12: Comparable#at_least

Geplaatst door Michiel de Mare wo, 20 feb 2008 08:00:00 GMT

It took me a while before I discovered the accepted Ruby idiom to find the bigger of two values. I expected a method in Kernel or perhaps in Comparable. Instead, the Ruby Way is to create an array and ask the maximum value in the array:


[x,y].max
Well, it’s certainly short, but I don’t like it, for three reasons:
  • You create an array to compare two integers? That has to be inefficient, right? Of course, worrying about efficiency is not The Ruby Way.
  • I don’t like the name. When I say max it feels as if I’m declaring an upper bound, a maximum, when in fact, I’m declaring a lower bound, a minimum.
  • By listing both values in the array, you’re placing them on equal footing, when often that’s not really the case. Often it’s more an afterthought: you’re saying: I want value foo (and by the way, it must be at least 7.25).
Hence, at_most and at_least:

total_time / total_tries.at_least(1)

Implementation too trivial to list.

Recommend Michiel de Mare

Geplaatst in , ,  | geen reacties

Our Daily Method #11: Hash#inv_multi

Geplaatst door Michiel de Mare di, 19 feb 2008 08:00:00 GMT

Hash has an invert-method, but it often happens that you’re dealing with a hash with arrays as values. Naturally, you don’t want arrays as keys – you want every element in the array to turn into a key, with an array of all original keys with that element as the value.

Simple example


{1 => [3,4]}.inv_multi
# => {3=>[1], 4=>[1]}

Complex example


{1 => [3,4,5,6], 2 => [3,4], 4 => 11}.inv_multi
# => {5=>[1], 11=>[4], 6=>[1], 3=>[1, 2], 4=>[1, 2]}
The method itself:

class Hash
  def inv_multi
    # there's inject! again. daily method #5
    inject!({}) do |h,(k,v)|  # Is this obvious? If not, say so!
      # this lambda binds h and k.
      l = lambda {|x| (h[x] ||= []) << k}
      if Array === v
        v.each(&l)
      else # value doesn't have to be an array
        l[v]
      end
    end
  end
end

Recommend Michiel de Mare

Geplaatst in , ,  | geen reacties

Our Daily Method #10: Object#r[rs][ds]s

Geplaatst door Michiel de Mare ma, 18 feb 2008 08:00:00 GMT

Ruby 1.9 has Object#tap. Danny introduced Object#with a long time ago. Then there’s Object#instance_eval.

Do these methods have anything in common, except for the inscrutability of their names?

It turns out that they do. These methods fall in the family of methods that:
  1. Are defined for any Object
  2. Take a block and always execute it once
  3. Don’t do anything else

So it may seem amazing that there are as much as three methods in this category. Actually, there’s even a fourth!

You see, even within these strict specs there are two decisions that we have to take.
  1. What do we return? The object itself? Or the result of the block?
  2. Within the block, what is self? Is it the object? Or is it unchanged (so we need to pass on the object as an argument)?
How do the methods we referred to earlier stack up?
  • tap: returns result, same self in block
  • with: return self, same self in block
  • instance_eval: returns result, different self in block.
And the Missing Method:
  • switch: returns self, different self in block.

Let’s see these methods in action!

Lees verder...

Geplaatst in , ,  | geen reacties

Our Daily Method #9: String#+@

Geplaatst door Michiel de Mare vr, 15 feb 2008 08:00:00 GMT

It’s Friday so we’ll keep it short.


[String,Symbol].each{|c|c.class_eval {alias +@ to_sym}}

Is it a Symbol? Is it a String? Who gives a damn!


hash[+key]

Recommend Michiel de Mare

Geplaatst in , ,  | geen reacties

Our Daily Method #8: Object.alias_class_method

Geplaatst door Remco van 't Veer do, 14 feb 2008 08:00:00 GMT

In an earlier daily method an alias is created for a class method. This is a bit tricky since the Module#alias_method method only operates in instance methodes. Fortunately a class is an instance of Class so we can use that instance as a context to use alias_method.

To extend an object instance we use the class<< notation. This adds a singleton/eigen/virtual/meta-class to the given instance which you can use to add methodes. Inside a class definition the self object points to the instance of the class begin defined. This allows us the do the following:


class Foo
  class << self
    alias_method :neu, :new
  end
end

This Foo class can now be instanciated using neu (note, new is just a class method). But this class<< stuff inside a class is a bit messy. I prefer using the following extension to Object:


class Object
  def self.alias_class_method(new_name, old_name)
    meta = class << self; self; end
    meta.send :alias_method, new_name, old_name
  end
end

Now we can write:


class Foo
  alias_class_method :neu, :new
end

For more information about eigenclasses see the discussion Nutter and Lam had on Ruby-core.

Geplaatst in , ,  | geen reacties

Our Daily Method #7: Enumerable#mjoin

Geplaatst door Michiel de Mare wo, 13 feb 2008 08:00:00 GMT

You all know flatten. Flatten takes an array and removes all structure from it. But sometimes you’ve got an array of arrays of arrays, and want to turn it into an array of arrays. What we need is a flatten-light: mjoin

module Enumerable
  def mjoin
    inject!([]) {|memo,x| a.each {|x| memo << x}}
  end
end
(read more about inject!).

When do you use this? Whenever you want to use map but you don’t always want to return exactly one value, and some or all of the values are arrays (which means you can’t use flatten).

Does that sound exceedlingly rare? In fact, it is a very common structure. A table is an array of arrays, and a join is an operation which returns zero or more results per row. And this also explains the name! (join, of course, is already taken – mjoin was inspired by this article).

I plan to talk more about using the table datastructure in the near future.

Recommend Michiel de Mare

Geplaatst in , ,  | geen reacties

Our Daily Method #6: AR.find(..).each

Geplaatst door Remco van 't Veer di, 12 feb 2008 08:00:00 GMT

AR.find(..).each

Working with ActiveRecord it often bothers me I need to write each after doing a find-all. I can give find a block but is just ignored without any warning.

So today no new method but the removal of a method!


class ActiveRecord::Base
  def self.find_with_block_sensitivity(*args)
    r = find_without_block_sensitivity(*args)
    [r].flatten.each {|v| yield v} if block_given?
    r
  end

  class << self
    alias_method :find_without_block_sensitivity, :find
    alias_method :find, :find_with_block_sensitivity
  end
end

Now, instead of:


Article.find(:all).each {|article| puts article.title}

we can write:


Article.find(:all) {|article| puts article.title}

Look ma! No each! Also works for single object results.

Geplaatst in , , ,  | geen reacties

Ruby And The Seven Virtues

Geplaatst door Michiel de Mare ma, 11 feb 2008 08:52:00 GMT

This is a Dutch blog, and therefore we love to quote Dutch computer scientists:

Elegance is not a dispensable luxury but a factor that decides between success and failure.

Edsgar Dijkstra

Seven pieces of Java code and the alternative in Ruby:

1. Short circuit with nil

Java


if(foo != null) { 
  bar(foo); 
} else { 
  bar(""); 
}

Ruby


bar(foo || "")

Recommend Michiel de Mare

Lees verder...

Geplaatst in ,  | 1 reactie

Oudere artikelen: 1 2 3