Using strings to drill down into objects

Folks,
      I'm writing a reporting application where I'm passing in an array of
method calls to populate a table

e.g.

    # lambda function to drill down object hierarchy
    drill_down = lambda do |obj, method_name|
                          o ||= obj
                          method_name.split('.').each {|m| o = o.send(m) if
o.respond_to?(m)}
                          o
                  end

methods = ['lookup1.code', 'lookup1.name']

report_value = drill_down.call(my_object_with_lookups, methods)

I'm sure there is a better "Ruby" way of doing this. Can someone offer
some advice?

Ross Dawson
Developer
Data Management & Reporting
Link Administration Services

Tel Direct: (03) 9633 8165
Tel Office: (03) 9633 8000

···

**********************************************************************
This communication may contain CONFIDENTIAL information and may also be the subject of LEGAL PROFESSIONAL PRIVILEGE and/or under copyright. If you are not an intended recipient, you MUST NOT keep, forward, copy, use, save or rely on this communication and any such action is unauthorised and prohibited. If you have received this communication in error, please reply to this e-mail to notify the sender of its incorrect delivery, and then delete both it and your reply. Thank you
**********************************************************************

Ross X Dawson wrote:

    # lambda function to drill down object hierarchy
    drill_down = lambda do |obj, method_name|
                          o ||= obj
                          method_name.split('.').each {|m| o = o.send(m) if
o.respond_to?(m)}
                          o
                  end

methods = ['lookup1.code', 'lookup1.name']

report_value = drill_down.call(my_object_with_lookups, methods)

I'm not sure what your intent is, but I guess this code won't work.

First, unless you define it before creating the lambda, "o" won't exist
in its binding, so you can't call o ||= obj. Second, you pass an array
of method names to your lambda as a second parameter, on which #split
isn't defined.

You could state instead:

method_name.each{|name| name.split{|part| ... } }

but then, "part" would take the value "lookup1", "code", "lookup1"
again, and "name" in that order. I highly doubt you want this.

However, AFAIK you're right that o.send(m, *args) is the way to call an
arbitrary named method on an object.

mortee

mortee wrote:

Ross X Dawson wrote:

    # lambda function to drill down object hierarchy
    drill_down = lambda do |obj, method_name|
                          o ||= obj
                          method_name.split('.').each {|m| o = o.send(m) if
o.respond_to?(m)}
                          o
                  end

method_name.each{|name| name.split{|part| ... } }

Sorry, that should read

method_name.each{|name| name.split('.').each{|part| ... } }

Are you sure about that?

brian@imagine:~$ irb
irb(main):001:0> x ||= 7
=> 7
irb(main):002:0> x
=> 7

···

On Oct 11, 8:32 am, mortee <mortee.li...@kavemalna.hu> wrote:

Ross X Dawson wrote:
> # lambda function to drill down object hierarchy
> drill_down = lambda do |obj, method_name|
> o ||= obj
> method_name.split('.').each {|m| o = o.send(m) if
> o.respond_to?(m)}
> o
> end

> methods = ['lookup1.code', 'lookup1.name']

> report_value = drill_down.call(my_object_with_lookups, methods)

I'm not sure what your intent is, but I guess this code won't work.

First, unless you define it before creating the lambda, "o" won't exist
in its binding, so you can't call o ||= obj.

Brian Adkins wrote:

Are you sure about that?

brian@imagine:~$ irb
irb(main):001:0> x ||= 7
=> 7
irb(main):002:0> x
=> 7

Sorry, you're right. I've never tried this actually on an undefined
local variable - and I guessed it would first try to evaluate x, which
would raise an exception. Thanks for pointing that out, I'm happy to
have learnt it (:

mortee