Ruby Unidentified Method for nil No Method Error - ruby

I'm attempting to run this code:
def get_linedict(filename,source)
`dwarfdump -l #{source} > dwarfline.txt`
linefile = File.new("dwarfline.txt","r")
match = false
linefile.readlines.each do |line|
puts line
if /uri:/ =~ line
file = line.match(/.*\/(.*)"/)[1]
if file == filename
match = true
end
puts file
puts match
end
end
And when I do I get the following error:
assn4.rb:12:in `block in get_linedict': undefined method `[]' for nil:NilClass (NoMethodError)
from assn4.rb:9:in `each'
from assn4.rb:9:in `get_linedict'
from assn4.rb:126:in `block in <main>'
from assn4.rb:80:in `each'
from assn4.rb:80:in `<main>'
If I change my each loop to only print the lines it's reading, it works fine. As I understand it, the error I'm getting comes from something being nil which shouldn't be, but if that error is coming from the each loop, why am I able to print out the file?

I guess you first have to ask if line.match gets something, before calling an element of the desired array.
line.match(/.*\/(.*)"/)[1]

When you call line.match(/.*\/(.*)"/) the result is nil. Then you attempt to access nil as an Array. That is when you get undefined method []' for nil:NilClass.
And as for this part of your question
but if that error is coming from the each loop, why am I able to print out the file?
The each loop is causing your code to fail and halt when the error occurs. Since you are attempting to print file after the errors, you are actually not printing out file on that iteration of the loop.
Be aware that line might not be nil. Your regular expression is probably just not covering all the cases you think it is, so one of the match calls is failing and returning nil.

Related

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

Errors in my ruby script

I am getting an error I don't understand. It runs how I intended but throws an error at the end. I am still new to ruby but I know it has something to do with my for loops.
This is my code
nums = Array.new(24){Array.new(80){'X'}}
system('cls')
for i in 0..24
for j in 0..79
print nums[i][j]
end
end
And this is the error messages
K:/Ruby 2/RubyInvaders.rb:5:in block (2 levels) in <main>': undefined method `[]' for nil:NilClass (NoMethodError)
from K:/Ruby 2/RubyInvaders.rb:4:in each'
from K:/Ruby 2/RubyInvaders.rb:4:in block in <main>'
from K:/Ruby 2/RubyInvaders.rb:3:in each'
from K:/Ruby 2/RubyInvaders.rb:3:in <main>'
Its ok to offer better ways to do this but I would also like to understand why I am getting this error
You are creating an array with 24 elements and then a loop with 25 iterations. When you try to print the 25th iteration of that loop, the array position doesn't exist. If you change for i in 0..24 to for i in 0..23, the error should be addressed:
nums = Array.new(24){Array.new(80){'X'}}
system('cls')
for i in 0..23
for j in 0..79
print nums[i][j]
end
end
To amplify on Jon's comment, ruby ranges created with the ... operator are exclusive and won't use the highest specified value (as opposed to the .. operator, which is inclusive).
And--while your approach to looping is valid--it's not idiomatic for ruby. Something like this would be more common:
nums = Array.new(24){Array.new(80){'X'}}
system('cls')
(0..23).each do |i|
(0..79).each do |j|
print nums[i][j]
end
end
When i is 24, nums[i] is nil, and you are calling [] on it.

New to Ruby: Defining Methods

I'm trying to teach myself Ruby. I don't know anyone who knows it, so I don't have anyone to help with my very simple, perhaps annoying problems. I'm running the following code and getting the following error:
def simon_says (command)
def echo (param)
puts "#{param}"
end
end
The error:
PS R:\learn_ruby\03_simon_says> rake
(in R:/learn_ruby)
You must use ANSICON 1.31 or later (http://adoxa.3eeweb.com/ansicon/) to use colour on Windows
Simon says
echo
should echo hello (FAILED - 1)
Failures:
1) Simon says echo should echo hello
Failure/Error: echo("hello").should == "hello"
NoMethodError:
undefined method `echo' for #RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x2fb5690>
# ./03_simon_says/simon_says_spec.rb:19:in `block (3 levels) in <top (required)>'
Finished in 0.003 seconds
1 example, 1 failure
The Rspec code can be found here (Github): simon_says_spec.rb
I just really have no idea what's wrong. Why would it say 'echo' is undefined? It looks defined to me. I also tried just outputting "hello" itself instead of the method parameter (param). Same error. All help appreciated. Also, if anyone knows of a more level appropriate place I can get this kind of help, it'd be nice.
Your program says the following:
Define a method called simon_says. When that function is executed, it should define a method called echo.
Thus, before you invoke simon_says(), echo does not exist:
echo("foo")
# NoMethodError
simon_says("whatever")
# => nil
echo("bar")
# bar
# => nil
Now, I do not know why you wrapped def echo inside def simon_says, so I can't really offer any helpful advice as to what you should be doing instead of what you now are.
Looking to your spec, I guess simon_says is class. It is not method. You are defining method inside method. Try this
class SimonSays
def echo params
puts "#{params}"
end
end

NoMethodError .to_i ruby

A basic code in ruby that isn't working for me.... The error specifies
NoMethodError (undefined method `to_i' for
row = row.split(",").map { |x| x.to_i }
EDIT:
NoMethodError (undefined method `to_i' for [["123,123,123,"]]:Array):
app/controllers/sessions_controller.rb:21:in `import'
app/controllers/sessions_controller.rb:20:in `each'
app/controllers/sessions_controller.rb:20:in `import'
app/controllers/sessions_controller.rb:17:in `each'
app/controllers/sessions_controller.rb:17:in `import'
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.7ms)
Rendered /Library/Ruby/Gems/1.8/gems/actionpack-3.2.11/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (8.2ms)
you're receiving that error because you're calling the method .to_i on an array, which is wrong since that method is of the String class, source :http://www.ruby-doc.org/core-2.1.0/String.html#method-i-to_i
So in order to fix this we need to take that string from the array so we can turn it into an integer, remember that you started with an array containing an array, so that's why I'm calling .pop twice:
row = [["123, 123, 123"]]
string_of_numbers = row.pop.pop
string_of_numbers.split(",").map {|x| x.to_i }
If it feels too odd try to play with it on irb, that's usually how I try to sort these kinds of things out, don't forget to always refer to the official documentation

Ruby. Mocking in RSpec

I have a problem with mocking. I have class DistanceMatrix and I would
like to indicate which method form_matrix was called in if/else
statement. I need to use mocha and RSpec. Any ideas?
class DistanceMatrix
def initialize(*args)
if args[0].class == String
form_matrix(get_data_from_yaml(args[0], args[1]))
elsif args[0].class == Array || args[0] == nil
form_matrix(get_data_from_db(args[0]))
end
end
def form_matrix(...)
...
end
end
it tried:
describe DistanceMatrix, "when mocking ..." do
it "should do call form_matrix" do
DistanceMatrix.any_instance.expects(:form_matrix).with([1]).once
DistanceMatrix.any_instance.expects(:get_data_from_yaml).with("file_name.yml").once.returns([1])
DistanceMatrix.new("file_name.yml")
end
end
but got error:
Failures:
1) DistanceMatrix when mocking ... should do call form_matrix
Failure/Error: DistanceMatrix.new("file_name.yml")
unexpected invocation: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml', nil)
unsatisfied expectations:
- expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml')
- expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.form_matrix([1])
satisfied expectations:
- allowed any number of times, already invoked once: #<DistanceMatrix:0x9e48b40>.get_optimal_route(any_parameters)
- allowed any number of times, already invoked once: #<Database::Distances:0x9d59798>.load_distances(any_parameters)
# ./distance_matrix.rb:18:in `initialize'
# ./tsp_algorithm_spec.rb:253:in `new'
# ./tsp_algorithm_spec.rb:253:in `block (2 levels) in <top (required)>'
Finished in 0.25979 seconds
I found that in RSpec we should use not .expects() but .should_receive(), so I tried:
describe DistanceMatrix, "when mocking ..." do
it "should do call form_matrix" do
DistanceMatrix.any_instance.should_receive(:form_matrix).with([1])
DistanceMatrix.any_instance.should_receive(:get_data_from_yaml).with("file_name.yml").and_return([1])
DistanceMatrix.new("file_name.yml")
end
end
but got new failure:
Failures:
1) DistanceMatrix when mocking ... should do call form_matrix
Failure/Error: DistanceMatrix.any_instance.should_receive(:form_matrix).with([1])
(#<Mocha::ClassMethods::AnyInstance:0x96356b0>).form_matrix([1])
expected: 1 time
received: 0 times
# ./tsp_algorithm_spec.rb:251:in `block (2 levels) in <top (required)>'
Finished in 0.26741 seconds
I only have experience with using Mocha and not RSpec, but looking at the Mocha failure message, the key parts are these :-
unexpected invocation: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml', nil)
unsatisfied expectations:
- expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml')
If you look at the ends of these lines, you will notice that get_data_from_yaml is not being called with the expected parameters. It is being called with ('filename.yml', nil) and not ('filename.yml') as expected.
This is happening because when you call DistanceMatrix.new("file_name.yml") in your test with only one argument and then inside DistanceMatrix#initialize DistanceMatrix#get_data_from_yaml is being called with (args[0], args[1]) and since args is a single element array, args[1] will be nil.
Maybe this isn't how you expected Ruby to work, but the following demonstrates this behaviour :-
def foo(*args)
puts "args[0]=#{args[0].inspect}; args[1]=#{args[1].inspect}"
end
foo("string") # => args[0]="string"; args[1]=nil
DistanceMatrix.any_instance.expects(:form_matrix).with("String") # => supply the correct string param
or
DistanceMatrix.any_instance.expects(:form_matrix).with([]) # => supply the correct array param
I'm not sure what your get_data_from_db and get_data_from_yaml methods are doing, but you should be able to control those inputs as well to verify the correct arguments are being supplied to form_matrix.
EDITED
You'll have to use DistanceMatrix.any_instance instead of mocking on an instance variable because you're trying to mock something in the initializer. Also, in case its unclear, you'll need to actually make the appropriate method call after you set up the mock in the lines above, e.g.
DistanceMatrix.new("SomeString")
EDITED
it "should do call #form_matrix with proper arguments" do
DistanceMatrix.any_instance.expects(:form_matrix).with([1])
DistanceMatrix.any_instance.expects(:get_data_from_yaml).with("foo").returns([1])
DistanceMatrix.new("foo")
end

Resources