S
Sam Stephenson
There's a few trivial but useful "extensions" to Ruby's standard
library that I find myself using in most of my projects. I'll share a
couple, and I'd really love to see what you're using, too.
Array folding is a functional idiom in which each item is evaluated in
some way and its result accumulated, returning the final value of the
accumulator. It's simple in Ruby:
| class Array
| def foldl(accum, &block)
| each {|value| accum = yield(accum, value)}
| return accum
| end
| def foldr(accum, &block)
| reverse.foldl(accum, &block)
| end
| alias fold :foldl
| end
The canonical example is summing values:
| r = (1..100).to_a
| p r.foldl(0) {|a,v| a += v}
=> 5050
| p r.foldr(5050) {|a,v| a -= v}
=> 0
A more interesting and useful application involves boolean logic. For
example, the following snippet ensures all arguments passed to
FooSet#new are of type Foo:
| class Foo; end
| class FooSet
| def initialize(*values)
| raise TypeError unless
| values.fold(true) {|a,v| a and v.is_a? Foo}
| # ...
| end
| end
Another quickie I'm fond of assists in what Josh Bloch calls
``defensive copying'' in his book ``Effective Java.'' The idea is
that you should always return copies of mutable instance variables if
you aren't prepared to have users of your class modify those
variables.
For instance, if I have a class which contains an array, and I want to
make that array accessible from outside but not modifiable,
attr_reader won't be sufficient -- I need to call Array#dup and return
that. Once again, it's trivial in Ruby to define a helper to do just
that:
| class Class
| def attr_defender(*symbols)
| symbols.each do |symbol|
| class_eval "def #{symbol}; @#{symbol}.dup; end"
| end
| end
| end
Here's how I might use it:
| class Container
| def initialize(*values)
| @values = values
| @length = values.length
| end
| attr_defender :values
| attr_reader :length
| end
Container#values returns a new object each time:
| c = Container.new('foo', 'bar', 'baz')
| p c.values.__id__
=> 402800548
| p c.values.__id__
=> 402800512
So now I can be lazy and do whatever I want with the copy.
Please share your quickies!
Sam
library that I find myself using in most of my projects. I'll share a
couple, and I'd really love to see what you're using, too.
Array folding is a functional idiom in which each item is evaluated in
some way and its result accumulated, returning the final value of the
accumulator. It's simple in Ruby:
| class Array
| def foldl(accum, &block)
| each {|value| accum = yield(accum, value)}
| return accum
| end
| def foldr(accum, &block)
| reverse.foldl(accum, &block)
| end
| alias fold :foldl
| end
The canonical example is summing values:
| r = (1..100).to_a
| p r.foldl(0) {|a,v| a += v}
=> 5050
| p r.foldr(5050) {|a,v| a -= v}
=> 0
A more interesting and useful application involves boolean logic. For
example, the following snippet ensures all arguments passed to
FooSet#new are of type Foo:
| class Foo; end
| class FooSet
| def initialize(*values)
| raise TypeError unless
| values.fold(true) {|a,v| a and v.is_a? Foo}
| # ...
| end
| end
Another quickie I'm fond of assists in what Josh Bloch calls
``defensive copying'' in his book ``Effective Java.'' The idea is
that you should always return copies of mutable instance variables if
you aren't prepared to have users of your class modify those
variables.
For instance, if I have a class which contains an array, and I want to
make that array accessible from outside but not modifiable,
attr_reader won't be sufficient -- I need to call Array#dup and return
that. Once again, it's trivial in Ruby to define a helper to do just
that:
| class Class
| def attr_defender(*symbols)
| symbols.each do |symbol|
| class_eval "def #{symbol}; @#{symbol}.dup; end"
| end
| end
| end
Here's how I might use it:
| class Container
| def initialize(*values)
| @values = values
| @length = values.length
| end
| attr_defender :values
| attr_reader :length
| end
Container#values returns a new object each time:
| c = Container.new('foo', 'bar', 'baz')
| p c.values.__id__
=> 402800548
| p c.values.__id__
=> 402800512
So now I can be lazy and do whatever I want with the copy.
Please share your quickies!
Sam