MiniTest is crashing - ruby

I want to overwite send in Object, like so
class Object
##object_send = self.instance_method( :send )
def send *args
##object_send.bind( self ).call *args
end
end
or
class Object
def send *args
__send__ *args
end
end
or
class Object
alias_method :old_send, :send
def send *args
old_send *args
end
end
but all this options cause this error to appear
/opt/local/lib/ruby1.9/gems/1.9.1/gems/minitest-2.8.1/lib/minitest/unit.rb:871:in `block in process_args': unsupported argument type: Integer (ArgumentError)
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/minitest-2.8.1/lib/minitest/unit.rb:862:in `new'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/minitest-2.8.1/lib/minitest/unit.rb:862:in `process_args'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/minitest-2.8.1/lib/minitest/unit.rb:912:in `_run'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/minitest-2.8.1/lib/minitest/unit.rb:905:in `run'
from /opt/local/lib/ruby1.9/gems/1.9.1/gems/minitest-2.8.1/lib/minitest/unit.rb:685:in `block in autorun'
Is there anything I can do?
Update: Tried updating to 2.9.1 but that hasn't solved the problem

Without a MWE it is difficult for me to analyze your problem. Perhaps I found a first hint for your problem.
I tried to reconstruct the error, but without success:
class Object
alias_method :old_send, :send
def send *args
old_send *args
end
end
n = 5
puts n.send(:*, 2)
I get 10.
But with blocks I get a problem:
puts n.send(:times){ |i| p i } #-> #<Enumerator:0xb778a8>
With a little modification you can see what happens:
class Object
alias_method :old_send, :send
def send *args
puts "send called with #{args}" #--> [:times]
old_send *args
end
end
n = 5
n.send(:times){ |i| p i }
You get
send called with [:times]
The block is missing. You must add the proc-parameter to your redefinition:
class Object
alias_method :old_send, :send
def send *args, &proc
old_send *args, &proc
end
end
n = 5
n.send(:times){ |i| p i } #-> 1 2 3 4 5

Related

What's the technique for calling back methods across objects using "send" in Ruby?

I'm doing some programming that involves asynchronous callbacks in Ruby, and need to pass the callback method to another object (which may or may not be statically called). The issue I have is the syntax of the callback to the instance - I know it's fairly complicated, but I'm not sure I can make it simpler. Here's what I have:
class OBJA
def self.staticMethod(text, returnCall)
puts "objA.staticMethod: #{text}"
OBJB.send(returnCall, "Call back from objA.staticMethod")
end
def instanceMethod(text, returnCall)
puts "objA.instanceMethod: #{text}"
OBJB.send(returnCall, "Call back from objA.instanceMethod")
end
end
class OBJB
def starterMethod
OBJA.staticMethod("foo", :returnedCall)
OBJA.new.instanceMethod("bar", :returnedCall)
end
def returnedCall(text)
puts text
end
end
You can execute it by doing the following:
b = OBJB.new
b.starterMethod
Thanks!
The issue I have is the syntax of the callback to the instance
You have to call an instance method with an instance. And if you call a class method on a class, e.g. OBJB.send(...), the class method has to be defined.
class OBJA
def self.staticMethod(text, methName)
puts "objA.staticMethod: #{text}"
OBJB.send(methName, "Call back from objA.staticMethod")
end
def instanceMethod(text, methName)
puts "objA.instanceMethod: #{text}"
OBJB.new.send(methName, "Call back from objA.instanceMethod")
end
end
class OBJB
def starterMethod
OBJA.staticMethod("foo", :returnedCall)
OBJA.new.instanceMethod("bar", :returnedCall)
end
def self.returnedCall(text)
puts text
end
def returnedCall(text)
puts text
end
end
b = OBJB.new
b.starterMethod
--output:--
objA.staticMethod: foo
Call back from objA.staticMethod
objA.instanceMethod: bar
Call back from objA.instanceMethod
You could also pass blocks to the OBJA methods:
class OBJA
def self.staticMethod(text, &block)
puts "objA.staticMethod: #{text}"
block.call("Call back from objA.staticMethod")
end
def instanceMethod(text, &block)
puts "objA.instanceMethod: #{text}"
block.call("Call back from objA.instanceMethod")
end
end
class OBJB
def starterMethod
OBJA.staticMethod("foo") {|str| puts str}
OBJA.new.instanceMethod("bar") {|str| puts str}
end
end
b = OBJB.new
b.starterMethod
--output:--
objA.staticMethod: foo
Call back from objA.staticMethod
objA.instanceMethod: bar
Call back from objA.instanceMethod
Or, more illustrative of the closure:
class OBJA
def self.staticMethod(text, &block)
puts "objA.staticMethod: #{text}"
block.call
end
def instanceMethod(text, &block)
puts "objA.instanceMethod: #{text}"
block.call
end
end
class OBJB
def initialize
#x = 1
#y = 2
end
def starterMethod
OBJA.staticMethod("foo") {puts instance_variable_get(:#x)}
OBJA.new.instanceMethod("bar") {puts instance_variable_get(:#y)}
end
end
b = OBJB.new
b.starterMethod
--output:--
objA.staticMethod: foo
1
objA.instanceMethod: bar
2
I don't know if this will help you or not, but this trick is used all over the Ruby frameworks. Ruby being the Wild West of programming languages, it will actually allow you to ignore the closure. That's useful when you want to accept a block from some code, but you don't want to execute the block in the context in which the block was defined--instead you want to execute the block in a context you create.
class OBJA
#x = 10 #Instance variables attach themselves to whatever object is
#y = 20 #self at the time they are created. Inside a class, but outside
#any defs, self is equal to the class, so these statements
#create what are known as 'class instance variables' (##variables
#aren't used in ruby because they don't behave 'correctly').
def self.staticMethod(text, &block)
puts "objA.staticMethod: #{text}"
instance_eval &block #See comment (1) below
end
def instanceMethod(text, &block)
puts "objA.instanceMethod: #{text}"
block.call
end
end
class OBJB
def initialize
#x = 1
#y = 2
end
def starterMethod
OBJA.staticMethod("foo") {puts instance_variable_get(:#x)}
OBJA.new.instanceMethod("bar") {puts instance_variable_get(:#y)}
end
end
b = OBJB.new
b.starterMethod
--output:--
objA.staticMethod: foo
10 #<--CHECK THIS OUT!!
objA.instanceMethod: bar
2
(1) When you call a method without a receiver, ruby uses self to call the method. Inside a class method, self is equal to the class, so the instance_eval() call is equivalent to:
OBJA.instance_eval &block
instance_eval() is used to change the value of the self variable to the receiver. But self was already equal to OBJA?? What instance_eval() succeeds in doing is changing the value of the self variable that it's block sees! By converting the block variable to become instance_eval's block, you actually change the blocks context, i.e. the variables that the block's code sees.
At the moment your callback OBJB.send is called on the class, but your returnedCall method is an instance method. There are two ways to fix this:
Call the callback on an instance instead of on the class by changing lines OBJB.send(... to
OBJB.new.send(...
Or by making the callback method a class method by changing def returnedCall(... to
def self.returnedCall(text)

Ruby Koans Proxy Project

I'm walking through the Ruby Koans and I have a trouble in about_proxy_object_project.rb
This is my solution
class Proxy
attr_reader :messages
def initialize(target_object)
#object = target_object
# ADD MORE CODE HERE
#messages = []
end
def number_of_times_called(method_name)
#messages.count method_name
end
def called?(method_name)
#messages.include? method_name
end
def method_missing(method_name, *args, &block)
if #object.respond_to? method_name
#object.send(method_name, *args)
#messages << method_name
else
super method_name, *args, &block
end
end
end
but when I typed rake I got this
The answers you seek...
Expected 10 to equal [:channel=, :power, :channel]
Please meditate on the following code:
/home/Shanicky/koans/about_proxy_object_project.rb:61:in `test_tv_methods_still_perform_their_function'
and in my about_proxy_object_project.rb
def test_tv_methods_still_perform_their_function
tv = Proxy.new(Television.new)
tv.channel = 10
tv.power
assert_equal 10, tv.channel # this is the 61st line
assert tv.on?
end
I am confused
Where i did do wrong?
Thanks all
and this is my Television class
class Television
attr_accessor :channel
def power
if #power == :on
#power = :off
else
#power = :on
end
end
def on?
#power == :on
end
end
In this if clause:
if #object.respond_to? method_name
#object.send(method_name, *args)
#messages << method_name # <-- this is the return value you get
else
super method_name, *args, &block
end
The check #object.respond_to? method_name always evaluates to true because the Television class defines all these methods you've called on its objects (channel=, power, channel). Therefore the first branch of the if runs and this code essentially adds to the #messages instance variable (which is an Array) the method names that you are calling.
So when you call tv.channel the return value of the method is that commented statement in the above code, which of course is not equal to 10. You essentially get the return value of #messages << method_name which is the new #messages array, which actually contains all the undefined method you've called until that time: [:channel=, :power, :channel].
You can just use 'send' without checking. There is no purpose of using 'else' because it always returns some Exception.
def method_missing(method_name, *args, &block)
#messages << method_name
#object.send(method_name, *args, &block)
end
if you swap the two statements:
#object.send(method_name, *args)
#messages << method_name # <-- this is the return value you get
so:
#messages << method_name # <-- this is the return value you get
#object.send(method_name, *args)
then the return value would be whatever is returned by the method_name, and so in the case of tv.channel it would return 10 as expected in your test.
I think this is just saying the same thing as in the answer, but thought it worth making it clearer

