Is there a ruby method that just returns the value of a block?
What you're looking for is essentially the equivalent of let
in Lisp or OCaml — something that allows you to temporarily bind a value to an identifier without introducing a new variable into the larger scope. There isn't anything that lets you do such a thing with that syntax in Ruby. The equivalent Ruby would be:
lambda {|value| deck.index(value).tap {|index|
STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }.call 'A'
You could of course just write a method like:
def let(*values)
yield *values
end
Return the value from Ruby block
Use call
.
block.call
if block
takes arguments, then give arguments:
block.call(whatever_arguments)
n.times do block just returns value of n
Nope, I don't see how you inferred from those answers that .times
block should return anything. What it does is it runs specified block specified number of times, nothing more. Return values of the block are discarded. Will do if you want to, say, print "hello" to standard output N times or do some other work.
n.times do
puts 'hello'
end
If you expected N copies of "hello" string in an array, then there are other ways to achieve this. For example:
Array.new(n, 'hello')
n.times.map { 'hello' }
# and many others
Ruby - Array.find, but return the value the block
[1, 2, 3].detect { |i| i += 1; break i if i == 2 }
# => 2
[1, 2, 3].detect { |i| i += 1; break i if i == 10 }
# => nil
Using return keyword in Ruby block
Herein lies one of the primary differences between a block/Proc and a lambda/Method (the other primary difference would be arity). If you don't want a call to return
to exit the method, that would infer that you expect that block should be self-contained in its flow control, and be treated as an encapsulated method.
This description is essentially what a lambda is - an anonymous method. However, a standard ruby block is essentially an anonymous Proc, and takes nothing away from the flow control of the method.
As mentioned in the comments, you may be able to use next
to escape the block without returning control away from the method. 'May' because next
may just continue to the next item that the method iterator is passing to the block.
Related to this, see http://yehudakatz.com/2012/01/10/javascript-needs-blocks/ and Differences between Proc and Lambda
How to get the return value of the block passed to eval method?
You can return the result of eval to the block using yield
. You just had to yield
the value; thus I changed your yield
to yield eval code
. In the block you give to Sandbox.secure_eval
you have to then bind this result to a block variable. The result of secure_eval
will be the result of the block, like you wanted.
proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
yield eval code # <= This line changed
end
end
Sandbox.secure_eval('hoge = ["hoge", "fuga"]') { |hoge| hoge[0] }
# => "hoge"
Sandbox.secure_eval('2 ** 4') { |result| result - 5 }
# => 11
In response to your comment; it turns out that with the aid of Kernel#Binding, we can get it to work more or less like you wanted. It feels rather like a hack so use it with caution.
I use the Binding to evaluate the code, which will have access to all defined variables. In addition, I define a method_missing
for the Binding class so we can access the variables more easily. Without it, you would need to do eval('varname')
rather than just varname
. Per the comment of @hakcho who mentioned the monkey-patch solution that was in place is not ideal, I now use refinements which only locally changes the behavior of Binding (i.e., the method_missing implementation).
I have added an explicit block
parameter to your method, which I use with instance_eval
instead of yield
. We can then access the variables directly in the block.
require 'timeout'
module Sandbox
refine Binding do
def method_missing(meth, *args, &block)
self.eval(meth.to_s)
end
end
def self.secure_eval(code, timeout: 5, safe_level: 2, &block)
raise ArgumentError, 'please set call back by block' unless block_given?
proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
binding = binding()
binding.eval(code)
binding.instance_eval(&block)
end
end
proc.call
end
end
using Sandbox # Activate the refinement so we can use x, y, z directly
Sandbox.secure_eval('x = [1,2,3]; y = 0; z = { key: "Hello!" }') do
x[1] # => 2
y # => 0
z[:key] # => "Hello!"
end
Related Topics
Error Install Rubyracer with Error "Invalid Gem: Package Is Corrupt"
How to Remove Duplicates in a Hash in Ruby on Rails
How to Use Functions Like Concat(), etc. in Arel
Ruby Indented Multiline Strings
What Does +@ Mean as a Method in Ruby
How to Send an Http Put Request in Ruby
Convert a String of 0-F into a Byte Array in Ruby
Get Chromes Console Log via Ruby Webdriver
Make Rails Ignore Daylight Saving Time When Displaying a Date
Rails 4 How to Call Accessible_Attributes from Model
How to Convert Ppt to Images in Ruby
How to Mark a Cucumber Scenario as Pending
If 'Main' Is an Instance of 'Object', Why Can't I Call It
How to Redefine Fixnum's + (Plus) Method in Ruby and Keep Original + Functionality