Access to variable of last expression - ruby

As you may know, there's a special variable _ of last expression in REPL's like irb and pry.
But can I get the result of last expression from Ruby platform?
Because of Ruby's dynamic nature and flexible compiler/virtual machine, maybe it's possible to get it from the Ruby's guts.
So I can avoid to write construction like this:
def some_method
result = begin
# some code
end
# do something with result
result
end
P.S. tap is not a solution for me

Related

ruby cast method input variable as string in ruby irb

How would I coerce the behavior of irb to treat variable identifiers as strings when used in method signatures?
I am trying to create a irb based calculation tool and I want to reduce the typing of users who use this tool in the irb shell. Assume my users are not ruby programmers or know much about the syntax of ruby. The may have some facility with the command line.
I have a file
calculator.rb
inside this file is
def calculate(value, units)
... some logic
end
I instruct the user to fire up irb like so
irb -r path/to/calculator.rb
I instruct the user to type
calculate(10, inches)
get return value in irb
how can I do this without requiring the user to understand that they have to wrap the second parameter in quotation marks. In other words I don't want the user to have to type
calculate(10, "inches")
is it possible to cast the user input as a string instead of a variable identifier before it is passed to my method inside my script? Maybe what I want to do is not possible without fundamentally breaking irb shell?
If this is for non-programmers how about using puts and gets?
def calculate
puts "Which number would you like to convert?"
number = gets.to_i
puts "What do you want to convert it to?"
type = gets
# your conversion logic
puts result
end
You can actually do it the way you requested using method_missing. Any matching units will get converted to strings instead of raising exceptions.
SO_CALC_UNITS = %w[inches feet yards meters parsecs]
def method_missing(method)
if SO_CALC_UNITS.include?(method.to_s)
method.to_s
else
super(method)
end
end

Are "begin" and "end" reserved words or not?

