Ruby koans: Stuck on koan 267 - ruby

I've been looking online, but I can't seem to crack this poxy Proxy koan!
Here's what I have as my Proxy class:
class Proxy
def initialize(target_object)
#object = target_object
# ADD MORE CODE HERE
#messages = []
end
# WRITE CODE HERE
def method_missing(method_name, *args)
if #object.respond_to?(method_name)
#messages << method_name
#object.__send__(method_name, *args)
end
end
end
Further down the code a Proxy Television gets instantiated and has its .channel set to 10, thus:
tv = Proxy.new(Television.new)
tv.channel = 10
I'm NOW getting the following error:
expected 10 to equal [:channel=, :power, :channel]
I have so many questions, I'm not sure where to start:
WHY does the method_missing method return an Array?
WHY does the first element in the Array end with a '='?
WHY, when I add...
def channel
#object.channel
end
...to the proxy, does the koans command line throw one of those elaborately drawn 'mountains are again merely mountains' errors?
And finally, can I quit now?
Any advice on these questions would be appreciated.

Don't quit! :)
I guess the main thing that you have to understand is the method_missing method. Within the if statement, the last line takes the method that the target object (in this case an instance of Television) is calling and saves it in an array called #messages. When you do tv.channel = 10, your target object is calling the channel= method.
Since that's the last thing in the method, method_missing returns that array.
The first item in the array is simply the "channel=" method, which is a method naming convention in ruby.
As for the last question, it'll throw an error because you're calling the method from within itself, which in theory will go on forever.
I hope that makes some sense.

Related

Naive aspect implementation in ruby

I am trying to make a simplistic implementation of AOP in ruby. I was able to implement before and after advices, I got stuck with around advice.
This is the target class that is going to be advised:
class MyClass
def method
puts "running method"
end
end
This is the Aspect class to instantiate objects capable of making advices:
class Aspect
def advise(class_name, method, type, &block)
class_name.send(:alias_method, :proceed, :method)
class_name.send(:define_method, :method) do
case type
when :before
yield
proceed
when :after
proceed
yield
when :around
yield(proceed) # * proceed is the old version of the method
end
end
end
end
(*) Yield should execute the block around MyClass#proceed on the current object when method is invoked.
Creating the target and the aspect:
mc = MyClass.new
a = Aspect.new()
Invoking the method without advising it:
puts mc.method
Advising MyClass#method with around:
a.advise(MyClass, :method, :around) do |proceed|
puts "First"
proceed # this is not working *
puts "Last"
end
puts mc.method
(*) I am not being able to pass something to identify the call of proceed, that is the invocation of the old method without the advice.
The output should be:
First
running method
Last
In Ruby, a method call looks like this:
receiver.method(arguments)
Or, you can leave off the receiver if the receiver is self.
So, to call a method named proceed on some receiver, you would write
receiver.proceed
However, in your implementation, you don't keep track of what the receiver should be, so since you don't know the receiver, you simply cannot call the method.
Note that there are lots of other problems with your approach as well. For example, if you advise multiple methods, you will alias them all to the same method, overwriting each other.
I believe there are two things going wrong here.
This section of code
when :around
yield(proceed) # * proceed is the old version of the method
end
Calls the block given to advise providing the output of the proceed method as an argument.
So your output probably looks something like:
running method
First
Last
This block
a.advise(MyClass, :method, :around) do |proceed|
puts "First"
proceed # this is not working *
puts "Last"
end
Just evaluates the argument given as proceed. If a method is given it does not call it. So taking problem 1 into consideration in your case the original definition of method (aliased to proceed) returns nil (output of return) which will be passed as the value to the proceed argument in the block when yielded. the block ends up evaluating to something like
puts "First"
nil
puts "Last"
mc.method is called.
To address the second part, you may want to consider using send. Because the inner workings of your aspect may not be known to your code that calls it. It may change over time, so what ever calls Aspect.advise shouldn't make assumptions that the original method will still be accessible. Instead, it should take an argument (the new method name) and send it to the object. Making the block passed to advise:
a.advise(MyClass, :method, :around) do |aliased_method_name|
puts "First"
send(aliased_method_name)
puts "Last"
end
And adjusting the around item added to your class when advise is called to the following:
when :around
yield(:proceed) # * proceed is the old version of the method
end
If you do both of these things, your around section will calls the provided block, using the symbol for the new alias for the overridden method.
N.B.: This approach won't work for methods that require any arguments.
This is what I did. In the definition of Aspect#advise now I use a Proc, like this:
when :around
yield Proc.new { proceed }
end
And when calling the method to advise MyClass#method with :around parameter I use this:
a.advise(MyClass, :method, :around) do |original|
puts "First"
original.call
puts "Last"
end
I got:
First
running method
Last
Here's the fixed version that will work for arguments, and avoid clobbering.
class Aspect
##count = 0
def self.advise(class_name, method, type=nil, &block)
old_method = :"__aspect_#{method}_#{##count += 1}"
class_name.send(:alias_method, old_method, method)
class_name.send(:define_method, method) do |*args, &callblock|
case type
when :before
yield
send(old_method, *args, &callblock)
when :after
send(old_method, *args, &callblock)
yield
when :around, nil
yield lambda {
send(old_method, *args, &callblock)
}
end
end
end
end
class Foo
def foo(what)
puts "Hello, #{what}!"
end
end
Aspect.advise(Foo, :foo) do |y|
puts "before around"
y.yield
puts "after around"
end
Aspect.advise(Foo, :foo, :before) do
puts "before"
end
Aspect.advise(Foo, :foo, :after) do
puts "after"
end
Foo.new.foo("world")
# before
# before around
# Hello, world!
# after around
# after

