Parens required or Ruby says: TypeError (class or module required) ... why? - ruby

I'm trying this in irb, Ruby version 3:
3.0.0 :001 > num = 42
=> 42
3.0.0 :002 > num.is_a?(Integer) && num > 10
=> true
3.0.0 :003 > num.is_a? Integer && num > 10
Traceback (most recent call last):
5: from /Users/kai/.rvm/rubies/ruby-3.0.0/bin/irb:23:in `<main>'
4: from /Users/kai/.rvm/rubies/ruby-3.0.0/bin/irb:23:in `load'
3: from /Users/kai/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>'
2: from (irb):3:in `<main>'
1: from (irb):3:in `is_a?'
TypeError (class or module required)
Why do I need the parentheses here:
v.is_a?(Integer)
?
How does the operator precedence work?
And why does Ruby generate such an arcane error message in this scenario?
With some digging I find the question answered previously here:
Ruby 'is_a?' class or module required (TypeError)
and the fundamental issue addressed here:
What's the precedence of method calls with and without parentheses?
which reference the official Ruby documentation:
https://ruby-doc.org/core-3.0.0/doc/syntax/precedence_rdoc.html
But I don't feel all my questions are answered. Anyone care to wrap all of this up cleanly?

Why do I need the parentheses here:
v.is_a?(Integer)
You need the parenthesis to specify what you are passing to the is_a? method. Without them, Ruby evaluates the entire Integer && num > 10 expression and passes that to the method.
How does the operator precedence work?
is_a? isn't an operator, so there's no precedence for it to follow. Expressions are evaluated before being passed to methods, that's all that's happening.
And why does Ruby generate such an arcane error message in this scenario?
Ruby is evaluating the expression Integer && num > 10 which gives true. This value is then being passed to num.is_a?. is_a? then gives a TypeError as it expects a class or module, not a boolean.

Related

ruby error of "block in initialize: uninitialized constant" but running well with irb

I have a ruby script as following:
class HashSet < Hash
def initialize
super { |hash, key| hash[key] = Set.new }
end
end
data = {}
data["hash"] ||= HashSet.new
data["hash"]["colors"].add "blue"
puts data
An error is raised when run this script:
$ ruby demo.rb
Traceback (most recent call last):
2: from demo.rb:9:in `<main>'
1: from demo.rb:9:in `[]'
demo.rb:3:in `block in initialize': uninitialized constant HashSet::Set (NameError)
But when I run it with irb, it runs well:
$ irb -r ./demo.rb
{"hash"=>{"colors"=>#<Set: {"blue"}>}}
What makes the difference and how can I fix the script?
Add this to the top of your script:
require "set"
Explanation:
Set is not part of the ruby core library. Rather, it is part of the ruby standard library.
In order to use Set, you must - somewhere - require the library explicitly.
As it happens, irb actually already requires set as part of its initialisation process:
$ irb
irb(main):001:0> Set
=> Set
$ ruby -e 'Set'
Traceback (most recent call last):
-e:1:in `<main>': uninitialized constant Set (NameError)

How to access element in array via command line in ruby?

Given a simple code in file test.rb:
def todo_list(todo_selector)
library = ["Get a cat", "Get a dog", "Build a fighting ring"]
puts "Your current step in todo-list is:\n#{library[todo_selector]}"
end
ARGV.each { |todo| todo_list(todo_selector) }
How am I able to call this method with an index via command line?
Normally I would use test.rb 1, but I am getting this error:
Traceback (most recent call last):
2: from test.rb:17:in `<main>'
1: from test.rb:17:in `each'
test.rb:17:in `block in <main>': undefined local variable or method `todo_selector' for main:Object (NameError)
Did you mean? todo_list
What am I doing wrong?
Try this way for one element, take care to convert String into Integer in order to access the Array by index.
selector = ARGV[0].to_i
todo_list(selector)
For an array of arguments: ARGV.each{ |i| todo_list(i.to_i) }

Test returns ArgumentError

I meant to type test and receive nil. However I receive this instead:
ArgumentError: wrong number of arguments (0 for 2..3)
from (irb):15:in `test'
from (irb):15
from /usr/bin/irb:12:in `<main>'
Does anyone know if I need to fix something?
I think this may be what you're after:
2.3.0 :003 > puts 'test'
test
=> nil

Ruby assignment vs expression modifier precedence [duplicate]

This question already has answers here:
I don't understand ruby local scope
(5 answers)
Closed 8 years ago.
I see the following behavior in both MRI 2.0 and jruby 1.7.16.1:
irb(main):001:0> a
NameError: undefined local variable or method `a' for main:Object
from (irb):1
from /usr/bin/irb:12:in `<main>'
irb(main):002:0> a = 2 unless true
=> nil
irb(main):003:0> a
=> nil
irb(main):004:0>
I expected a to remain undefined because = has higher precedence than unless. What am I missing?
a = 2 unless true is evaluated like this:
unless true
a = 2
end
precedence doesn't come into play because its a different scope.
a #=>NameError: undefined local variable or method `a' for main:Object
The parser can not decide if this is a local variable OR METHOD, as the error says.
a = 2 unless true
Here the parser is able to recognize this is meant to be a variable, and it is defined (not initialized). It will be initialized if the statement is executed. Uninitialized variables evaluate to nil.

Ruby equivalent operators at "OrElse" and "AndAlso" of Vb.net

There are operators in Ruby similar to "OrElse"and "AndAlso" in VB.NET?
For example in Ruby NoMethodError exception is raised when active_record is nil:
if active_record.nil? || active_record.errors.count == 0
...
end
In VB.net i can do:
If active_record Is Nothing OrElse active_record.errors.count = 0
...
End
That does not generate an exception because it is only checked the first expression
In this case there will be no exception raised (because only the first term in || will be evaluated). However you might be interested in reading about Object#try from ActiveSupport, which can be helpful when dealing with objects that can be nil.
in ruby, there is a big difference between something that is nil and something that is undefined. Considering the following, from IRB:
ruby-1.9.2-p0 :002 > active_record
NameError: undefined local variable or method `active_record' for main:Object
from (irb):2
from /Users/jed/.rvm/rubies/ruby-1.9.2-p0/bin/irb:16:in `<main>'
ruby-1.9.2-p0 :003 > active_record = nil
=> nil
ruby-1.9.2-p0 :004 > active_record.class
=> NilClass
ruby-1.9.2-p0 :006 > active_record.nil?
=> true
So, an object that is nil is an instance of NilClass and therefore responds to the message nil? will return true, but without declaring the variable (as in your code) Ruby doesn't know what you are calling.
A couple of options here:
Ruby's || operator is a strict operator, whereas the or keyword is less strict, so I don't know where the vb operation compares to these two or flow options.
you could use a neat little gem callled 'andand'
require 'andand'
active_record.andand.errors.count == 0
but, generally when you are dealing with this situation in rails, you would use another means to determine the situation above, consider:
#post = Post.new(:my_key => "my value") #=> an ActiveRecord object
if #post.valid?
# do something meaningful
else
puts #post.errors.full_messages.to_sentence
end
and if you mean to assign something based on if it possibly undefined, you would want to use memoization:
#post ||= Post.new
which will declare the object if undefined or use the existing object
Ruby || is short circuit evaluation operator, so it should evaluate only first condition, therefore your if should not raise any exception.
I assume active_record.nil? returns boolean true.

Resources