`parse_response': undefined method `new' for nil:NilClass (NoMethodError) - ruby

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.

Related

return values for Ruby setter

I read that attr_writer :age is short hand for this:
def age=(value)
#age = value
end
So I created a class with a function like this:
def age=(value)
if #age == -1
#age = value
return true
end
return false
end
Then I wanted to call it like this in another place:
rv = Foo.age(1)
# do stuff with rv
But I get an error:
ArgumentError:
wrong number of arguments (given 1, expected 0)
Anyway, I can do something like Foo.age = 1 but that doesn't give me control over the return value. What is the proper idiomatic Ruby here?
how about a wrapper method that do 2 steps: first it'll try to set value age= then validate that age == new_value and return, so that you could know that the setter is success or not.
class Foo
def age=(val)
# do a bunch of complicated networking that was non-deterministic
# return true/false
end
def set_age(val)
self.age = val
#age == val
end
end
foo = Foo.new
result = foo.set_age(1)
you could also replace true/false by raising an error, then you could wrap setter into a begin-end block
class Foo
def age=(val)
# do a bunch of complicated networking that was non-deterministic
raise RuntimeError
end
end
result = begin
foo.age = 1
true
rescue => e
false
end

Getting this 'Undefined method 'fetch''

I am learning ruby and getting this error
My code:
class New_class
hash{}
File.readlines('file.txt').each do |line|
if (line =~ /^(\w+)=>(.*)/)
hash[$1] =$2
end
end
def check
a='2345'
value = hash.fetch{a,''}
if (value == '')
puts 'Error no value found'
else
puts value
end
end
end
var=New_class.new
var.check
Error :undefined method 'fetch'
Here I want hash to run one time and store all the key/value so that I can use the hash in multiple methods and check for values. Anyone know how to fix this error or any better way to do?
The hash variable is out of scope. You can make it global by changing it to $hash.
Also fetch uses round brackets not curly brackets.
class New_class
$hash = {}
File.readlines('file.txt').each do |line|
if (line =~ /^(\w+)=>(.*)/)
$hash[$1] =$2
end
end
def check
a='2345'
value = $hash.fetch(a,'')
if (value == '')
puts 'Error no value found'
else
puts value
end
end
end

private method `select' called for nil:NilClass (NoMethodError)

I am new to ruby and would love some help please :)
I fixed the error in my ruby code, but I'm confused as to WHY the fix works.
I get the following error private method `select' called for nil:NilClass (NoMethodError) when I type in the following line:
scanned = #keywords.select { |key| key.match(word) }
, which is located within the following method:
def find(word)
return {} unless #entries.any?
scanned = #keywords.select { |key| key.match(word) }
found ={}
if scanned.any?
scanned.each do |x| found.merge!( { x => #entries[x] } )
end
else
{}
end
found
end
,yet this error goes away if I replace the erroneous line above with the following:
scanned = #entries.keys.sort.select { |key| key.match(word) }
I define #keywords as #keywords = #entries.keys.sort in the class structure below... Why can't I use '.select' on #keywords yet I can use it on #keywords' contents?
class Dictionary
def initialize
#entries = {}
end
def entries
#entries
end
def add(entry)
#entries = entry.is_a?(Hash) ? #entries.merge!(entry) : #entries.merge!( {entry => nil} )
end
def keywords
#keywords = #entries.keys.sort
end
def include?(keyword)
#entries.keys.include?(keyword)
end
def find(word)
return {} unless #entries.any?
scanned = #keywords.select { |key| key.match(word) }
found ={}
if scanned.any?
scanned.each do |x| found.merge!( { x => #entries[x] } )
end
else
{}
end
found
end
def printable
printable = #entries.sort.map do |key, value| %Q{[#{key}] "#{value}"}
end
printable.join("\n")
end
end
You are never calling the method keywords, and thus, you are never executing the code that populates #keywords with data. It remains nil.
#keywords will remain nil until you call the method keywords, which will initialize #keywords to be the sorted entry keys.
It looks like you're calling find on a dictionary object without first calling keywords. This would result in a nil value for #keywords.

Fix "no id given" message in method_missing

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

Ruby. OOP. Attribute not stored?

What i bascially want is to extend the Numeric class so that it has one extra Attribute (currencie), which is set when of the undefined methods are invoked [yen(s), euro(s), etc.]
So, here is the class definition:
class Numeric
##currencies = {'yen' => 0.013, 'euro' => 1.292, 'rupee' => 0.019, 'dollar' => 1}
attr_accessor :currencie
def method_missing(method_id)
singular_currency = method_id.to_s.gsub( /s$/, '')
if ##currencies.has_key?(singular_currency)
self.currencie = singular_currency
self * ##currencies[singular_currency]
puts "method finished"
else
super
end
end
def in(convert_to)
end
end
Now, when i run the code
a = 5.rupees
puts "currencie is -> " + a.currencie
i've got:
method finished
/path_to_file/hw2.1.rb:33:in `<main>': undefined method `currencie' for nil:NilClass (NoMethodError)
Also the attribute currencie seems to be unset.
What am i doing wrong ?
In your case method_missing should return object i.e. self. Just add self to method_missing and it will work.
def method_missing(method_id)
singular_currency = method_id.to_s.gsub( /s$/, '')
if ##currencies.has_key?(singular_currency)
self.currencie = singular_currency
puts "method finished"
self * ##currencies[singular_currency] # just change the order of expressions
else
super
end
end
EDIT: Fixed as injekt said

Resources