What is being called in this Ruby method?

I need some help understanding what's going on here. It's a block inside of a method. Basically I get everything here except the call in the if statement wasABlock_nowAProc.call. This is not defined here, so what is it calling?
class Array
def eachEven(&wasABlock_nowAProc)
isEven = true # We start with "true" because arrays start with 0, which is even.
self.each do |object|
if isEven
wasABlock_nowAProc.call object
end
isEven = (not isEven) # Toggle from even to odd, or odd to even.
end
end
end
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
puts oddBall.to_s+' is NOT an even number!'
end
def eachEven(&wasABlock_nowAProc) declares that the eachEven method accepts a block, which is the do ... end stuff from your two examples. It is then accessible within the method as a .callable Proc/Lambda object with the name wasABlock_nowAProc.
wasABlock_nowAProc.call object basically invokes the attached block from within the method and passes it one argument, object.
Do a google search for "ruby block to proc" and any of the first results should give you a thorough explanation.
Basically, when you define a method parameter with an & prefix (as in def eachEven(&wasABlock_nowAProc)), it tells Ruby that this method is expecting to receive a Proc object as an argument. In the method body you can then do stuff with Proc, such as use the #call method to run it or pass it on to another method.
Now, it's rare for Ruby programmer to manually create Proc objects. It's much more common to just use a block (less typing, easier to read, etc). If you try to pass a block to method that requires a Proc, well, Ruby handles that just fine. It magically converts the block to a Proc and uses that.
In this particular example, the only reason I can see to define the &wasABlock_nowAProc parameter is to tell Ruby to raise an error if the method is called with a block. You could remove the parameter and replace the #call line with yield to achieve the same functionality.

How and why does this dynamic method definition work?

