How do you stringize/serialize Ruby code? - ruby

I want to be able to write a lambda/Proc in my Ruby code, serialize it so that I can write it to disk, and then execute the lambda later. Sort of like...
x = 40
f = lambda { |y| x + y }
save_for_later(f)
Later, in a separate run of the Ruby interpreter, I want to be able to say...
f = load_from_before
z = f.call(2)
z.should == 42
Marshal.dump does not work for Procs. I know Perl has Data::Dump::Streamer, and in Lisp this is trivial. But is there a way to do it in Ruby? In other words, what would be the implementation of save_for_later?
Edit: My answer below is nice, but it does not close over free variables (like x) and serialize them along with the lambda. So in my example ...
x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n (x + y)\n}"
... the string output does not include a definition for x. Is there a solution that takes this into account, perhaps by serializing the symbol table? Can you access that in Ruby?
Edit 2: I updated my answer to incorporate serializing local variables. This seems acceptable.

Use Ruby2Ruby
def save_for_later(&block)
return nil unless block_given?
c = Class.new
c.class_eval do
define_method :serializable, &block
end
s = Ruby2Ruby.translate(c, :serializable)
s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1|').sub(/end$/, '}')
end
x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n (x + y)\n}"
g = eval(s)
# => #<Proc:0x4037bb2c#(eval):1>
g.call(2)
# => 42
This is great, but it does not close over free variables (like x) and serialize them along with the lambda.
To serialize variables also, you can iterate over local_variables and serialize them as well. The problem, though, is that local_variables from within save_for_later accesses only c and s in the code above -- i.e. variables local to the serialization code, not the caller. So unfortunately, we must push the grabbing of local variables and their values to the caller.
Maybe this is a good thing, though, because in general, finding all free variables in a piece of Ruby code is undecidable. Plus, ideally we would also save global_variables and any loaded classes and their overridden methods. This seems impractical.
Using this simple approach, you get the following:
def save_for_later(local_vars, &block)
return nil unless block_given?
c = Class.new
c.class_eval do
define_method :serializable, &block
end
s = Ruby2Ruby.translate(c, :serializable)
locals = local_vars.map { |var,val| "#{var} = #{val.inspect}; " }.join
s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1| ' + locals).sub(/end$/, '}')
end
x = 40
s = save_for_later(local_variables.map{ |v| [v,eval(v)] }) { |y| x + y }
# => "lambda { |y| _ = 40; x = 40;\n (x + y)\n}"
# In a separate run of Ruby, where x is not defined...
g = eval("lambda { |y| _ = 40; x = 40;\n (x + y)\n}")
# => #<Proc:0xb7cfe9c0#(eval):1>
g.call(2)
# => 42
# Changing x does not affect it.
x = 7
g.call(3)
# => 43

Use sourcify
This will work on Ruby 1.8 or 1.9.
def save_for_later(&block)
block.to_source
end
x = 40
s = save_for_later {|y| x + y }
# => "proc { |y| (x + y) }"
g = eval(s)
# => #<Proc:0x00000100e88450#(eval):1>
g.call(2)
# => 42
See my other answer for capturing free variables.
Update:
Now you can also use the serializable_proc gem, which uses sourcify, and captures local, instance, class, and global variables.

Check out the answers to this question.

Ruby has the Marshal class that has a dump method that you can call.
Take a look here:
http://rubylearning.com/satishtalim/object_serialization.html

Related

Conditionally assign return value of functions in one line

Imagine I have the following two functions:
def myfunc
puts "hello from myfunc"
return "returned myfunc"
end
def myfunc2
puts "hello from myfunc2"
return "returned myfunc2"
end
And I want to conditionally assign the return value of these functions to a variable, while at the same time ensuring that both functions are called like so:
x = nil
temp = myfunc
x = temp unless x
temp = myfunc2
x = temp unless x
How can I reduce each two line assignment statement segment to one line?
Note, the following won't work because the second function won't get called:
x = nil
x ||= myfunc
x ||= myfunc2
x = [myfunc1, myfunc2].reduce { |f1, f2| f1 || f2 }
Unfortunately, the short notation would not work because of the necessity to imply short-circuit on or:
x = [myfunc1, myfunc2].reduce(:||) # does not work
Not sure why you want to do this but this is valid ruby code and both methods will get called
x ||= a = myfunc; b = myfunc2; a || b
Both methods are called but on first run of this line, x will always be assigned to return of myfunc so I don't understand the purpose of this code.
Or maybe you want a random assignment of a or b ?
x ||= a = myfunc; b = myfunc2; [a,b].sample
You could use an Hash:
h = {f1: myfunc, f2: myfunc2}
x = nil
x ||= h[:f1]
x ||= h[:f2]

