-
26
JUN
2008Summoning Error Classes As Needed
In the past, I've written a lot of code like this:
class SomeThing class SomeError < RuntimeError; end class AnotherError < RuntimeError; end class YetAnotherError < RuntimeError; end # some methods that can raise the above errors... end
I have a new strategy I've been using for code like this and it has really been working out well. Here is how I do the same thing today:
class SmarterThing def self.const_missing(error_name) # :nodoc: if error_name.to_s =~ /Error\z/ const_set(error_name, Class.new(RuntimeError)) else super end end # error raising methods here... end
Let's discuss how this works. The
const_missing()
method is a hook in Ruby, much like the belovedmethod_missing()
. Note thatconst_missing()
is a class method though, instead of an instance method. When a constant is used and Ruby can't find it, a call to the hook will be triggered.In this version, I just check to see if the constant name ends in
Error
. If it does, I summon anException
subclass on the fly. Other calls to this hook are forwarded on to Ruby's default error raising implementation viasuper
. -
25
JUN
2008The One Method Config
I've used this technique a couple of times now for dirt-simple configurations. The idea is to provide a trivial way to read and write configuration values with just a single method. Let me show you what I mean:
module Configurable module_function def config(new_config = nil) if new_config.nil? @config ||= { } else config.merge!(new_config) end end end include Configurable config # => {} config :a => 1, :b => 2 config # => {:a=>1, :b=>2} config[:a] # => 1 config :a => -1, :c => 3 config # => {:a=>-1, :b=>2, :c=>3} config.clear config # => {}
There's no deep magic here, obviously. The method has two function: read and write for the configuration. Read is handled with what I like refer to as Ruby's "caching operator" (
||=
). The first time that line is triggered, it will cache an emptyHash
in the variable. Thereafter, the same call is just a cache hit to get the sameHash
back.