I have a code like this:
class Game
....
def end_game?
return win? || draw?
end
until end_game? do
....
end
end
I get this error:
undefined method `end_game?' for Game:Class (NoMethodError) at line 89 (that contains the until loop)
Related
I want to implement method which raises errors based on status code. I tried to implement this code:
def parse_response
system_errors = { }
(100..199).each do |current|
system_errors[current.to_s] = SystemError
end
(200..999).each do |current|
system_errors[current.to_s] = CommunicationError
end
return params_for_success if successful_response?
# pp system_errors
pp payment_response
if valid?
raise system_errors[340].new(technical_message, response_code)
else
raise errors.full_messages.join(";\n")
end
end
def successful_response?
response_code == RESPONSE_CODE_FOR_SUCCESS
end
def params_for_success
payment_response.dig(:payment_response)
end
.....
class CommunicationError < StandardError
def initialize(current_technical_message, response_code)
#response = response
end
end
But I get error parse_response': undefined methodnew' for nil:NilClass (NoMethodError)`
What is the proper way to raise error based on a range of numbers?
This line is causing the issue: system_errors[:error_class].new(technical_message, response_code)
Unlike Javascript, Ruby does not implicitly convert between types.
(200..999).each do |current|
system_errors[current.to_s] = CommunicationError
end
# now we have
system_errors["340"] == CommunicationError
So later when you do
raise system_errors[340].new(technical_message, response_code)
It uses the interger key 340 rather than the string key "340". Missing keys return nil, so you're calling nil.new. Decide on whether you're going to use integer or string keys and stick to it when inserting/reading.
Please explain me why i should define attr_list before attr? I can not understand why i should do that?
class Question
def self.attr_list
[:id, :name]
end
attr *self.attr_list
end
class Question
attr *self.attr_list
def self.attr_list
[:id, :name]
end
end
NoMethodError: undefined method `attr_list' for Question:Class
Unlike a def, a class is executed line by line immediately after you hit return to run your program:
class Dog
x = 10
puts x
end
--output:--
10
...
class Dog
puts x
x=10
end
--output:--
1.rb:2:in `<class:Dog>': undefined local variable or method `x'
In this line:
...
class Dog
def self.greet
puts 'hello'
end
greet
end
--output:--
hello
...
class Dog
greet
def self.greet
puts 'hello'
end
end
--output:--
1.rb:2:in `<class:Dog>': undefined local variable or method `greet'
Similarly, in this line:
attr *self.attr_list
you call self.attr_list(), yet the def comes after that line, so the method doesn't exist yet.
With a def, you can write this:
def do_math()
10/0
end
and you won't get an error until you call the method.
But by the time you create an instance of a class, all the code inside the class has already executed, creating the methods and constants that are defined inside the class.
By the way, you don't ever need to use attr because ruby 1.8.7+ has attr_accessor(reader and writer), attr_reader, and attr_writer.
The following Ruby code raises the confusing error "no id given" shown at the end. How do I avoid this problem?
class Asset; end
class Proxy < Asset
def initialize(asset)
#asset
end
def method_missing(property,*args)
property = property.to_s
property.sub!(/=$/,'') if property.end_with?('=')
if #asset.respond_to?(property)
# irrelevant code here
else
super
end
end
end
Proxy.new(42).foobar
#=> /Users/phrogz/test.rb:13:in `method_missing': no id given (ArgumentError)
#=> from /Users/phrogz/test.rb:13:in `method_missing'
#=> from /Users/phrogz/test.rb:19:in `<main>'
The core of this problem can be shown with this simple test:
def method_missing(a,*b)
a = 17
super
end
foobar #=> `method_missing': no id given (ArgumentError)
This error arises when you call super inside method_missing after changing the value of the first parameter to something other than a symbol. The fix? Don't do that. For example, the method from the original question can be rewritten as:
def method_missing(property,*args)
name = property.to_s
name.sub!(/=$/,'') if name.end_with?('=')
if #asset.respond_to?(name)
# irrelevant code here
else
super
end
end
Alternatively, be sure to explicitly pass a symbol as the first parameter to super:
def method_missing(property,*args)
property = property.to_s
# ...
if #asset.respond_to?(property)
# ...
else
super( property.to_sym, *args )
end
end
I have a class like this
require 'net/http'
class Foo
def initialize
#error_count = 0
end
def run
result = Net::HTTP.start("google.com")
#error_count = 0 if result
rescue
#error_count += 1
end
end
And this is a spec file for it.
require_relative 'foo'
describe Foo do
let(:foo){ Foo.new}
describe "#run" do
context "when fails 30 times" do
foo.instance_variable_set(:#error_count, 30)
end
end
end
And run rspec foo_spec.rb, then fails with this error.
foo_spec.rb:7:in `block (3 levels) in <top (required)>': undefined local variable or method `foo' for #<Class:0x007fc37410c400> (NameError)
How should I call instance_variable_set method in rspec?
Edit
I want to call send_error method if 30 times fails.
require 'net/http'
class Foo
def initialize
#error_count = 0
end
def run
result = Net::HTTP.start("google.com")
#error_count = 0 if result
rescue
#error_count += 1
send_error if #error_count >= 30
end
def send_error
end
end
And spec file to test that send_error is called when connection fails 30 times.
require_relative 'foo'
describe Foo do
let(:foo){ Foo.new}
describe "#run" do
context "when fails 30 times" do
it "should send error" do
foo.instance_variable_set(:#error_count, 30)
expect(foo).to receive(:send_error)
end
end
end
end
I don't know what you're trying to do, but I suspect it's not the right approach to do things.
However, your immediate problem is that you're not in the context of a test, so foo is undefined. You want to wrap your foo.instance_variable_set in a test construct - either an it or specify block, or a before :each, or something similar.
I have this snippet:
class MyClass
def self.callWithBlock (&block)
print block.blockVar
end
end
MyClass::callWithBlock do
blockVar = 'Hello'
end
which gives me an error:
in `callWithBlock': undefined method `blockVar' for #<Proc:0x000000017ed168#./block-test.rb:9> (NoMethodError)
from ./block-test.rb:9:in `<main>'
How to access this blockVar?
If you add binding at the end of the block, that would become the result of call-ing the block, and you can eval whatever local variables assigned in that block within the context of the binding.
class MyClass
def self.callWithBlock (&block)
print block.call.eval('blockVar')
end
end
MyClass::callWithBlock do
blockVar = 'Hello'
binding
end
# => Hello