Override '+' method - ruby

In the process of understanding ruby, I was trying to overide '+' with a default argument value. Something like this.
class C
def something(a = 5)
puts "Received: #{a}"
end
def +(b = 10)
puts "Received: #{b}"
end
end
Now
x = C.new
x.something #=> Received: 5
x.something(88) #=> Received: 88
x.+ #=> IRB shows ? whereas I was expecting an output 'Received: 10'
Is this because of operator precedence?

Problem with IRB (look like it doesn't handle such cases). If you create separate .rb file and run it you will get expected output:
Received: 5
Received: 88
Received: 10

IRB is parsing the + and expecting a second parameter for the binary operation. If you provide parenthesis it works correctly:
x.+() #=> Received: 10

IRb uses a different parser than Ruby does. So, in some weird corner cases, IRb may parse code differently than Ruby. If you want to see whether something is valid Ruby or not, you should ask Ruby not IRb.
The reason for this is mainly that Ruby always parses the entire file at once, so it always knows when an expression ends. IRb on the other hand, has to "guess" every time when you press ENTER whether you simply want to continue the expression on a new line or whether you wanted to evaluate the expression as-is. As a result, IRb cannot just use the Ruby parser, it needs to have its own. And Ruby's grammar is so complex that writing your own parser is really really hard. That's why such bugs and corner cases pop up from time to time even in a piece of software as old and as widely used as IRb.

Related

Which is correct REPL or command-line?

when i write method missing in Object class i'm getting the output different in each interface.
the code is
class Object
def method_missing(hgh)
puts self
end
end
when i use REPL like irb, i get
when i use the command line, i get no error, any reasons would be helpful, thanks in advance
The tl;dr answer is that both are correct. Just more stuff happen in the REPL.
When you run the code from the command line like:
ruby script.rb
All that happens is that it's evaluated.
Whereas REPLs like IRB read your input, evaluate it and print it in a loop.
In this case evaluating your code literally broke the REPL and resulted in the subsequent print failing.
Now you may be a bit confused by this. "There is a print in both cases, I use puts!". The print I'm referring to here is the result that gets visualised after each evaluation. In this case the method definition result (=> :method_missing).
It might not only be the printing itself. It can be the ton of other under the hood code that the REPL has to execute to keep state like "what code was defined on which line" and so on.
Think of what you just did - you made it so that every object has every method possible to return nil. That is not just for the code you write in the REPL. It's for the code of the REPL itself as well.

How can I watch a variable in Ruby Pry?

I'm using Ruby 2.2.2, Pry and 'pry-byebug'. The continue statement removes any watched variables in have in pry-byebug:
[1] pry(main)> watch foo
Watching foo
watch: foo => 42
[2] pry(main)> watch
Listing all watched expressions:
1: foo => 42
[3] pry(main)> continue
[1] pry(main)> watch
No watched expressions
Losing them on every continue makes watched expressions pretty worthless. If I use next and step to the same point in the code instead, the watched expressions are still there; it's just the continue that causes the problem. At the moment I can't even find any documentation on the watch statement, so I don't know why this occurs.
More generally, I just want to print out the value of a set of expressions on every Pry prompt (or, perhaps, print them out if they've changed since the last time they were printed.) How can I achieve this in a Ruby debugger?
Using pry-moves you can use watch variable - this will display value of variable on each step.
You should be able to write a plugin that just shows the expressions after evaluating if that's exactly what you want.
Pry plugins
Which you could do something simple like
Pry.hooks.add_hook(:after_eval, "reporter") do |output, binding, pry|
$watch ||= []
$watch.each {|block| block.call}
end
$watch = [-> { puts "hello"}]
Or something along the lines of that, would report "hello" after each new evaluation. (this is untested however, currently on mobile)

Ruby REPL, determinate if a line it's part of a valid expression

I'm doing a Ruby REPL (just a hobby, won't be big and professional like pry).
I wrote a very simple REPL that works fine if the input it's just a single valid line of Ruby:
loop do
print "ruby> "
input = gets
puts "=> #{eval(input)}"
end
I want to support multiline inputs.
One approach that I'm thinking is to check for each input line if the code is a correct Ruby expression, part of a Ruby expression or invalid code.
valid_expression?("def foo; end") # => true, complete expression
valid_expression?("def foo") # => true, partial expression
valid_expression?("def ::foo") # => false
Anyway, I tried to understand other implementations1,2,3 but is really difficult/undocumented code. Maybe I can use RubyLex or Ripper.
Ideally, I'm interesting to use Ruby standard libraries without any external gem. It doesn't matter if only target for Ruby 2.x versions, but if there is a gem to do the work, I'll happy to use it.
Since you noticed that there is pry, you should look its source and learn from it. Actually, pry does internally use such method as you described. It is: MethodSource::CodeHelpers#complete_expression?.

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

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.

Resources