Simple ruby code demonstrating default arguments is throwing name/method error - ruby

Seems pretty straightforward. Trying to write a simple code that has a default argument. This throws an error with a name error and method error. Code should be able to take any argument and print the arg and if not arg given print "meat".
Any help why its throwing errors?
def meal_choice( meal = "meat")
puts "#{meal}"
end
Failures:
1) #meal_choice should default to meat
Failure/Error: expect(meal_choice).to eq("meat")
NameError:
undefined local variable or method `meal_choice' for #<RSpec::ExampleGroups::MealChoice:0x007fb4ec159188>
# ./spec/meal_choice_spec.rb:3:in `block (2 levels) in <top (required)>'
2) #meal_choice should allow you to set a meal
Failure/Error: expect(meal_choice("vegan")).to eq("vegan")
NoMethodError:
undefined method `meal_choice' for #<RSpec::ExampleGroups::MealChoice:0x007fb4ec14b0d8>
# ./spec/meal_choice_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00125 seconds (files took 0.12294 seconds to load)
2 examples, 2 failures
Failed examples:
rspec ./spec/meal_choice_spec.rb:2 # #meal_choice should default to meat
rspec ./spec/meal_choice_spec.rb:6 # #meal_choice should allow you to set a meal

It is a working code:
[1] pry(main)> def meal_choice( meal = "meat")
[1] pry(main)* puts "#{meal}"
[1] pry(main)* end
#=> :meal_choice
[2] pry(main)> meal_choice
#=> meat
#=> nil
[3] pry(main)> meal_choice(:sdgsdg)
#=> sdgsdg
#=> nil
You must be having a typo in the method call or wrongly calling a method.

You need to make the method do the work without puts:
def meal_choice (meal = "meat")
meal
end

Related

How to fix a NoMethodError :undefined method `<<' for nil:NilClass

I have 3 error messages which I believe all relate to one thing - me calling a method on an object that has not been defined properly.
I've checked over for typos, white spacing, syntax, naming. I'm following the same process as other methods in this program which all tested OK.
I've narrowed the loop down and believe the issue is here:
def add(param)
#param << param
Heres the code in full context:
class Todo
def initialize(param)
#param = param
end
def text
return #param
end
end
class TodoList
def initialize
#item_list = []
end
def add(param)
#param << param
end
def print
#item_list.each do |param|
puts "* #{param.text}" #=> .text?
end
end
end
Error Messages:
Here are the error messages I'm trying to resolve. As I mentioned earlier they all look to be pointing to a method I've not defined properly but I've not yet been able to work out why that may be.
1) Q1. Todo list TodoList adding todos adds a todo without raising an error
Failure/Error: expect { todo_list.add(todo) }.to_not raise_error
expected no Exception, got #<NoMethodError: undefined method `<<' for nil:NilClass> with backtrace:
# ./questions/question_1.rb:43:in `add'
# ./spec/question_1_spec.rb:31:in `block (5 levels) in <top (required)>'
# ./spec/question_1_spec.rb:31:in `block (4 levels) in <top (required)>'
# ./spec/question_1_spec.rb:31:in `block (4 levels) in <top (required)>'
2) Q1. Todo list TodoList printing todos one todo prints a single todo with a bullet point
Failure/Error: todo_list.add(todo)
NoMethodError:
undefined method `<<' for nil:NilClass
# ./questions/question_1.rb:43:in `add'
# ./spec/question_1_spec.rb:41:in `block (5 levels) in <top (required)>'
3) Q1. Todo list TodoList printing todos many todos prints the todos, separated by newlines
Failure/Error: todo_list.add(todo_1)
NoMethodError:
undefined method `<<' for nil:NilClass
# ./questions/question_1.rb:43:in `add'
# ./spec/question_1_spec.rb:59:in `block (5 levels) in <top (required)>'
Thanks!
ruby do not know what #param is in your TodoList class, you have to initialize it in your constructor like this #param = [] that fix your issue
By default instance variables are initialized to nil, hence the error. So in your TodoList class, you need to initialize #param to an object that can respond to <<, which in your own case, is an array []
class TodoList
def initialize
#param = []
end
end

Unexpected Method Call

