Intercepting def in a block - ruby

I have a method that needs to do a bit of sorcery on the attached block. A sample of such a block might be
myMethod do
somemethod x
someother y
def name(a,b)
a+b
end
end
the first two method calls (somemethod x and someother y) should just be executed as normal. However I'd like to intercept the method definition (as S-expression) without actually defining a new method. I can do this if I transform the entire block to S-expressions and then search through the AST. However then I need to figure out how to call the methods. A solution to either will do. That is either
intercepting the definition, transform to S-expression (that Ruby2Ruby can understand)
transform the block to S-expressions and find the method calls and execute these
EDIT
The AST I'm looking for is something similar to
[:defn,
:name,
[:args,:a,:b],
[:call,
[lvar,:a],
:+
[lvar,:b]]]

If I understand correctly, you want to be able to define a method within a code block passed to another method, but intercept that inner method definition so that it doesn't actually get defined but is instead converted to an S-expression? So you want it to behave almost as if it were commented out and some external process had come through the source code and parsed out the implementation into an S-expression?
Something like:
myMethod do
somemethod x
someother y
# def name(a,b)
# a+b
# end
end
Where somemethod and someother still execute, the implementation of name is defined, but is ignored by the Ruby interpreter. Then you somehow want to capture this implementation as an S-expression. It obviously wouldn't be done like this, by commenting it out, but its a nice way for me to picture the behavior.
Well, the RubyParser gem might do what you want. It takes advantage of the ability to pass in a 'here document' as a string to a method, as in this example:
def x (str)
str
end
x( <<-EOF )
this is
a here
document
EOF
# => "this is\n a here\ndocument\n"
Using RubyParser, you can do something like the following:
require 'ruby_parser'
require 'pp'
pp RubyParser.new.parse( <<-EOF )
def plus(x,y)
x+y
end
EOF
# => s(:defn, :name, s(:args, :a, :b), s(:call, s(:lvar, :a), :+, s(:lvar, :b)))
It would be a trivial matter, then, to merge it with your desired code, like so:
require 'ruby_parser'
def myMethod
x = yield
end
def somemethod( x )
puts x
end
def someother( y )
puts y
end
x = 'magic'
y = 'output'
sexp = myMethod do
somemethod x
someother y
RubyParser.new.parse( <<-EOF )
def name(a,b)
a+b
end
EOF
end
pp sexp
name(1,2)
# magic
# output
# s(:defn, :name, s(:args, :a, :b), s(:call, s(:lvar, :a), :+, s(:lvar, :b)))
# NoMethodError: undefined local variable or method 'name' for main:Object
As you can see, the method definition is essentially just a string, and can be manipulated as such.

Related

ruby get caller full namespace with its parameter name and argument

in debugging ruby applications, i am interested in printing in each function the:
- full method namespace
- the method parameters and their arguments (values)
for instance, given the following code block
module Foo
module Bar
def self.baz(p, q)
end
end
end
when invoking baz with arguments, such as Foo::Bar.baz 'val1', 'val2', a message should be printed with the following output Foo::Bar.baz(p=val1, q=val2) (or any similar output)
i am familiar with ruby reflection, so i can introduce to each function some additional code to print it. though, single point of modification is a bliss, thus having the each method call another method that will produce such output will be the great.
my questions are:
is there anyway to introduce a method, which each other method invoke that will yield an output similar to the above?
is there anyway to achieve the same result by binding the printing method (function) to the beginning of any other method?
What you are looking for is #set_trace_func combined with binding introspection:
module Foo
module Bar
def self.baz(p, q)
end
end
end
intercept_event = proc do |event, _, _, method_name, method_binding, _|
if event == 'call'
self_in_method = method_binding.eval('self')
parameter_names = self_in_method.method(method_name).parameters.map(&:last)
parameter_list = parameter_names.map do |name|
"#{name}=#{method_binding.local_variable_get(name)}"
end
puts "#{self_in_method}.#{method_name}(#{parameter_list.join ', '})"
end
end
set_trace_func intercept_event
Foo::Bar.baz 'val1', 'val2' # Foo::Bar.baz(p=val1, q=val2)
Note that this will not work for C methods. To handle them, you can check for 'c-call' instead of 'call'. You will have to move the method parameters in the string eval however, as self in those methods is not the same as in Ruby methods.

Ruby Bracket Method with Block

