Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I want to write a code that satisfies:
SomeClass.new.execute(method) == 3
and I have:
class SomeClass
def execute(method)
def method
yield
end
end
end
method = 1+2
which gives me nil. I'm still very confused about yield. Any help is greatly appreciated.
You're along the right lines, but your parameter method must be a code block.
You can create a code block in a few different ways. The most common is anonymously, using {...} or do...end. If you want to store the code block in a variable, which you'd need to do to call SomeClass.new.execute(method), you can use Proc.new.
There are other ways of creating blocks (using the lambda syntax), but they are beyond the scope of this question.
This will work using a block stored in a variable:
class SomeClass
def execute
yield
end
end
method = Proc.new { 1+2 }
SomeClass.new.execute(&method) # => 3
Or, more succinctly,
SomeClass.new.execute { 1 + 2 } # => 3
You're sort of in the right direction-ish. yield will execute a passed-in block. So you want to do something like this:
class SomeClass
def execute
yield
end
end
And then you can call it like this:
SomeClass.new.execute { 1+2 }
The yield keyword passes control to any block that was passed to the method. You haven't passed any blocks, so there's nothing to do.
You want something like this:
class C
def execute
yield # Pass control to a block that was passed in.
# Method returns whatever the value of evaluating `b` was.
end
end
Now you can do:
C.new.execute { 1 + 2 } # Pass block containing a statement "1 + 2".
# => 3 # The result of evaluating "1 + 2" is
# returned from the #execute method.
If you want to pass a method object corresponding to the block you want to pass, instead of specifying it anonymously, you can make a lambda:
b = lambda { 1 + 2 }
C.new.execute &b # Pass an object to #execute that will be used as
# => 3 # the block.
Ruby has a few mostly-equivalent ways of making lambdas:
lambda { 1 + 2 }
Proc.new { 1 + 2 }
-> { 1 + 2 }
Related
New to ruby language. I'm aware that ruby has then keyword to compose blocks and << for proc objects to compose proc. However, the question I have focuses on named functions that yield value to each other. I'm wondering what is the best way to implement such pipeline paradigm in ruby.
Consider the following code I came up with. I don't know if this is idiomatic.
# #param [Proc] lproc
# #param [Proc] rproc
def then_proc(lproc, rproc)
proc { |x| lproc.call(x, &rproc) }
end
def n(x)
yield x
end
def branch(x)
yield x + 1 if x > 2
0
end
def add_one(x)
x + 1
end
then_proc(method(:n).to_proc,
then_proc(method(:branch).to_proc, method(:add_one).to_proc)).call 2
=> 0
then_proc(method(:n).to_proc,
then_proc(method(:branch).to_proc, method(:add_one).to_proc)).call 3
=> 4
To me this is more similar to the forms of pipelines seen in other programming languages (Promise in javascript, for example), because functions can have branches to not yield and terminate early, whereas then requires the pipeline to be completely executed. I'm wondering if there is some mechanism in ruby that can achieve this. If not, how would go about this problem?
Thank you.
Clarification on the question
I would like to build a pipeline using a series of named functions that might but not necessarily yield to a block. Per my understanding, in the existing ruby then/yield_self function, the block is always invoked, which is not the intention. Notice in the toy example I gave, the final add_one block is only executed if previous branch function receives x > 2.
I would like to build a pipeline using a series of named functions that might but not necessarily yield to a block.
A method does not need to yield.
The following implements a conditional using procs:
def _if(v, cond, yes, no = nil)
if cond.call(v)
yes.call(v)
else
no&.call(v)
end
end
cond = lambda { |v| v > 2 }
yes = lambda { |v| v + 1 }
no = lambda { |v| 0 }
_if(1, cond, yes, no)
_if(3, cond, yes, no)
_if(1, cond, yes)
There are many examples how to pass Ruby block as an argument, but these solutions pass the block itself.
I need a solution that takes some variable, executes an inline code block passing this variable as a parameter for the block, and the return value as an argument to the calling method. Something like:
a = 555
b = a.some_method { |value|
#Do some stuff with value
return result
}
or
a = 555
b = some_method(a) { |value|
#Do some stuff with value
return result
}
I could imagine a custom function:
class Object
def some_method(&block)
block.call(self)
end
end
or
def some_method(arg, &block)
block.call(arg)
end
but are there standard means present?
I think, you are looking for instance_eval.
Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables. In the version of instance_eval that takes a String, the optional second and third parameters supply a filename and starting line number that are used when reporting compilation errors.
a = 55
a.instance_eval do |obj|
# some operation on the object and stored it to the
# variable and then returned it back
result = obj / 5 # last stament, and value of this expression will be
# returned which is 11
end # => 11
This is exactly how #Arup Rakshit commented. Use tap
def compute(x)
x + 1
end
compute(3).tap do |val|
logger.info(val)
end # => 4
Can I some how pass the result of an evaluated block as an argument to a function?
This illustrates what I want to do by using a helper function (do_yield):
#!/usr/bin/env ruby
def do_yield
yield
end
def foo a
#'a' must be an array
puts "A: [#{a.join(", ")}]"
end
foo (do_yield{
a = []
a << 1
})
Can I do this without creating my own helper function? Preferably by using facilities in the language, if the language does not offer a way to do it, then is there an existing function I can use instead of my own do_yield
So, you want to pass a result of executing some code into some other code? You just need to convert your "block" to an expression (by making it a proper method, for example)
def bar
a = []
a << 1
end
foo bar
If your code is really this simple (create array and append element), you can use the code grouping constructs (which combine several statements/expressions into one expression)
foo((a = []; a << 1))
or
foo(begin
a = []
a << 1
end)
Personally, I'd definitely go with the method. Much simpler to read.
The piece of terminology you probably want to search for here is lambda - a lambda being an anonymous function that can be passed around as a parameter.
So to do what you are describing with a Lambda you might do this:
my_lambda = lambda do
a = []
a << 1
end
def foo a
#'a' must be an array
puts "A: [#{a.join(", ")}]"
end
foo my_lambda.call
Of course you can have parameterised lambdas and if foo was expecting a lambda you could have it call #{a.call.join(", ")}] ( your actual code has double-quotes everywhere so not sure it would work ) so that the evaluation only happened when it was passed.
This is an interesting and powerful part of Ruby so it is worth learning about.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Hi I`m learning from LRtHW and I got stuck....
I have program like this:
require 'open-uri'
WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []
PHRASES = {
"class ### < ###\nend" => "Make a class named ### that is-a ###.",
"class ###\n\tdef initialize(###)\n\tend\nend" => "class ### has-a initialize that takes ### parameters.",
"class ###\n\tdef ***(###)\n\tend\nend" =>"class ### has-a function named *** that takes ### parameters.",
"*** = ###.new()" => "Set *** to an instance of class ###.",
"***.***(###)" => "From *** get the *** function, and call it with parameters ###.",
"***.*** = '***'" => "From *** get the *** attribute and set it to '***'."
}
PHRASE_FIRST = ARGV[0] == "english"
open(WORD_URL) do |f|
f.each_line {|word| WORDS.push(word.chomp)}
end
def craft_names(rand_words, snippet, pattern, caps=false)
names = snippet.scan(pattern).map do
word = rand_words.pop()
caps ? word.capitalize : word
end
return names * 2
end
def craft_params(rand_words,snippet,pattern)
names = (0...snippet.scan(pattern).length).map do
param_count = rand(3) + 1
params = (0...param_count).map {|x| rand_words.pop()}
params.join(', ')
end
return names * 2
end
def convert(snippet, phrase)
rand_words = WORDS.sort_by {rand}
class_names = craft_names(rand_words, snippet, /###/, caps=true)
other_names = craft_names(rand_words, snippet,/\*\*\*/)
param_names = craft_params(rand_words, snippet, /###/)
results = []
for sentence in [snippet, phrase]
#fake class name, also copies sentence
result = sentence.gsub(/###/) {|x| class_names.pop}
#fake other names
result.gsub!(/\*\*\*/) {|x| other_names.pop}
#fake parameter list
result.gsub!(/###/) {|x| param_names.pop}
results.push(result)
end
return results
end
# keep going until they hit CTRL-D
loop do
snippets = PHRASES.keys().sort_by { rand }
for snippet in snippets
phrase = PHRASES[snippet]
question, answer = convert(snippet, phrase)
if PHRASE_FIRST
question, answer = answer, question
end
print question, "\n\n> "
odp = gets.chomp
if odp == "exit"
exit(0)
end
#exit(0) unless STDIN.gets
puts "\nANSWER: %s\n\n" % answer
end
end
I understand most of this code, but I have a problem with:
for sentence in [snippet, phrase]
I know that it is a "for" loop and it creates a "sentence" variable, but how does the loop know that it need to look in a key and value of hash "PHRASES"
And my second "wall" is:
question, answer = convert(snippet, phrase)
It looks like it creates and assigns "question" and "answer variables to the "convert" method with "snippet" and "phrase" parameters... again how does it assigns "question" to a key and answer to a value.
I know that this is probably very simple but as for now it blocks my mind :(
For your first question about the for-loop:
Look at where the for-loop is defined. It's inside the convert() method, right? And the convert() method is passed two arguments: one snippet and one phrase. So the loop isn't "looking" for values in the PHRASES hash, you are the one supplying it. You're using the method's arguments.
For your second question about assignment:
In Ruby we can do something called "destructuring assignment". What this means is that we can assign an array to multiple variables, and each variable will hold one value in the array. That's what's happening in your program. The convert() method returns a two-item array, and you're giving a name (question and answer) to each item in the array.
Here's another example of a destructuring assignment:
a, b, c = [1, 2, 3]
a # => returns 1
b # => returns 2
c # returns 3
Try this out in IRB and see if you get the hang of it. Let me know if I can help clarify anything, or if I misunderstood your question. You should never feel bad about asking "simple" questions!
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s this &block in Ruby? And how does it get passes in a method here?
I dont Understand the &block part, what does it do?
here is an example:
def method_missing(method_name, *args, &block)
#messages << method_name
#object.send method_name, *args, &block
end
Blocks give you an opportunity to state a callback to pass on to a method.
The & is key here - like #pst mentioned, it "promotes" the block to a Proc and binds the Proc to the variable with the given name.
With &
def time(&block)
puts block
end
time
# => nil
time { foo }
# => #<Proc:0x00029bbc>
Without &
def time(block)
puts block
end
time { foo }
# => ArgumentError: wrong number of arguments (0 for 1)
# Because & isn't included, the method instead expected an arguement,
# but as a block isn't a arguement an error is returned.
Answering "And how would I pass it to another method?" comment by Brian:
Like this:
def compose init_value, n=2, &b
if n==0 then init_value else
b.call( compose init_value, n - 1, &b )
end
end
compose 2 do |n| n * n end
#=> 16
compose 2, 4 do |n| n * n end
#=> 65536
compose 2, 4 do |n| n * 0.5 end
#=> 0.125
This is a recursive method that recursively applies the same block to a number several times. Here, the block packaged into b argument gets called, but at the same time it is passed on recursively to compose method, while n argument is decremented by 1. In the same way, b could be passed to any method, like map, reduce, anything.
Whereas, should you not need to pass the block to another method, you could simply use yield:
def apply_block_to_1_2_3
return yield( 1 ), yield( 2 ), yield( 3 )
end
apply_block_to_1_2_3 { |n| n * n }
#=> [1, 4, 9]
May the force be with you.
It converts the block to a proc object that can be passed on to another method.
when you call a method with a block, there are 2 ways to use that block:
call yield inside method
convert it into a Proc object by prepending & to it
with second way you can pass it to another method.
so in your case it transforms the given block into a Proc and calling method_name with it.
think of it as you can pass a block just like any argument.