How can i dynamically call a Proc in Ruby? - 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

Related

How Ruby Method Modify in Place

How does one write Ruby methods for modification in place?
I want to accomplish the following:
def fulljoin(ruby_array)
r = ''
ruby_array.each {|item| r += "'#{ item }', "}
r.chop!.chop!
end
a = ['Alex', 'Bert', 'Charlie']
a = fulljoin(a) # => 'Alex', 'Bert', 'Charlie'
But I want to modify the array a in place:
a.fulljoin!
What is the syntax to accomplish this?
Initially a is an Array. If you could write method a.fulljoin! with desirable result, a would become a String, but it's not possible in Ruby.
But a.fulljoin! can convert a to Array with single member a[0] - a
String you need. And it will be as close to your goal as possible:
class Array
def fulljoin!
r = "'#{self.join("', '")}'"
self.clear
self[0] = r
end
end
a = ["Alex", "Bert", "Charlie"]
a.fulljoin!
p a
=> ["'Alex', 'Bert', 'Charlie'"]
P.S.: As suggested by #engineersmnky, method fulljoin! can be simplified to:
class Array
def fulljoin!
self.replace(["'#{self.join("', '")}'"])
end
end

How do I process multiple variables in the same way?

It's highly probable this question has been asked, but I can't find the answer.
I have four variables:
a,b,c,d = [a,b,c,d].map{|myvar| myvar+1 }
How can I make this line more DRY (keeping it compact), i.e., achieve the same changes without repeating variable names?
Don't create separate variables, put the values in an Array or Hash from the beginning.
data = []
data << 1
data << 2
data << 3
data << 4
data = data.map { |value| value + 1 }
data.inspect # => [2, 3, 4, 5]
or
data = {}
data[:a] = 1
data[:b] = 2
data[:c] = 3
data[:d] = 4
data.each { |key, value| data[key] = value + 1}
data.inspect # => {:a=>2, :b=>3, :c=>4, :d=>5}
i have a growing suspicion that short answer (for this specific example with integers) is "no way"
due to the same reason as described in the answer in my previous question:
replacing referenced Integer value in Ruby like String#replace does
update:
if variables we operate on are an Array, Hash or String, and they keep the same datatype after the performed operation, it's drier, more compact and saving memory to use replace
[a,b,c,d].each{|v| v.replace(v + [1])} #example for an array

In Ruby, how to conditionally add several members to an object?

I would like to create a hash with several members added conditionally.
The simple approach is:
var a = {}
a['b'] = 5 if condition_b
a['c'] = 5 if condition_c
a['d'] = 5 if condition_d
Now, I would like to write a more idiomatic code. I am trying:
a = {
b => (condition_b? 5 : null),
c => (condition_c? 5 : null),
d => (condition_d? 5 : null)
}
But now, a.length equals 3 whatever conditions are met. This is not the desired result.
Is there a handy solution?
May be not exactly what you want but this can help
array = ['b','c','d'] ##array of values you want as keys
a ={}
array.each do |val|
a[val] = 5 if send("condition_"+val.to_s) #call method condition_#{key_name}
end
If the conditions are not related you can use your own hash and you can
a = {
b => (condition_b? 5 : nil),
c => (condition_c? 5 : nil),
d => (condition_d? 5 : nil)
}
a.values.compact.size
to get length of values other then nil
How about you only add to the hash if the condition is met, like this:
a = {}
a.merge!({'b'=>5}) if condition_b
a.merge!({'c'=>5}) if condition_c
In the second way, you're always going to have the three keys; the conditions only determine the particular values. So if you want to use that syntax, you will need to define a custom method that only counts the keys if they are not nil (also, it's nil in Ruby, not null). Something like:
def non_nil_length(hash)
i = 0
hash.each_pair do |k,v|
if !v.nil?
i += 1
end
end
i
end
There's probably a better way to do that, but there's the quick and dirty.

RoR different bracket notation

I'm getting to grips with rails and whilst I feel I am progressing there is one thing that I am struggling to get to grips with and it's very basic. I am trying to understand the different usage of [] {} and () Are there any good sources of their usage and are there any tips you can give to a beginner in recognizing when to use one or the other, or as I seem to see in some cases when they are not required at all?
I know this is extremely basic but I have struggled to find literature which explains concisely the interplay between them and Ruby or specifically RoR
It has nothing to do with RoR; the various brackets are Ruby language constructs.
[] is the array operator, for arrays and other classes that implement it (like a string taking a range to get substrings, or hashes to look up a key's value):
a = [1, 2, 3]
a.each { |n| puts n }
s = "ohai"
puts s[1..-1]
h = { foo: "bar", baz: "plugh" }
puts h[:foo]
{} is for hashes, and one of two ways of delimiting blocks (the other being begin/end). (And used with # for string interpolation.)
h = { foo: "bar", baz: "plugh" }
h.each { |k, v| puts "#{k} == #{v}" }
() is for method parameters, or for enforcing evaluation order in an expression.
> puts 5 * 3 + 5 # Normal precedence has * ahead of +
=> 20
> puts 5 * (3 + 5) # Force 3+5 to be evaluated first
=> 40
def foo(s)
puts(s)
end
They're sometimes optional if the statement has no ambiguity:
def foo s
puts s
end
(They're not always optional, and putting a space between the method call and its parenthetical parameter list can cause issues--best not to, IMO.)
(I probably missed something, too, but there's the nutshell.)
[] are used to access objects within a hash (via a key) or within an array (via an index).
hash[:key] # returns a value
array[0] # returns the first array element
[] is used to describe an array.
array = ['a', 'b', 'c']
Of course this can be nested.
nested = [['a','b','c'], [1,2,3]]
[] can be used to declare a hash, but that's because the Hash class can accept an array.
hash = Hash[['a',1], ['b',2]] # { 'a' => 1, 'b', => 2 }
{} is used to declare a hash.
hash = { 'a' => 1, 'b' => 2 }
This too can be nested.
hash = { 'a' => { 'c' => 3 }, 'b' => { 'd' => 4 } }
{} is also used to delimit blocks. The .each method is a common one. The following two blocks of code are equivalent.
array.each do |n|
puts n
end
array.each { |n| puts n }
The () is just used for grouping in cases where ambiguity needs clarification. This is especially true in methods that take many arguments, some of which may be nil, some of which may be obejcts, etc. You'll see a lot of code that omit them entirely as no grouping is needed for clarity.
puts(string)
puts string
I recommend firing up the rails console and start declaring variables and accessing them.

How do you stringize/serialize Ruby code?

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

Resources