How to intercept class method calls, not just instance method calls

Can someone help me modify the answer provided for intercepting instance method calls so that it works with either class method calls, or both class and instance method calls? From my limited knowledge of metaprogramming with Ruby, I'd imagine it would have something to do with opening up the singleton class some place using class << self, but I've tried doing that in various places with this code and I can't seem to figure it out. Instead of a direct answer, though, could you provide me with a push in the right direction? I'm a big fan of figuring things out for myself unless I'm completely out of my depth. Thanks!
Here is my solution modified from the answer in the link you provided. I moved the hook logic from super class to a separate module so that when ever a class needs the hook, it just include or extend that module and call the hook method.
before_each_method type, &block - type can be :class or :instance, and the block is the code to be executed before each method. The block will be evaluated under certain environments, that is, for instance methods, self in the block is the instance; for class methods, self in the block is the class.
before_class_method &block - alias for before_each_method :class, &block
before_instance_method &block - alias for before_each_method :instance, &block
module MethodHooker
def self.included(base)
base.extend(ClassMethods)
end
def self.extended(base)
base.extend(ClassMethods)
end
module ClassMethods
def before_each_method type, &block
singleton = class << self; self; end
case type
when :instance
this = self
singleton.instance_eval do
define_method :method_added do |name|
last = instance_variable_get(:#__last_methods_added)
return if last and last.include?(name)
with = :"#{name}_with_before_each_method"
without = :"#{name}_without_before_each_method"
instance_variable_set(:#__last_methods_added, [name, with, without])
this.class_eval do
define_method with do |*args, &blk|
instance_exec(name, args, blk, &block)
send without, *args, &blk
end
alias_method without, name
alias_method name, with
end
instance_variable_set(:#__last_methods_added, nil)
end
end
when :class
this = self
singleton.instance_eval do
define_method :singleton_method_added do |name|
return if name == :singleton_method_added
last = instance_variable_get(:#__last_singleton_methods_added)
return if last and last.include?(name)
with = :"#{name}_with_before_each_method"
without = :"#{name}_without_before_each_method"
instance_variable_set(:#__last_singleton_methods_added, [name, with, without])
singleton.class_eval do
define_method with do |*args, &blk|
instance_exec(name, args, blk, &block)
send without, *args, &blk
end
alias_method without, name
alias_method name, with
end
instance_variable_set(:#__last_singleton_methods_added, nil)
end
end
end
end
def before_class_method &block
before_each_method :class, &block
end
def before_instance_method &block
before_each_method :instance, &block
end
end
end
class Test
extend MethodHooker
before_each_method :instance do |method, args, block|
p [method, args, block]
puts "before instance method(#{method}) #{#var}"
end
before_class_method do |method, args, block|
puts "before class method(#{method}) #{#class_instance_var}"
end
#class_instance_var = 'stackoverflow'
def initialize
#var = 1
end
def test(a, b, c)
puts "instance method test"
end
def self.test1
puts "class method test"
end
end
Test.new.test(1, "arg2", [3]) {|t| t}
Test.test1
The output will be something like:
[:initialize, [], nil]
before instance method(initialize)
[:test, [1, "arg2", [3]], #<Proc:0x00000001017d5eb8#/Users/test/before_method.rb:88>]
before instance method(test) 1
instance method test
before class method(test1) stackoverflow
class method test

ruby dsl making

I try to write DSL
class Warcraft
class << self
def config
unless #instance
yield(self)
end
#instance ||= self
end
attr_accessor :name, :battle_net
def game(&block)
#instance ||= Game.new(&block)
end
end
class Game
class << self
def new
unless #instance
yield
end
#instance ||= self
end
attr_accessor :side, :hero
def rune_appear_every(period)
#rune_appear_every = period
end
end
end
end
Warcraft.config do |war|
war.name = "Warcraft III"
war.battle_net = :iccup
war.game do |game|
game.side = :sentinels
game.hero = "Furion"
game.rune_appear_every 2.minutes
end
end
And i get such error:
dsl.rb:41:in `block (2 levels) in <main>': undefined method `side=' for nil:NilClass (NoMethodError)
The issue is here:
def new
unless #instance
yield
end
#instance ||= self
end
You're not passing in any argument when you yield, later on when you call:
war.game do |game|
The game variable is nil. So instead of just doing yield, do yield self.

Define singleton methods on initialization using instance variables

I'm trying to optimize some code and I want to instead on checking a value on every method call just define the method to respond with the checking already pre-calculate, because this checking doesn't change on the whole live of the instance.
I decided to define different versions of the method for every instance created. More or less this way:
class TestingSingletonMethodsWithVariable
METHODS = %w(a b c d)
def initialize(favorite_method)
class << self
METHODS.each do |method_name|
if( favorite_method == method_name )
define_method method_name do
puts "#{method_name} its my favorite method"
end
else
define_method method_name do
puts "#{method_name} its not my favorite method"
end
end
end
end
end
end
t = TestingSingletonMethodsWithVariable.new('b')
t.a
t.b
t.c
t.d
# $ ruby test/testing_singleton_methods_with_variable.rb
# test/testing_singleton_methods_with_variable.rb:7:in `initialize': undefined local variable or method `favorite_method' for #<Class:#<TestingSingletonMethodsWithVariable:0x1001a77b8>> (NameError)
# from test/testing_singleton_methods_with_variable.rb:6:in `each'
# from test/testing_singleton_methods_with_variable.rb:6:in `initialize'
# from test/testing_singleton_methods_with_variable.rb:21:in `new'
# from test/testing_singleton_methods_with_variable.rb:21
What is happening is that something weird is happening with the variables: the variables declares out-side the class << self block are not visible for the variables inside.
Any one can explain me how can I do the behavior I'm looking for?
Thanks
In Ruby, only blocks can be closures, class bodies (as well as module and method bodies) cannot be closures. Or to put it another way: only blocks create a new nested lexical scope, all others (module bodies, class bodies, method bodies and script bodies) create new top-level scopes.
So, you will need a block. Normally, this would mean using some form of eval, but here you can just use define_singleton_method instead:
class TestingSingletonMethodsWithVariable
METHODS = %w(a b c d)
def initialize(favorite_method)
METHODS.each do |method_name|
if favorite_method == method_name
define_singleton_method method_name do
puts "#{method_name} its my favorite method"
end
else
define_singleton_method method_name do
puts "#{method_name} its not my favorite method"
end
end
end
end
end
t = TestingSingletonMethodsWithVariable.new('b')
t.a
t.b
t.c
t.d
Adding to Jörg's answer: define_singleton_method is Ruby 1.9+. If you want to run it in pre 1.9, the following works:
class Object
def metaclass
class << self; self; end
end
end
class TestingSingletonMethodsWithVariable
METHODS = %w(a b c d)
def initialize(favorite_method)
METHODS.each do |method_name|
if( favorite_method == method_name )
metaclass.send(:define_method, method_name, Proc.new do
puts "#{method_name} its my favorite method"
end)
else
metaclass.send(:define_method, method_name, Proc.new do
puts "#{method_name} its not my favorite method"
end)
end
end
end
end
t = TestingSingletonMethodsWithVariable.new('b')
t.a
t.b
t.c
t.d

Resources