I'm using mongomapper to store pages in a db, and I index them first. In the index method, I loop through each word, and check to see if it is already in the words hashmap. If not, I add an empty array to the hash, then push its location to the array.
def index_words
#words = self.body.split(" ")
#words.each_with_index do |word,i|
if self.words[word.stem].nil?
self.words[word.stem] = []
end
puts "Called from #{caller[0]}"
self.words[word.stem].push(i)
end
end
When I run this, I get an undefined method error, saying that self.words[word.stem] is nil. Furthermore, this method is actually being called from the loop, when it's only called once in the constructor:
def initialize(*args)
super
index_words
end
The error message is:
p = Page.new({author: 'Michael',url: 'michaelfine.me',title: 'Michael Fine',body: 'Body Text'})
called fromPage.rb:19:in `each'
NoMethodError: undefined method `push' for nil:NilClass
from Page.rb:24:in `block in index_words'
from Page.rb:19:in `each'
from Page.rb:19:in `each_with_index'
from Page.rb:19:in `index_words'
from Page.rb:14:in `initialize'
from (irb):103:in `new'
from (irb):103
from /Users/Michael/.rvm/rubies/ruby-1.9.3-p286/bin/irb:16:in `<main>'

Why do I get "Undefined method ::new" in simple classes?

I am writing an ATM-system-like socket/server solution. I would appreciate if someone could tell me what I'm missing. For some reason, I get the following error running my stub test suite:
# Running tests:
.E
Finished tests in 0.002411s, 829.4384 tests/s, 414.7192 assertions/s.
1) Error:
test_0001_connects_to_a_host_with_a_socket(AtmClient::connection):
NoMethodError: undefined method `new' for #<SpoofServer:0x9dce2dc #clients=[], #server=#<TCPServer:fd 5>>
/media/wildfyre/Files/Programming/KTH/progp/Atm/spec/client/SpoofServer.rb:12:in `start'
/media/wildfyre/Files/Programming/KTH/progp/Atm/spec/client/client_spec.rb:12:in `block (3 levels) in <top (required)>'
2 tests, 1 assertions, 0 failures, 1 errors, 0 skips
My minispec file is:
require_relative '../spec_helper.rb'
require_relative '../../lib/AtmClient.rb'
require_relative 'SpoofServer.rb'
describe AtmClient do
it "can be created with no arguments" do
AtmClient.new.must_be_instance_of AtmClient
end
describe 'connection' do
it "connects to a host with a socket" do
spoof = SpoofServer.new.start
client = AtmClient.new.connect
spoof.any_incoming_connection?.must_be true
spoof.kill
end
end
end
My SpoofServer file is:
require 'socket'
class SpoofServer
def initialize
end
def start
#clients = []
#server = TCPServer.new 1234
#listener_thread = new Thread do
#clients.add #server.accept
end
end
def any_incoming_connection?
#clients.size > 0
end
def kill
#listener_thread.exit
#clients.each {|c| c.close}
end
end
As you can read in the trace of the calls stack:
NoMethodError: undefined method `new' for #<SpoofServer:...>
/.../spec/client/SpoofServer.rb:12:in `start'
The error is inside the start method defined in SpoofServer.rb, at line 12, the wrong line is:
#listener_thread = new Thread do
That should be:
#listener_thread = Thread.new do
As you have written it, what you are actually doing is to calling the new method passing the Thread class as argument. Since no new method is defined for instances of the SpoofServer class you get the NoMethodError exception.
In body of instance method SpoofServer#start, you can't call the class method SpoofServer.new by new.

Confusion with IRB output in Ruby when object#initialize is overloaded

