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

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)

Related

Ruby - undefined local variable or method `_1'

I'm getting the error undefined local variable or method '_1' for main:Object when I run the following code. Any idea why I'm getting this error? and how can I store the result in a variable.
result="-e hostname=webserver001 -e username=root -e password=testing123"
p result.scan(/\w+=\w+/)
.map { _1.split("=") }
.to_h
Error:
Traceback (most recent call last):
2: from main.rb:4:in `<main>'
1: from main.rb:4:in `map'
main.rb:4:in `block in <main>': undefined local variable or method `_1' for main:Object (NameError)
exit status 1
You're probably running an older version of ruby - the numbered parameters for blocks have been available in ruby since 2.7 - see https://www.bigbinary.com/blog/ruby-2-7-introduces-numbered-parameters-as-default-block-parameters
You can make it work on older version by using
p result.scan(/\w+=\w+/)
.map { |s| s.split("=") }
.to_h

Why this simple ruby code does not work in the commandline, but does when pasting it in irb

I have the following code:
sample_code.rb
class Foo
def bar
Timeout.timeout(0.5){
puts "Interupt this if it takes longer then 0.5 seconds"
}
end
end
foo = Foo.new()
foo.bar
The example above works when you paste it in irb,
but when you place it in a script and run it like this:
ruby ./sample_code.rb
It will give the following error.
Traceback (most recent call last):
1: from ./irb_works_ruby_dont.rb:11:in `<main>'
./irb_works_ruby_dont.rb:4:in `bar': uninitialized constant Foo::Timeout (NameError)
Is this a Timeout issue? Does irb load some modules that the normal ruby command doesn't? How to make the code work when run as a script?
The most likely explaination is that IRB requires Timeout when it starts up the REPL - but your script file is being executed before that happens. You can fix it by simply requiring it:
require 'timeout'
class Foo
def bar
Timeout.timeout(0.5){
puts "Interupt this if it takes longer then 0.5 seconds"
}
end
end
foo = Foo.new
foo.bar

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) }

Byebug does not update local variable on Ubuntu

Here's my code:
# please_just_work.rb
require 'bundler/setup'
Bundler.require
byebug
puts "a = #{a}"
Inside the byebug session I set the value of a, but it remains undefined:
[1, 5] in /home/paper/tmp/debug.rb
1: require 'bundler/setup'
2: Bundler.require
3:
4: byebug
=> 5: puts "a = #{a}"
(byebug) a = 1
1
(byebug) continue
Traceback (most recent call last):
please_just_work.rb:5:in `<main>': undefined local variable or method `a' for main:Object (NameError)
I'm running Ubuntu 18.04
Turns out I had to use #a instead of a. I did not find this in the documentation, so I'll leave the answer here for whoever faces this same issue.

How to run a file in pry that takes arguments

I can start a pry session of a command line app like this
pry -r ./todo.rb
However, if I want to call the list function
pry -r ./todo.rb list
I'm getting an error message.
Without pry, I call the list function
ruby todo.rb list
This is the error message
/Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/repl_file_loader.rb:16:in `initialize': No such file: /Users/michaeljohnmitchell/Sites/todo/bin/list (RuntimeError)
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/pry_class.rb:161:in `new'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/pry_class.rb:161:in `load_file_through_repl'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/cli.rb:162:in `block in <top (required)>'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/cli.rb:65:in `call'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/cli.rb:65:in `block in parse_options'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/cli.rb:65:in `each'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/lib/pry/cli.rb:65:in `parse_options'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/gems/pry-0.9.10/bin/pry:16:in `<top (required)>'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/bin/pry:19:in `load'
from /Users/michaeljohnmitchell/.rvm/gems/ruby-1.9.2-p290#global/bin/pry:19:in `<main>'
Source Code
TODO_FILE = 'todo.txt'
def read_todo(line)
line.chomp.split(/,/)
end
def write_todo(file,name,created=Time.now,completed='')
file.puts("#{name},#{created},#{completed}")
end
command = ARGV.shift
case command
when 'new'
new_task = ARGV.shift
File.open(TODO_FILE,'a') do |file|
write_todo(file,new_task)
puts "Task added."
end
when 'list'
File.open(TODO_FILE,'r') do |file|
counter = 1
file.readlines.each do |line|
name,created,completed = read_todo(line)
printf("%3d - %s\n",counter,name)
printf(" Created : %s\n",created)
unless completed.nil?
printf(" Completed : %s\n",completed)
end
counter += 1
end
end
when 'done'
task_number = ARGV.shift.to_i
binding.pry
File.open(TODO_FILE,'r') do |file|
File.open("#{TODO_FILE}.new",'w') do |new_file|
counter = 1
file.readlines.each do |line|
name,created,completed = read_todo(line)
if task_number == counter
write_todo(new_file,name,created,Time.now)
puts "Task #{counter} completed"
else
write_todo(new_file,name,created,completed)
end
counter += 1
end
end
end
`mv #{TODO_FILE}.new #{TODO_FILE}`
end
Update
when I try
pry -r ./todo.rb -e list
I'm getting the following error
NameError: undefined local variable or method `list' for main:Object
From pry --help:
-e, --exec A line of code to execute in context before the session starts
So, if your list method is defined on main (if you don't know, it probably is), then you can do this:
pry -r ./todo.rb -e list
Update
Pry doesn't let you pass in arguments for scripts it loads (or at least it isn't documented). But all is not lost, you can call pry from your script. Just drop this at wherever you want to inspect:
require 'pry'; binding.pry
This will spawn a pry session that has access to all the local variables and methods.
I think you can use:
ruby -rpry ./todo.rb -e list

Resources