I'm kind of confused about reserved words in Ruby.
"The Ruby Programming Language", co-authored by Matz, says that begin and end are reserved words of the language. They're certainly used syntactically to mark out blocks.
However, range objects in the language have methods named begin and end, as in
(1..10).end
=> 10
Now, testing this out, I find that, indeed, I can define methods named "begin" and "end" on objects, though if I try to name a variable "begin" it fails. (Here's a sample of using it as a method name, it actually works...:)
class Foo
def begin
puts "hi"
end
end
Foo.new.begin
So, I suppose I'm asking, what actually is the status of reserved words like this? I would have imagined that they couldn't be used for method names (and yet it seems to work) or that at the very least it would be terrible style (but it is actually used in the core language for the Range class).
I'm pretty confused as to when they're allowed to be used and for what. Is there even documentation on this?
Yes, they are reserved words. Yes, they can be used for method names. No, you can't call them without an explicit receiver. It's probably not a good idea anyway.
class Foo
def if(foo)
puts foo
end
end
Foo.new.if("foo") # outputs foo, returns nil
Update: Here's a quote from "The Ruby Programming Language", by Matz (the creator of Ruby) himself:
In most languages, these words would be called “reserved words” and
they would be never allowed as identifiers. The Ruby parser is
flexible and does not complain if you prefix these keywords with #,
##, or $ prefixes and use them as instance, class, or global variable
names. Also, you can use these keywords as method names, with the
caveat that the method must always be explicitly invoked through an
object.
When they are given in a form that is unambiguously a method call, you can use them. If you have a period in front of it .begin or have parentheses after is begin(), then it is unambiguously a method call. When you try to use it as a variable begin, it is ambiguous (in principle).
Actually, as Perry, notes, begin() might be tricky. I checked with irb with Ruby 1.9.3, and the following strange thing happens:
irb(main):001:0> def begin(foo)
irb(main):002:1> puts 'a'
irb(main):003:1> end
=> nil
irb(main):004:0> begin(3)
irb(main):005:1>
irb(main):006:1* end
=> 3
It is not defined, and what looks like a method call might be just a block returning the last-evaluated 3. But the lines around def begin(foo) remains mystery.

Ruby knows 'myvar' is a variable in myvar = 0 if false

I'm learning Ruby and I like playing with irb to discover new features and tricks. Today I was playing with variables and methods because I wanted to know which one took preference in front of the other one. Everything looked fine until I tried this:
def test
puts "hello"
end
test = "bye" if false
puts test
I was expecting this to return "hello" , but it doesn't. So, I suppose the parser is treating 'test' as a variable instead of as a method. I have two questions:
Is my assumption correct?
Is there any way to know if something is a variable or a method? Some method like test.is_variable?
test = "hello" if false
p test #=> nil
The local variable test is created anyway (with default value nil), and given that local variables overshadow methods with the same name, that's the value you get. Just an hour ago someone got bitten by a subtle variation of the theme. And don't you think this only happens with one-liner conditionals:
if false
test = "hello"
end
p test #=> nil
That's because Ruby defines variables when they are parsed (and not when they are executed).
There are at least two methods that help: methods and local_variables. I wouldn't recommend using them in real world programs, but they might be useful when learning Ruby.

What is the difference between these two method parameter definitions?

I'm starting to learn Ruby. I read that arguments where passed by reference to a method,
however I don't understand the difference between these two methods.
def print(text)
puts text
end
and
def print(*text)
puts text
end
Using a * means that we are passing a pointer like in C?
The *text is what's called the splat operator in Ruby. It basically means if you pass multiple arguments to the second print they will get slurped into the single text variable.
See The Splat Operator in Ruby
The * before a parameter name in a Ruby parameter list is used for variable length arguments, so they are similar to the ... in C/C++ for varargs.
def vlaFunc(*args)
puts args
end
vlaFunc(1,2,3)
# output is [1,2,3]
There are no pointers in Ruby, * in this context is generally referred to as the "splat" operator:
http://4loc.wordpress.com/2009/01/16/the-splat-operator-in-ruby/
http://theplana.wordpress.com/2007/03/03/ruby-idioms-the-splat-operator/
In this case the method can take an arbitrary number of arguments, which will be available in the array text.
First you have two nice methods started there. But I would say try to avoid using puts inside them. You don't need it anyway. A method will always yield the last statement evaluated. something = text would get the job done. And I don't need to answer now about the differences.
Your first two replies are very good there. But you may want to try something like this
j = *[] #=> nil in 1.8 but [] in 1.9
It's been the new kid on the block for a time now. Guess what it does?

How to get argument names using reflection

I would like to do some fairly heavy-duty reflection in Ruby. I want to create a function that returns the names of the arguments of various calling functions higher up the call stack (just one higher would be enough but why stop there?). I could use Kernel.caller, go to the file and parse the argument list but that would be ugly and unreliable.
The function that I would like would work in the following way:
module A
def method1( tuti, fruity)
foo
end
def method2(bim, bam, boom)
foo
end
def foo
print caller_args[1].join(",") #the "1" mean one step up the call stack
end
end
A.method1
#prints "tuti,fruity"
A.method2
#prints "bim, bam, boom"
I would not mind using ParseTree or some similar tool for this task but looking at Parsetree, it is not obvious how to use it for this purpose. Creating a C extension like this is another possibility but it would be nice if someone had already done it for me.
I can see that I'll probably need some kind of C extension. I suppose that means my question is what combination of C extension would work most easily. I don't think caller+ParseTree would be enough by themselves.
As far as why I would like to do this goes, rather than saying "automatic debugging", perhaps I should say that I would like to use this functionality to do automatic checking of the calling and return conditions of functions:
def add x, y
check_positive
return x + y
end
Where check_positive would throw an exception if x and y weren't positive. Obviously, there would be more to it than that but hopefully this gives enough motivation.
In Ruby 1.9.2, you can trivially get the parameter list of any Proc (and thus of course also of any Method or UnboundMethod) with Proc#parameters:
A.instance_method(:method1).parameters # => [[:req, :tuti], [:req, :fruity]]
The format is an array of pairs of symbols: type (required, optional, rest, block) and name.
For the format you want, try
A.instance_method(:method1).parameters.map(&:last).map(&:to_s)
# => ['tuti', 'fruity']
Of course, that still doesn't give you access to the caller, though.
I suggest you take a look at Merb's action-args library.
require 'rubygems'
require 'merb'
include GetArgs
def foo(bar, zed=42)
end
method(:foo).get_args # => [[[:bar], [:zed, 42]], [:zed]]
If you don't want to depend on Merb, you can choose and pick the best parts from the source code in github.
I have a method that is quite expensive and only almost works.
$shadow_stack = []
set_trace_func( lambda {
|event, file, line, id, binding, classname|
if event == "call"
$shadow_stack.push( eval("local_variables", binding) )
elsif event == "return"
$shadow_stack.pop
end
} )
def method1( tuti, fruity )
foo
end
def method2(bim, bam, boom)
foo
x = 10
y = 3
end
def foo
puts $shadow_stack[-2].join(", ")
end
method1(1,2)
method2(3,4,4)
Outputs
tuti, fruity
bim, bam, boom, x, y
I'm curious as to why you'd want such functionality in such a generalized manner.
I'm curious how you think this functionality would allow for automatic debugging? You'd still need to inject calls to your "foo" function. In fact, something based on set_trace_func is more able to be automatic, as you don't need to touch existing code. Indeed this is how debug.rb is implemented, in terms of set_trace_func.
The solutions to your precise question are indeed basically, as you outlined. use caller + parsetree, or open the file and grab the data that way. There is no reflection capability that I am aware of that will let you get the names of arguments. You can approve upon my solution by grabbing the associated method object and calling #arity to then infer what of local_variables are arguments, but though it appears the result of that function is ordered, I'm not sure it is safe to rely on that. If you don't mind me asking, once you have the data and the interface you describe, what are you going to do with it? Automatic debugging was not what initially came to mind when I imagined uses for this functionality, although perhaps it is failing of imagination on my part.
Aha!
I would approach this differently then. There are several ruby libraries for doing design by contract already, including ruby-contract, rdbc, etc.
Another option is to write something like:
def positive
lambda { |x| x >= 0 }
end
def any
lambda { |x| true }
end
class Module
def define_checked_method(name, *checkers, &body)
define_method(name) do |*args|
unless checkers.zip(args).all? { |check, arg| check[arg] }
raise "bad argument"
end
body.call(*args)
end
end
end
class A
define_checked_method(:add, positive, any) do |x, y|
x + y
end
end
a = A.new
p a.add(3, 2)
p a.add(3, -1)
p a.add(-4, 2)
Outputs
5
2
checked_rb.rb:13:in `add': bad argument (RuntimeError)
from checked_rb.rb:29
Of course this can be made much more sophisticated, and indeed that's some of what the libraries I mentioned provided, but perhaps this is a way to get you where you want to go without necessarily taking the path you planned to use to get there?
if you want the value for the default values, too, there's the "arguments" gem
$ gem install rdp-arguments
$ irb
>> require 'arguments'
>> require 'test.rb' # class A is defined here
>> Arguments.names(A, :go)
In fact, the method you describe clearly fails to distinguish arguments from local variables while also failing to work automatically
That's because what you're trying to do is not something which is supported. It's possible (everything is possible in ruby), but there's no documented or known way to do it.
Either you can eval the backtrace like what logan suggested, or you can bust out your C compiler and hack sourcecode for ruby. I'm reasonably confident there aren't any other ways to do this.

Resources