What I actually trying to see when no 'initialize' method is given to an class definition then the class as you said should call the "Object#initialize",which here I tried to customize and see if it has been called or not. With that approach I reached to a conclusion(although that's wrong), when I typed "ob = A .new" that yes I can overload the Object#initialize method.But all has been ended up with the below exception. Then I thought I did something wrong in my customization.So I tried to create the object creation within an exception block and when I typed "begin" and pressed "ENTER" - i got the same error.
>> class A
>> def Object.new initialize
>> p "hi"
>> rescue
>> end
>> end
=> nil
>> begin # <~~~ Here I have pressed on ENTER
"hi" #<~~~~ How was it print out?
/usr/lib/ruby/1.9.1/irb/ruby-token.rb:94:in `Token': undefined method `set_backtrace' for "hi":String (NoMethodError)
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:348:in `block in lex_init'
from /usr/lib/ruby/1.9.1/irb/slex.rb:236:in `call'
from /usr/lib/ruby/1.9.1/irb/slex.rb:236:in `match_io'
from /usr/lib/ruby/1.9.1/irb/slex.rb:221:in `match_io'
from /usr/lib/ruby/1.9.1/irb/slex.rb:75:in `match'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:286:in `token'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:262:in `lex'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:233:in `block (2 levels) in each_top_level_statement'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
from /usr/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
from /usr/lib/ruby/1.9.1/irb.rb:70:in `block in start'
from /usr/lib/ruby/1.9.1/irb.rb:69:in `catch'
from /usr/lib/ruby/1.9.1/irb.rb:69:in `start'
from /usr/bin/irb:12:in `<main>'
#ubuntu:~$
Now my questions are -
How has the "hi" been printed?
What is the cause of the error as printed above?
If such initialize definition is not allowed,then why has the error not come after I ended with the class definition?
EDIT
As per #casper I tried below:
>> def Object.new
>> p "hi"
>> end
=> nil
>> begin
/usr/lib/ruby/1.9.1/irb/ruby-token.rb:96: stack level too deep (SystemStackError)
But here no "hi" printed back.
So what made the "hi" to print back in the first case?
What exactly are you trying to do? You just redefined Object.new, so there is no surprise you make everything go haywire.
You can basically get the same effect by just:
>> def Object.new
>> end
>> [press enter]
KABOOM
The reason "hi" is printed is that someone just called Object.new, probably the irb REPL loop, and it expected an object, but instead it gets gobledygook.
You can also try this:
def Object.new *args
p args
end
And you will see funny stuff. However you won't be able to quit irb or do anything useful with it after that. Again: you just broke Object.
To make some sense of it you should read this:
In Ruby, what's the relationship between 'new' and 'initialize'? How to return nil while initializing?
And then you can try this:
class Object
class << self
alias :old_new :new
end
end
Now you can do:
def Object.new *args
p args
old_new *args
end
This won't break new because you are still calling the old version of it. However you will now be printing out stuff every time someone calls new.

How do I debug an undefined method for nil class error?

I'm trying to create a classifier using the cardmagic classifier gem. This is my code:
require 'classifier'
classifications = '1007.09', '1006.03'
traindata = Hash["1007.09" => "ADAPTER- SCREENING FOR VALVES VBS", "1006.03" => "ACTUATOR- LINEAR"]
b = Classifier::Bayes.new classifications
traindata.each do |key, value|
b.train(key, value)
end
But when I run this I get the following error:
Notice: for 10x faster LSI support, please install http://rb-gsl.rubyforge.org/
c:/Ruby192/lib/ruby/gems/1.9.1/gems/classifier-1.3.3/lib/classifier/bayes.rb:27:in `block in train': undefined method `[]' for nil:NilClass (NoMethodError)
from c:/Ruby192/lib/ruby/gems/1.9.1/gems/classifier-1.3.3/lib/classifier/bayes.rb:26:in `each'
from c:/Ruby192/lib/ruby/gems/1.9.1/gems/classifier-1.3.3/lib/classifier/bayes.rb:26:in `train'
from C:/_Chris/Code/classifier/smdclasser.rb:13:in `block in <main>'
from C:/_Chris/Code/classifier/smdclasser.rb:11:in `each'
from C:/_Chris/Code/classifier/smdclasser.rb:11:in `<main>'
This is the source from the gem code:
# Provides a general training method for all categories specified in Bayes#new
# For example:
# b = Classifier::Bayes.new 'This', 'That', 'the_other'
# b.train :this, "This text"
# b.train "that", "That text"
# b.train "The other", "The other text"
def train(category, text)
category = category.prepare_category_name
text.word_hash.each do |word, count|
#categories[category][word] ||= 0
#categories[category][word] += count
#total_words += count
end
end
I am lost where to go to troubleshoot this error, what is the next step I should take?
Classifier::Bayes.new expects an exploded array of values, rather than a single parameter. For example, notice that the sample code uses:
b = Classifier::Bayes.new 'This', 'That', 'the_other'
rather than:
b = Classifier::Bayes.new ['This', 'That', 'the_other']
Pass in the splat version of your classifications array and it should work:
b = Classifier::Bayes.new *classifications

Resources