How to DRY this?

Discussion in 'Ruby' started by Peter Szinek, Oct 4, 2006.

  1. Peter Szinek

    Peter Szinek Guest

    Hello,

    I have two very similar code snippets in two different methods, and I am
    absolutely sure there is some nice way to DRY them in Ruby... I am still
    a noob when comes to Ruby idioms so I'd appreciate some help ;-)

    ...
    while element.class != Hpricot::Doc do
    path.push element.name
    element = element.parent
    end
    ...

    and
    ...
    while element.class != Hpricot::Doc do
    path.push element
    element = element.parent
    end
    ...


    i.e. in the first snippet I am pushing element's names, and in the
    latter the elements themselves.

    Thanks,
    Peter
    http://www.rubyrailways.com
    Peter Szinek, Oct 4, 2006
    #1
    1. Advertising

  2. Peter Szinek

    Guest

    > Hello,
    >
    > I have two very similar code snippets in two different methods, and I am
    > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > a noob when comes to Ruby idioms so I'd appreciate some help ;-)
    >
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element.name
    > element = element.parent
    > end
    > ...
    >
    > and
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element
    > element = element.parent
    > end
    > ...


    Pull out the loop logic in to another method...

    def traverse_up(element)
    while element.class != Hpricot::Doc do
    yield(element)
    element = element.parent
    end
    end

    The two cases now become:
    traverse_up(element) {|e| path.push e,name}
    and
    traverse_up(element) {|e| path.push e}


    Additional comments:

    It may (or may not) make sense for the traverse_up method to be a member
    of element's class.

    You might like to provide an additional, optional argument, that can be
    used to control loop termination...

    def traverse_up(element, terminate_at = Hpricot::Doc)
    while !(terminate_at === element) do
    yield(element)
    element = element.parent
    end
    end

    (I've also changed the way that element's class is checked here - but
    classes of Hpricot::Doc will also match and terminate the loop).

    Cheers,
    Benj
    , Oct 4, 2006
    #2
    1. Advertising

  3. Peter Szinek

    Ken Bloom Guest

    On Wed, 04 Oct 2006 22:05:41 +0900, Peter Szinek wrote:

    > Hello,
    >
    > I have two very similar code snippets in two different methods, and I am
    > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > a noob when comes to Ruby idioms so I'd appreciate some help ;-)
    >
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element.name
    > element = element.parent
    > end
    > ...
    >
    > and
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element
    > element = element.parent
    > end
    > ...
    >
    >
    > i.e. in the first snippet I am pushing element's names, and in the
    > latter the elements themselves.


    Option 1: don't. It's a very small snippet of code.
    Option 2:

    def dopush
    while element.class!= Hpricot::Doc do
    path.push(yield(element))
    element = element.parent
    end
    end

    The first snippet becomes

    dopush {|e| e.name}

    The second snippet becomes

    dopush {|e| e}

    --
    Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
    Department of Computer Science. Illinois Institute of Technology.
    http://www.iit.edu/~kbloom1/
    I've added a signing subkey to my GPG key. Please update your keyring.
    Ken Bloom, Oct 4, 2006
    #3
  4. Peter Szinek

    Jean Helou Guest

    On 10/4/06, Peter Szinek <> wrote:
    > Hello,
    >
    > I have two very similar code snippets in two different methods, and I am
    > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > a noob when comes to Ruby idioms so I'd appreciate some help ;-)
    >
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element.name
    > element = element.parent
    > end
    > ...
    >
    > and
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element
    > element = element.parent
    > end
    > ...
    >
    >
    > i.e. in the first snippet I am pushing element's names, and in the
    > latter the elements themselves.
    >
    > Thanks,
    > Peter
    > http://www.rubyrailways.com
    >
    >


    interesting question ...

    def element_pusher(root_element, attribute=nil)
    while element.class!=Hpricot::Doc do
    pushie = attribute.nil? ? element : element.send(attribute.to_sym)
    path.push pushie
    element = element.parent
    end
    path
    end

    good ?

    I don't have time to mockup something to test it but
    path.push(attribute.nil? ? element : element.send(attribute.to_sym))
    might even work ...

    jean

    jean
    Jean Helou, Oct 4, 2006
    #4
  5. On Wed, Oct 04, 2006 at 10:05:41PM +0900, Peter Szinek wrote:
    > Hello,
    >
    > I have two very similar code snippets in two different methods, and I am
    > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > a noob when comes to Ruby idioms so I'd appreciate some help ;-)


    how about (untested)...

    def element_and_each_ancestor(element)
    while element.class != Hpricot::Doc do
    yield element
    element = element.parent
    end
    end

    >
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element.name
    > element = element.parent
    > end
    > ...


    element_and_each_ancestor(element) do |el|
    path.push el.name
    end

    > and
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element
    > element = element.parent
    > end
    > ...


    element_and_each_ancestor(element) do |el|
    path.push element
    end

    >
    > i.e. in the first snippet I am pushing element's names, and in the
    > latter the elements themselves.


    ta,
    dave

    --
    http://david.holroyd.me.uk/
    David Holroyd, Oct 4, 2006
    #5
  6. Peter Szinek

    Jean Helou Guest

    On 10/4/06, <> wrote:
    > > Hello,
    > >
    > > I have two very similar code snippets in two different methods, and I am
    > > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > > a noob when comes to Ruby idioms so I'd appreciate some help ;-)
    > >
    > > ...
    > > while element.class != Hpricot::Doc do
    > > path.push element.name
    > > element = element.parent
    > > end
    > > ...
    > >
    > > and
    > > ...
    > > while element.class != Hpricot::Doc do
    > > path.push element
    > > element = element.parent
    > > end
    > > ...

    >
    > Pull out the loop logic in to another method...
    >
    > def traverse_up(element)
    > while element.class != Hpricot::Doc do
    > yield(element)
    > element = element.parent
    > end
    > end
    >
    > The two cases now become:
    > traverse_up(element) {|e| path.push e,name}
    > and
    > traverse_up(element) {|e| path.push e}
    >
    >
    > Additional comments:
    >
    > It may (or may not) make sense for the traverse_up method to be a member
    > of element's class.
    >
    > You might like to provide an additional, optional argument, that can be
    > used to control loop termination...
    >
    > def traverse_up(element, terminate_at = Hpricot::Doc)
    > while !(terminate_at === element) do
    > yield(element)
    > element = element.parent
    > end
    > end
    >
    > (I've also changed the way that element's class is checked here - but
    > classes of Hpricot::Doc will also match and terminate the loop).
    >
    > Cheers,
    > Benj


    great !! I like yours better, now I wish I hadn't tried :)

    jean
    Jean Helou, Oct 4, 2006
    #6
  7. Peter Szinek

    Guest

    > jean wrote
    > great !! I like yours better, now I wish I hadn't tried :)


    Well, thanks, but don't let that put you off (or I'll wish I hadn't).

    It's quite interestesting to look at the different approaches. The four
    suggestions have three different approaches, and two of the approaches
    are _very_ similar (utilisation of yield).
    , Oct 4, 2006
    #7
  8. Peter Szinek wrote:
    > Hello,
    >
    > I have two very similar code snippets in two different methods, and I am
    > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > a noob when comes to Ruby idioms so I'd appreciate some help ;-)
    >
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element.name
    > element = element.parent
    > end
    > ...
    >
    > and
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element
    > element = element.parent
    > end
    > ...
    >
    >
    > i.e. in the first snippet I am pushing element's names, and in the
    > latter the elements themselves.
    >
    > Thanks,
    > Peter
    > http://www.rubyrailways.com
    >
    >


    A couple of obvious (to me, anyhow) questions:

    1. You are "pushing" elements and element names. Are you "pulling" or
    "popping" them somewhere else?

    2. If you just pushed the element name, could you retrieve the element
    from its name?

    3. Is there some reason you need two loops up the chain? Could you do

    while element.class != Hpricot::Doc do
    path.push [element.name => element]
    element = element.parent
    end

    or something similar?
    M. Edward (Ed) Borasky, Oct 4, 2006
    #8
  9. Peter Szinek wrote:
    > Hello,
    >
    > I have two very similar code snippets in two different methods, and I am
    > absolutely sure there is some nice way to DRY them in Ruby... I am still
    > a noob when comes to Ruby idioms so I'd appreciate some help ;-)


    If you had this:

    def ancestors element
    ...
    while element.class != Hpricot::Doc do
    path.push element
    element = element.parent
    end
    path
    end

    > ...
    > while element.class != Hpricot::Doc do
    > path.push element.name
    > element = element.parent
    > end
    > ...


    would become: ancestors(element).map{|a|a.name}

    > and
    > ...
    > while element.class != Hpricot::Doc do
    > path.push element
    > element = element.parent
    > end
    > ...


    would become: ancestors(element)

    > i.e. in the first snippet I am pushing element's names, and in the
    > latter the elements themselves.
    >
    > Thanks,
    > Peter


    cheers

    Simon
    Simon Kröger, Oct 4, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. yoda
    Replies:
    2
    Views:
    270
  2. Todd
    Replies:
    0
    Views:
    309
  3. R. Bernstein

    How do I DRY the following code?

    R. Bernstein, Dec 30, 2008, in forum: Python
    Replies:
    4
    Views:
    211
    R. Bernstein
    Dec 30, 2008
  4. Marc Aymerich
    Replies:
    9
    Views:
    271
    Marc Aymerich
    Feb 3, 2011
  5. egbert

    DRY and class variables

    egbert, Sep 8, 2011, in forum: Python
    Replies:
    0
    Views:
    119
    egbert
    Sep 8, 2011
Loading...

Share This Page