How can i dynamically call a Proc in Ruby?

Is there a method.send equivalent for proc?
eg:
def s a
a + 1
end
b = "s"
send b.to_sym,10 #=> 11
Is there something like this?
p = Proc.new{|s| s + 1}
d = "p"
*call d.to_sym,10 *
EDIT:
In response to mudasobwa's answer
I need to call the Procs from an array of methods.
eg:
ss = ["a","b","c","d"]
Is it possible in this case?
The other answers cover the exact question asked. But I say, it was a wrong approach. Don't do that runtime introspection. It brings no benefit. If you want to address your procs by name, put them in a hash and use "civilian-grade" ruby.
handlers = {
'process_payment' => proc { ... },
'do_this' => proc { ... },
'or_maybe_that' => proc { ... },
}
pipeline = ['process_payment', 'or_maybe_that']
pipeline.each do |method_name|
handlers[method_name].call
end
For this particular example:
p = Proc.new{|s| s + 1}
d = "p"
#⇒ *call d.to_sym,10 *
It would be:
binding.local_variable_get(d).(10)
#⇒ 11
Updated
Procs are objects, so you can store them in variables, arrays, hashs, just like any objects, and call them from those rather than by names.
If you need to make an array of procs, store the procs themself in an array, rather than the names of the variables you assigned them to. This way, you can pass this array around and call them all.
myprocs = []
myprocs << = Proc.new{|s| s + 1}
myprocs.each {|p| p.call(10)}
If you want to call them by names, use a hash.
myprocs = {}
myprocs["d"] = Proc.new{|s| s + 1}
myprocs["d"].call(10)
Using eval - bad practice, but as one of the possible solutions is:
p = Proc.new{|s| s + 1}
d = "p"
eval("#{d}[10]")
#=> 11

Ruby: A function returning another function

