How to wrap methods with before and after in Ruby? - ruby

Is there a better way to achieve the following? It seems a little clunky to list the methods as symbols...
This code runs an init before and draw after for each of the 4 methods. The following code works, but is there a more readable or idiomatic way of doing it?
Class DrawMap
def draw_method_1
...
end
def draw_method_2
...
end
def draw_all
[:draw_method_1, :draw_method_2, :draw_method_3, :draw_method_4].each do |method|
init_draw
send method
#draw.draw
end
end
...
The Rails before and after filters would do the same thing, but this is not a Rails app.
Ruby 1.9.3

If you just want to make the code above a little cleaner, you could try this:
def draw_all
(1..4).each do |n|
init_draw
send "draw_method_#{n}"
#draw.draw
end
end
Otherwise, there is a pretty good SO question right here that would really help you out. It involves a little metaprogramming that basically redefines methods and wraps them with some additional code. In your case, you would wrap with init_draw and draw.

Related

Could someone help me understand what alias_method does in this code

I'm having trouble understanding the purpose of alias_method in this code
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
alias_method :configure_connection_without_interval, :configure_connection
define_method :configure_connection do
configure_connection_without_interval
execute('SET intervalstyle = iso_8601', 'SCHEMA')
end
end
What is the purpose of line 4 where they call configure_connection_without_interval -- doesn't that just call itself?
The code below works for me but I don't fully know what I'm doing and I'm worried it'll create bugs later
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
define_method :configure_connection do
execute('SET intervalstyle = iso_8601', 'SCHEMA')
end
end
alias_method operates immediately on that line before the method is redefined, preserving the old method under that given name.
That's a common Ruby technique to capture a version of a particular method and wrap it in another. When you're patching a class directly instead of subclassing you'll often be forced to do this.

Make an enumerable object lazy by default

I've started playing around with the Enumerable::Lazy functionality in Ruby 2.0 and it looks really useful.
I have an Enumerable collection that pages through a remote data source. Because of this, I would like it to be a "lazy" collection. However, I don't want to have to instruct every user of my class to call .lazy every time they want to use any of the Enumerable methods on it. Instead it would be nice to include a hypothetical LazyEnumerable module and have all the enumerable methods be lazy by default.
Does anyone have any ideas on a clean way to accomplish this? Thanks!
I had an idea and thought I would take a stab at this:
module LazyEnumerable
include Enumerable
def self.make_lazy(*methods)
methods.each do |method|
define_method method do |*args, &block|
lazy.public_send(method, *args, &block)
end
end
end
make_lazy *(Enumerable.public_instance_methods - [:lazy])
end
Curious to know if there is a more robust way to do this.

Could an object reinitialize itself before a method is executed?

Can I have an object reinitialize itself before a method is executed? I'm using Ruby and selenium to test a web app and I am trying to improve my page objects. for example
class Foo
def initialize
#stuff happens here
end
def NewMethod
self.initialize
#What happens here is what I really want to happen
end
end
Is this a good or bad idea? Or is there a better way to do this?
it's always possible to change the data contained in your object. you could ie put all the init-logic into an additional method and then call that from your custom methods.
in general, what you are trying to do does not sound like a good idea...
A remark in advance: methods are written in lower case. Please replace NewMethod with newmethod.
If you try Foo.newmethod you get an error.
What do you want to do? Do you want to define different possibilities to create an object?
What you could do:
class Foo
def initialize
end
def self.newmethod
me = self.new
#Some actions ...
me #Return the (modified?) object
end
end
p Foo.newmethod #->#<Foo:0xb77d58>
Time is using something like this. There is Time.new, Time.gm, Time.local...

In how many ways can methods be added to a ruby object?

When it comes to run time introspection and dynamic code generation I don't think ruby has any rivals except possibly for some lisp dialects. The other day I was doing some code exercise to explore ruby's dynamic facilities and I started to wonder about ways of adding methods to existing objects. Here are 3 ways I could think of:
obj = Object.new
# add a method directly
def obj.new_method
...
end
# add a method indirectly with the singleton class
class << obj
def new_method
...
end
end
# add a method by opening up the class
obj.class.class_eval do
def new_method
...
end
end
This is just the tip of the iceberg because I still haven't explored various combinations of instance_eval, module_eval and define_method. Is there an online/offline resource where I can find out more about such dynamic tricks?
Ruby Metaprogramming seems to be a good resource. (And, linked from there, The Book of Ruby.)
If obj has a superclass, you can add methods to obj from the superclass using define_method (API) as you mentioned. If you ever look at the Rails source code, you'll notice that they do this quite a bit.
Also while this isn't exactly what you're asking for, you can easily give the impression of creating an almost infinite number of methods dynamically by using method_missing:
def method_missing(name, *args)
string_name = name.to_s
return super unless string_name =~ /^expected_\w+/
# otherwise do something as if you have a method called expected_name
end
Adding that to your class will allow it to respond to any method call which looks like
#instance.expected_something
I like the book Metaprogramming Ruby which is published by the publishers of the pickaxe book.

When do you use method aliasing?

Do you use the alias method in order to add more ways to call methods (like length and size) or is there another use for it?
The alias_method call is also useful for re-implementing something but preserving the original version. There's also alias_method_chain from Rails which makes that kind of thing even easier.
alias_method also comes in handy when you have a number of behaviors that are initially identical but might diverge in the future, where you can at least rough them in to start.
def handle_default_situation
nil
end
%w[ poll push foo ].each do |type|
alias_method :"handle_#{type}_situation", :handle_default_situation
end
Yes.
It is often used to preserve a handle to existing methods before overriding them. (contrived example)
Given a class like this:
class Foo
def do_something
puts "something"
end
end
You could see code that adds new behaviour like so:
class Foo
def do_something_with_logging
puts "started doing something"
do_something_without_logging # call original implementation
puts "stopped doing something"
end
alias_method :do_something_without_logging, :do_something
alias_method :do_something, :do_something_with_logging
end
(this is exactly how alias_method_chain works)
However, for this use case it't often more appropriate to use inheritance and modules to your advantage.
Still, alias_method is a useful tool to have, if you absolutely need to redefine behaviour in an existing class (or if you wanted to implement something like alias_method_chain)

Resources