info | twitter | github
J-_-L | Writings on Ruby Programming
14.07.10
3 comments

Become a Proc Star!

One useful (and funny) feature of Ruby is the Symbol#to_proc method that lets you write concise code like this: %w|1 2 3 4|.map(&:to_i). Almost everyone who knows this feature loves it ;). However, the use cases are pretty limited, because in most cases you need to pass parameters!

Luckily, there is a pretty simple solution: symbols are not the only type that supports turning into a proc. Actually, every class is able to, it just needs to implement the to_proc method ;).

Array

Let’s do this with Array (as done here) – now we are able to pass parameters:

 1
2
3
4
5
6
7
8
9
10
11
12
# Uses the array as arguments for the object's send method

class Array
  def to_proc
    Proc.new{ |obj|
      obj.send *self
    }
  end
end

# usage
#  [1,2,3,4,5].map &[:to_s, 2]  # => ["1", "10", "11", "100", "101"]

Hash

What would be expedient uses for other classes? This is an idea for Hash:

Listing 2
/29/hash2proc.rb ruby
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# If the object is found as key in the hash, this runs its value as proc,
#  else it just returns the object.

class Hash
  def to_proc
    Proc.new{ |obj|
      if self.member? obj
        self[obj].to_proc.call obj
      else
        obj
      end
    }
  end
end

# usage
#  [1,2,3,4,5].map &{ 1 => :to_s,
#                     3 => [:to_s, 2] } # if you use Array#to_proc
#  => ["1", 2, "11", 4, 5]

Regexp

Why not also match Regexes?

 1
2
3
4
5
6
7
8
9
10
11
12
13
# Use this with string arrays

class Regexp
  def to_proc
    Proc.new{ |e|
      e.to_s[self]
    }
  end
end

# usage
#  %w|just another string array|.map    &/[jy]/  # => ["j", nil, nil, "y"]
#  %w|just another string array|.select &/[jy]/  # => ["just", "array"]

String

Reg Braithwaite once wrote a String#to_proc method that let you write stuff like [1,2,3,4,5].map &'*3+2'

Class

Finally, you could even add it to Class (as seen here) to simply initialize many objects:

 1
2
3
4
5
6
7
8
9
10
11
12
# Shortcut for initializing objects

class Class
  def to_proc
    Proc.new{ |*args|
      self.new *args
    }
  end
end

# usage
#  [[1,2],[3,5,6,7]].map &Set  # => [#<Set: {1, 2}>, #<Set: {5, 6, 7, 3}>]
Creative Commons License

Comments

14.07.10

anonym

To much magic or not?

14.07.10

J-_-L

Since the implementations are kept simple, I don't think, it's too much magic. Besides this, lots of rubyists are already familiar with Symbol#to_proc, so they might guess what Array#to_proc or Class#to_proc do.

17.07.10

Tim Connor

While I like the Array one, the Class#to_proc is downright sexy