In order to understand the functional programming part of ruby I want to write a function that takes 2 functions f(x,y),g(x) as arguments and returns a new function h(x,y)=f(g(x),g(y)).
def foo(x, y)
return x+y
end
def bar(x)
return 2*x
end
def comp(f,g)
end
f=comp(f,g)
f(1,2) #=> 6
I tried things like
def comp(f,g)
mylambda = lambda {|x,y| return f(g(x),g(y))}
return mylambda
end
f=comp(foo, bar)
f.call(1,2)
I thought f would be a Proc now, and I could just call it. But apparently "in `foo': wrong number of arguments (0 for 2) (ArgumentError)"
What syntax would I have to use? And is it possible to return a "real" function instead of a Proc, so that instead of f.call(1,2) I could just writhe f(1,2) like if I had just defined f myself normaly?
This type of functional pattern doesn't work as smoothly as on more functional languages, as javascript or python. Since ruby has optional parentheses, writing foo is the same as calling the foo method without passing any arguments.
To get a reference to a method, you need to use the Object#method method:
def foo(x, y)
x + y
end
def bar(x)
x * 2
end
def comp(f, g)
lambda { |x, y| f.call(g.call(x), g.call(y)) }
end
h = comp(method(:foo), method(:bar))
h.call(1, 2) # => 6
Ruby doesn't have first class functions like Python. Ruby has lambdas, and method objects that can be constructed specially from a method, but methods themselves are not objects. The closest you'll get to this is this:
def foo(x, y)
return x+y
end
def bar(x)
return 2*x
end
def comp(f,g)
return lambda {|x, y| f.call(g.call(x), g.call(y))}
end
f=comp(method(:f),method(:g))
f.call(1,2) #=> 6
Also, for the calling syntax point, you can call a lambda with square brackets, so you could do this:
f[1,2]
What you have there aren't functions, they are methods. Functions (more precisely: procedures) are defined like this:
foo = -> (x, y) { x + y }
bar = -> x { 2 * x }
comp = -> (f, g) { -> (x, y) { f.(g.(x), g.(y)) } }
f = comp.(foo, bar)
f.(1, 2) #=> 6
Try this:
def foo() lambda {|x,y| x+y} end
def bar() lambda {|x| 2*x} end
def comp(f,g) lambda {|x,y| f[g[x], g[y]]} end
h = comp(foo, bar)
h[1,2] # => 6
or any of the following
h.call(1,2) # => 6
h.(1,2) # => 6
h.yield(1,2) # => 6
If you'd prefer,
foo = lambda {|x,y| x+y}
bar = lambda {|x| 2*x}
Before this question I was unaware of the myriad of ways one can now invoke a lambda (or proc). (The rationale for providing Proc#yield escapes me, as it is the same as call and may be confused with the unrelated yield keyword we all know and love.) One could substitute Proc.new or proc for lambda, or create the lambda with the "stabby" syntax -> (e.g., def bar() ->(x) {2*x} end.
f=comp(foo, bar)
This won't work like it would in python. The error message you're getting is wanting to see something like this.
f = comp(foo(1,2), bar(1))
You need to actually make foo and bar lambdas themselves (or methods that return lambdas) if you want to call it like that:
foo = lambda { |x, y| x + y }
bar = lambda { |x| 2 * x }
or
def foo(x, y)
lambda { |x, y| x + y}
end
def bar(x)
lambda { |x| 2 * x }
end
Then you can achieve what you want to do.

Pass parameters to passed-in block in Ruby

I want to pass a block to a function, and then call that block with some additional parameters as follows:
def foo(&block)
some_array = (1..3).to_a
x = 7 # Simplified
result = some_array.map &block # Need some way to pass in 'x' here
end
def a_usage_that_works
foo do |value|
value
end
end
def a_usage_that_doesnt_work
foo do |value, x|
x # How do I pass in x?
end
end
# rspec to demonstrate problem / required result
describe "spike" do
it "works" do
a_usage_that_works.should == [1,2,3]
end
it "doesn't work" do
a_usage_that_doesnt_work.should == [7, 7, 7]
end
end
How can I pass in the additional parameter to the block?
Create another block and call first one from it.
def foo(&block)
some_array = (1..3).to_a
x = 7 # Simplified
result = some_array.map {|elem| block.call(elem, x)}
end
You pass to the block by yielding to it.
def foo(&block)
some_array = [1,2,3]
x = 7
some_array.map{|el| yield el, x}
end
p foo{|p1, p2| p2} #=>[7,7,7]
p foo{|p1, p2| p1} #=>[1,2,3]
You can use a higher-order function to generate a simplified function:
Let's assume that the block we pass to foo will accept value, x.
Naive strategy, using an inline-defined x:
def foo(&block)
some_array = (1..3).to_a
x = 7
simple_func = proc {|value| block.call(value, x) }
result = some_array.map &simple_func
end
Strategy using separation of concerns:
def get_simple_func(block)
# This assumes x won't change per iteration.
# If it can change, you can move the calculation inside the proc.
# Moving it inside also allows the calculation to depend on "value", in case you want that.
x = complex_calculation_for_x()
proc {|value| block.call(value, x) }
end
def foo(&block)
some_array = (1..3).to_a
simple_func = get_simple_func(block)
result = some_array.map &simple_func
end
Obviously you shouldn't use this when x is a literal value because it would be over-engineering. But as the calculation of x becomes more complex, separating it out makes the code more readable. Also, foo can focus on the specific task of applying the function to some_array.

How do I deep copy a Proc in Ruby?

Is there a straightforward way in Ruby to produce a copy of a Proc?
I have a Proc called #foo. I want another method to periodically augment #foo with additional logic. For example:
# create initial Proc
#foo = lambda { |x| x }
# augment with more logic
#foo = lambda { |x| x > 1 ? x*x : #foo[x] }
I don't want the second line that does the augmentation to produce a recursive function. Instead, I want #foo to be bound by value into the lexical scope of the new #foo definition, producing a function that looks more like this:
#foo = lambda { |x| x > 1 ? x*x : lambda{ |x| x }[x] }
I get an infinite recursion and an eventual stack overflow instead, due to the resulting function looking like this:
#foo = lambda { |x| x > 1 ? x*x : lambda { |x| x > 1 ? x*x : { lambda |x| # etc...
I'd like the code to be like this:
# augment with more logic
#foo = lambda { |x| x > 1 ? x*x : (#foo.clone)[x] }
but clone doesn't work on Procs.
Additionally, the standard Ruby deep copy hack, using marshal and unmarshal, doesn't work on Procs either. Is there some way to do this?
Even if clone would work on Procs, it wouldn't help you, because you'd still be calling clone on the new value of #foo, not on the previous one like you want.
What you can do instead is just store the old value of #foo in a local variable that the lambda can close over.
Example:
def augment_foo()
old_foo = #foo
#foo = lambda { |x| x > 1 ? x*x : old_foo[x] }
end
This way old_foo will refer to the value that #foo had when augment_foo was called and everything will work as you want.

Resources