How does following code works and, more importantly, why does it work that way?
class Example
def one
def one
#value = 99
end
puts "Expensive Call"
#value = 99 # assume its expensive call
end
end
ex = Example.new
puts ex.one # => "Expensive Call"; 99
puts ex.one # => 99
Here, on first call to method one, Ruby executes the outer one method, but on successive calls, it executes only the inner one method, bypassing the outer one method totally.
I want to know how does it happen and why does it happen so.
How It Works
Ruby allows you to redefine classes at run-time, because class and def are actually executable code. In your example, the code does the following:
Defines an Example#one method that will (re)define the Example#one method when the instance method is called.
For practical purposes, the inner def will not be executed until the outer instance method is called. (Hair-splitters may legitimately argue this definition, but that gets into details of the parser/interpreter that just don't matter for the purposes of this discussion.)
You define an instance of Example named "ex."
You invoke the instance method on ex, which defines a new method with the same name.
When you call the instance method again, the new method is used instead of the old one.
Why It Works
Basically, the last definition of a method replaces any earlier definitions in that namespace, but the methods are actually new objects. You can see this in action as follows:
def my_method
puts 'Old Method'
puts self.method(:my_method).object_id
def my_method
puts 'New Method'
puts self.method(:my_method).object_id
end
end
If you run this in an irb or pry session, you can see the method redefined at run-time:
> my_method; puts; my_method
Old Method
8998420
New Method
8998360
As you can see by the different object IDs, even though the methods have the same name and are attached to the same object (generally main at the console), they are actually different method objects. However, since the methods were defined with the same name, only the most recent definition is found when the instance does a method lookup.
When you execute it the first time, it redefines itself in the class and then finishes. The second time, the method one has been overriden by itself to just #value = 99, so nothing is printed.
It's important to realize first that there is no such thing as inner or outer methods in Ruby.
You're defining a new method within a method—in this case, since the method being defined has the same name as an existing one, the new definition completely overwrites the original one.
What you have is equivalent to the (perhaps) more obvious:
class Example
def one
self.class.send(:define_method, :one) do
#value = 99
end
puts "Expensive Call"
#value = 99 # assume its expensive call
end
end
Here it's clearer that you're defining a method within the context of the class.

Ruby any way to catch messages before method_missing?

I understand that method_missing is something of a last resort when Ruby is processing messages. My understanding is that it goes up the Object hierarchy looking for a declared method matching the symbol, then back down looking for the lowest declared method_missing. This is much slower than a standard method call.
Is it possible to intercept sent messages before this point? I tried overriding send, and this works when the call to send is explicit, but not when it is implicit.
Not that I know of.
The most performant bet is usually to use method_missing to dynamically add the method being to a called to the class so that the overhead is only ever incurred once. From then on it calls the method like any other method.
Such as:
class Foo
def method_missing(name, str)
# log something out when we call method_missing so we know it only happens once
puts "Defining method named: #{name}"
# Define the new instance method
self.class.class_eval <<-CODE
def #{name}(arg1)
puts 'you passed in: ' + arg1.to_s
end
CODE
# Run the instance method we just created to return the value on this first run
send name, str
end
end
# See if it works
f = Foo.new
f.echo_string 'wtf'
f.echo_string 'hello'
f.echo_string 'yay!'
Which spits out this when run:
Defining method named: echo_string
you passed in: wtf
you passed in: hello
you passed in: yay!

Running code before every method in a class (Ruby)

I want to keep track of all the methods which have been run on an instance of a class I've built.
Currently I do:
class MyClass
def initialize
#completed = []
end
# Sends a welcome and information pack to the person who requested it
def one_of_many_methods
unless #completed.include? __method__
# Do methody things
#completed.push __method__
end
end
alias :another_name :one_of_many_methods
# Calling myClassInstance.another_name will insert
# :one_of_many_methods into #completed.
# Methody things should not now be done if .another_name
# or .one_of_many_methods is called.
end
But that gets very laborious when I have many methods in my class. I'm repeating myself! Is there a way to track the methods being called and to only allow them to be called once, like I'm doing above, but without having to repeat that block in every method?
Thanks!
(PS. I'm using Ruby 1.9)
This sounds like the perfect use case for a Proxy object. Fortunately, Ruby's dynamic nature makes implementing it quite easy:
class ExecuteOnceProxy
def initialize(obj)
#obj = obj
#completed = []
end
def method_missing(method, *args)
unless #completed.include?(method)
args.empty? ? #obj.send(method) : #obj.send(method, args)
#completed << method
end
end
end
Initialize your proxy simply by passing the original object in the constructor:
proxy = ExecuteOnceProxy.new(my_obj)
method_missing
There are frameworks that will do things like this but to answer your question, yes, there is an easy way.
And the easy way to only writing the code once is to front-end the entire class and implement method_missing. You can then uncover the real methods one at a time as each is discovered to be "missing" with an initial call.
I think there is new solution for your question.
Some times ago, Tobias Pfeiffer released after_do gem
This is not an answer because I do not have enough reputation to comment but please note that the answer #emboss posted has an error in it (missing star).
args.empty? ? #obj.send(method) : #obj.send(method, args)
should be
args.empty? ? #obj.send(method) : #obj.send(method, *args)
otherwise the method will receive a single arg: an array of the args you tried to pass it.

Resources