I would like to define the [] method on a class of my own creation to take a block. I have done so as follows.
class A
def self.[](*args, &block)
puts "I am calling #{block} on #{args}."
block.(*args)
end
end
I can invoke this as follows.
# Explicit method invocation
A.[](1) { |x| puts x }
# With a procedure argument
arg = proc { |x| puts x }
A[2, &arg]
However, what I would like to be able to do is this.
A[3] { |x| puts x }
Which unfortunately seems to produce a syntax error. Is there a block syntax for the bracket method, or am I stuck with the first two ways of invoking it? In fact, more generally, which Ruby method names will allow blocks in their invocation, as it seems that there might be a limitation on when this is allowed?
There's not much you can do against a syntax error, so you'll have to change the syntax.
If you accept :
to define (i.e. pollute) an uppercase method inside Kernel (similar to Kernel#Array)
to use parens instead of brackets
You could write :
class A
def self.call_block_with_args(*args, &block)
puts "I am calling #{block} on #{args}."
block.call(*args)
end
end
module Kernel
def A(*args, &block)
A.call_block_with_args(*args, &block)
end
end
It works this way :
A(3) { |x| puts x }
#=>
# I am calling #<Proc:0x000000012b9c50#block_brackets.rb:14> on [3].
# 3
It's not clean, but it's probably the closest you can be to A[3] { |x| puts x }.
Blocks work with normal method calls only.
Ruby has plenty of operators, listing all of them here would be exhaustive, there are more than two dozens. Even `a` and !a and -a are method calls in Ruby. And obviously there are limitations to all these operators, eg + must take one parameter but not more, et cetera.
Fun fact, loop is a method call too.

Ruby - Is &prc different than &block?

I'm writing a simple method that adds num to the return value of the block that is passed to it and I noticed that &block and &prc both work. I know that a proc is an object and can be assigned to a variable which could be handy. Is that the only difference though? Is there any difference between these two when it comes to performance, convention, or versatility? Is it ever better to use &block instead of &prc?
def adder(num = 1, &block)
yield + num
end
vs.
def adder(num = 1, &prc)
yield + num
end
Is there any difference between these two when it comes to
performance, convention, or versatility?
There is no difference between these, you able to name it as you want, it's just a name. Some devs call it &blk some &block or &b or &foo ...
>> def foo &foo
>> yield
>> end
=> :foo
>> foo do
?> puts '1'
>> end
1
Strictly saying & is an operator which you can apply to any object, and it will take care of converting that object to a Proc by calling to_proc().
>> def bar(&some_proc)
>> some_proc
>> end
=> :bar
>> p = bar { puts 'Call proc' }
=> #<Proc:0x005601e6d69c80#(irb):4>
>> p.call
=> Call proc
>> p.class
=> Proc
Only the one thing is important, the name should be informative.
Line any argument to your method the name is largely subjective. Typically you'll see &block used if only by convention, but the name itself can be anything you want so long as it's a valid variable name.
In your example you're declaring a block name but not actually using the name. Keep in mind that any Ruby method can be given a block, there's no way to restrict this, but it's up to the method itself to use the block if it wants. That block can be called zero or more times either immediately or at some point in the future. Giving the block to the method surrenders control, so be sure to read the documentation on any given method carefully. There can be surprises.
If you need to chain through a block, declare it with a name:
def passes_through(&block)
[ 1, 2, 3, 4 ].each(&block)
end
If you are going to yield on the block there's no need here:
def direct_call
[ 1, 2, 3, 4 ].each do |n|
yield n
end
end
If you're going to preserve the call and use it later, that's also a case for naming it:
def preserved_call(&block)
#callback = block
end
def make_callback
#callback and #callback.call
end
Any method can check if a block was supplied:
def tests_for_block
if (block_given?)
yield 'value'
else
'value'
end
end
There's a small but measurable cost to capturing a block by declaring it in the method signature, a lot of computation has to be done to properly capture all the variables that might be used in a closure situation. In performance sensitive code you'll want to avoid this.
You can dynamically create a block:
def captures_conditionally
if (block_given?)
#callback = Proc.new
end
end
The Proc.new method will assume control over whatever block has been supplied to the method if one has been.
in your example, there is not a difference between &block and &prc, because in each case you are just passing a block to be call into the method.
Block and proc are similar in that they are both blocks of code.
[1,2,3].each {|x| puts x }
everything within the {} is the block.
A proc is just a block of code that you can name and can be called at a later time.
put_element = Proc.new {|x| puts x}
then you use put_element as an argument in your function.

Unary Ampersand Operator and passing procs as arguments in Ruby

I'm having trouble understanding this code below.
I get the idea of Unary Ampersand Operator and passing procs as arguments to methods. But I really can't wrap my head around passing self to the language.call. I understand it like this: we're passing self as an argument to the proc/block language. It doesn't make any sense to me. Can someone please explain? :)
class Translator
def speak &language
language.call(self)
end
protected
def french
'bon jour'
end
def spanish
'hola'
end
def turkey
'gobble'
end
def method_missing(*args)
'awkward silence'
end
end
We're using it with:
translator.speak(&:spanish)
This example beautifully ties together multiple Ruby concepts. Because of that, I will try to explain all of them.
Blocks
Methods in Ruby can accept blocks (pieces of code) in elegant matter:
def run_code
yield
end
run_code { puts 42 } # => prints 42
Procs are similar to blocks, but they are actual addressable objects:
deep_thought = proc { puts 42 }
deep_thought.call # => prints 42
You can turn a proc into a block when calling a method with the & operator:
def run_code
yield
end
deep_thought = proc { puts 42 }
run_code(&deep_thought) # => prints 42
Procs and blocks can accept arguments:
def reveal_answer
yield 5_000
end
deep_thought = proc do |years_elapsed|
years_elapsed >= 7_500_000 ? 42 : 'Still processing'
end
reveal_answer(&deep_thought) # => 'Still processing'
You can turn a block into proc using & in the method signature:
def inspector(&block)
puts block.is_a?(Proc)
puts block.call
end
inspector { puts 42 } # => prints true and 42
inspector(&proc { puts 42 }) # => the same
Symbol#to_proc creates a proc that calls methods with the same name on the object:
class Dummy
def talk
'wooooot'
end
end
:talk.to_proc.call(Dummy.new) # => "wooooot"
In other words,
:bar.to_proc.call(foo)
is pretty much equivalent to
foo.bar
BasicObject#method_missing:
When you try to call a method on an object, Ruby traverses it's ancestor chain, searching for a method with that name. How the chain is constructed is a different topic, lengthy enough for another day, the important thing is that if the method is not found til the very bottom (BasicObject), a second search is performed on the same chain - this time for a method called method_missing. It gets passed as arguments the name of the original method plus any argument it received:
class MindlessParrot
def method_missing(method_name, *args)
"You caldt #{method_name} with #{args} on me, argh!"
end
end
MindlessParrot.new.foo # => "You caldt foo with [] on me, argh!"
MindlessParrot.new.bar :baz, 42 # => "You caldt bar with [:baz, 42] on me, argh!"
So what does all this mean in our specific case? Lets assume for a second there was no protected.
translator.speak(&:spanish)
calls the method Translator#speak with :spanish converted to block.
Translator#speak takes that block and transforms it to a proc, named language, and calls it, passing self as argument.
self is an instance of Translator, therefore, it has the methods speak, french, spanish, turkey and method_missing.
And so:
Translator.new.speak(&:spanish)
is equivalent to:
:spanish.to_proc.call(Translator.new)
which is equivalent to:
Translator.new.spanish
giving us "hola".
Now, taking the protected back, all the language methods of our translator object are still present, but they can not be directly accessed by outsiders.
Just as you can't call
Translator.new.spanish
and expect "hola" back, you can't call
Translator.new.speak(&:spanish)
And since the method is not directly accessible, it is considered not found and method_missing is called, thus giving us "awkward silence".

Ruby creating objects syntax

I just started using Shoes and i know a lille bit of ruby but there is something i quite dont understand with the objects and constructor.
I learned to create objects this way:
#obj = SomeClass.new(:someParameter => 3)
Now Shoes want me to create objects this way:
Shoes.app do
#shape = star(points: 5)
motion do |left, top|
#shape.move left, top
end
end
Here is an other example:
require 'shoes'
class ListCell < Shoes::Widget
def initialize
stack :margin_left => 30, :top => 30 do
line 50, 100, 200, 200
end
end
end
Shoes.app :width => 500, :height => 400 do
stack do
#line = list_cell
end
end
Why is there a .new missing?
Why does shoes use the syntax with the colon to pass parameter in the first example?
In the second example i create a ListCell object but I use the syntax list_cell without the new.
Why does this behave like this?
This is maybe a very basic question, but i am trying to learn ruby and i have VB.Net/Java background and some things are just wierd and not very usual to me. The syntax is confusing me.
It is just a DSL. Those methods like star will call .new under the hood.
The colon syntax is just an alternative hash syntax introduced in Ruby 1.9.3:
{ :a => :b }
{ a: :b }
These two lines do the same thing.
Class methods
Shoes.app do is not creating an instance, this is calling a class method.
This allows to call a method directly on a class, without having to instantiate it.
class Foo
def self.hello
puts "hello"
end
end
Foo.hello # outputs "hello"
Block parameter
The block form may confuse you, but it's an other ruby idiom that allows to pass chunk of logic to a method :
def yell( message, &block )
block.call( message.upcase )
end
yell( 'hello' ) do |message|
puts message
end
# outputs "HELLO"
DSL
Finally, there's a special form of block parameter often used to have good looking configuration : blocks that are evaluated in an other context.
When you call a block like in the previous example, the code inside blocks won't be able to access any private method or variable from the class where it's called ; it can only access what is in the scope of where the block was declared.
You can change that using #instance_eval :
class Foo
def config( &block )
instance_eval &block
end
def write!
# perform some writing
end
end
foo = Foo.new
foo.config do
write! # this will work
end
So, basically, your shoes are doing a combination of those three concepts :)
This is not instantiating a class (although it probably does so behind the hood) and you don't especially need that, just use initialization as you are used to.

Resources