Forum: Ruby Best DRY way to write bang versions of methods?

Posted by Joel Pearson (virtuoso)
on 2013-02-14 13:06
I've been wondering about the best way to quickly create a "bang"
version of a method (specifically one which overwrites self). Is there a
better DRY approach than the below?
I guess that there's probably a way to input a list of methods as
symbols and output bang versions of each as new methods, but at the
moment I'm more interested in the wording of the bang method itself.

This is the best I can come up with (in pseudo-code):

def test( arg1, arg2, arg3=true )
  #Do stuff with the args that returns a value
end

def test!(*p)
  replace test(*p)
end
Posted by Edoardo Rossi (Guest)
on 2013-02-14 13:44
(Received via mailing list)
On Thu, Feb 14, 2013 at 1:06 PM, Joel Pearson <lists@ruby-forum.com> 
wrote:
>   #Do stuff with the args that returns a value
> end
>
> def test!(*p)
>   replace test(*p)
> end
>
> --
> Posted via http://www.ruby-forum.com/.
>

Hi...

IMHO sometimes this is useful:

def foo(something)
  dup.foo!(something)
end

def foo!(something)
  # do the work...
end

e.
Posted by Love U Ruby (my-ruby)
on 2013-02-14 13:49
Edoardo Rossi wrote in post #1096893:
> On Thu, Feb 14, 2013 at 1:06 PM, Joel Pearson <lists@ruby-forum.com>

@Rossi `+1` to you.

>>
>
> Hi...
>
> IMHO sometimes this is useful:
>
> def foo(something)
>   dup.foo!(something)
> end
>
> def foo!(something)
>   # do the work...
> end
>
> e.
Posted by Joel Pearson (virtuoso)
on 2013-02-14 13:49
That's an interesting way to do it. If I assume that any bang method I 
write in a given class would also have a non-bang method, then I could 
easily have a catch-all process define the methods for me when an 
instance is generated. Cool!
Posted by Hans Mackowiak (hanmac)
on 2013-02-14 14:02
something like that?

#when something is called, call dup.something!

def method_missing(meth,*args)
  if respond_to?("#{meth}!")
    dup.send("#{meth}!",*args)
  else
    super
  end
end

#when something! is called, call replace something

def method_missing(meth,*args)
  if /(\w+)!/ =~ meth
    replace send($!,*args)
  else
    super
  end
end



PS: you cant use both at the same place :P
Posted by Edoardo Rossi (Guest)
on 2013-02-14 14:02
(Received via mailing list)
On Thu, Feb 14, 2013 at 1:49 PM, Joel Pearson <lists@ruby-forum.com> 
wrote:
> That's an interesting way to do it. If I assume that any bang method I
> write in a given class would also have a non-bang method, then I could
> easily have a catch-all process define the methods for me when an
> instance is generated. Cool!
>
> --
> Posted via http://www.ruby-forum.com/.
>

Yup!
Hope this helps... happy hacking.
By the way... pay attention at all the consequences of 'dup'
See: http://ruby-doc.org/core-1.9.3/Object.html#method-i-dup

e.
Posted by Robert Klemme (robert_k78)
on 2013-02-14 18:04
(Received via mailing list)
On Thu, Feb 14, 2013 at 1:43 PM, Edoardo Rossi <edd.rossi@gmail.com> 
wrote:
> IMHO sometimes this is useful:
>
> def foo(something)
>   dup.foo!(something)
> end
>
> def foo!(something)
>   # do the work...
> end

There is one gotcha in this code: foo! will often return nil if
nothing is changed.  A better approach is

def foo(something)
  dup.tap {|copy| copy.foo!(something)}
end

Kind regards

robert
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.