Caleb Tennis wrote:
> I have some methods in a class that look like this:
>
>   def h_coil(chan)
>     raise NoDataError if @h_coils[chan].nil?
>     @h_coils[chan]
>   end
>
>   def i_coil(chan)
>     raise NoDataError if @i_coils[chan].nil?
>     @i_coils[chan]
>   end
>
> and so on and so forth...
>
> I've been refactoring a bit to cut down on the redunancy in the code,
> and I'm wondering your thoughts on the best way of doing this,
> considering that all methods have the same "signature".
>
> Is define_method the smartest way?

You are recreating functionality that's already there (assuming coils
collections are arrays or hashes):

>> h={1=>2}
=> {1=>2}
>> h.fetch 1
=> 2
>> h.fetch 2
IndexError: key not found
        from (irb):7:in `fetch'
        from (irb):7
        from :0
>> a=[1]
=> [1]
>> a.fetch 0
=> 1
>> a.fetch 1
IndexError: index 1 out of array
        from (irb):16:in `fetch'
        from (irb):16
        from :0


IMHO it's not worth while to use meta programming in this case but YMMV.
*If* you use meta programming then I'd probably use a way that makes sure
the member is there, properly initialized and the getter defined.  I'd
probably create a module whose initialize will create member variables and
which when included will define the create_coil for the including class...

> # pseudo code off the top of my head, probably has errors:
>
> def create_coil_method(name)
>   define_method(name) do |chan|
>     iv = ("@" + name.to_s + "s").to_sym
>     val = instance_variable_get(iv)
>     raise NoDataError if val.nil?
>     val[chan]
>   end
> end
>
> create_coil_method(:h_coil)
> create_coil_method(:i_coil)
> ..

Of course you can combine both techniques and save the exception throwing
part.

Kind regards

    robert