Wrong number arguments error when using unpacked keyword args along with send - ruby

I noticed that attempting to use the send method while passing in unpacked keyword args as a variable led to some unexpected behavior.
First the setup:
class SomeClass
def some_method
true
end
end
kwargs = {}
c = SomeClass.new
c.some_method
=> true
c.some_method(**kwargs)
=> true
c.send(:some_method, **{})
=> true
All of the above works as expected. However, if I attempt to use send in conjunction with passing key word args via a variable (as oppose to a literal), I suddenly get a 'wrong number of arguments' error
c.send(:some_method, **kwargs)
Traceback (most recent call last):
5: from /Users/rs/.rvm/rubies/ruby-2.6.7/bin/irb:23:in `<main>'
4: from /Users/rs/.rvm/rubies/ruby-2.6.7/bin/irb:23:in `load'
3: from /Users/rs/.rvm/rubies/ruby-2.6.7/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
2: from (irb):9
1: from (irb):2:in `some_method'
ArgumentError (wrong number of arguments (given 1, expected 0))
Is this intended behavior?

Related

Ruby NoMethodError (undefined method ''...' for '....:Class'

require_relative 'json_lookup'
require_relative 'csv_lookup'
require_relative 'error'
BASE_RATE = 'EUR'
class CurrencyExchange
def initialize(file:, date:, from:, to:)
#file = file
#date = date
#from = from
#to = to
end
def rate
lookup = find_lookup
lookup.to_currency / lookup.from_currency
end
private
def find_lookup
case File.extname(#file)
when ".json"
JsonLookup.new(#file, #date, #from, #to)
when ".csv"
CsvLookup.new(#file, #date, #from, #to)
else raise FileError
end
end
end
I keep on getting this error for when i run the CurrencyExchange.rate in irb so I am guessing something is going wrong with the rate method but can't figure it out as to why. But I may be missing something completely obvious... As I am a complete beginner at Ruby, would appreciate any help :)
The traceback is as follows..
irb(main):003:0> CurrencyExchange.rate(Date.new(2018, 11, 22), "USD", "GBP") Traceback (most recent call last):
5: from C:/Ruby26-x64/bin/irb.cmd:31:in `<main>'
4: from C:/Ruby26-x64/bin/irb.cmd:31:in `load'
3: from C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
2: from (irb):3
1: from (irb):3:in `rescue in irb_binding'
NoMethodError (undefined method `rate' for CurrencyExchange:Class)
rate is an instance method in your example but CurrencyExchange.rate tries to call a class method.
To solve this, initialize an instance first and call then rate on that instance. Furthermore rate doesn't accept arguments, you need to pass the variables to the initializing method.
currency_exchange = CurrencyExchange.new(
file: file, date: Date.new(2018, 11, 22), from: "USD", to: "GBP"
)
currency_exchange.rate
Note take the initializer expects 4 named arguments. You will need to pass a file to the new method too.

I am getting an error on line 13. It says that the `<<` method is undefined. how do I fix this? I am using Ruby

This is the code:
def self.scrape_shoe
#doc.css("div.product-card__body").each do |nike|
name = nike.css("div.product-card__title").text.strip
price = nike.css("div.product-card__price").text.strip
shoes = self.new
#all << shoes #having error here
end
end
This is the error:
Traceback (most recent call last):
7: from bin/new_nikes:7:in `<main>'
6: from /home/merkonical/new_nikes/lib/new_nikes/cli.rb:17:in `call'
5: from /home/merkonical/new_nikes/lib/new_nikes/cli.rb:11:in `list_price'
4: from /home/merkonical/new_nikes/lib/new_nikes/scraper.rb:9:in `scrape_shoe'
3: from /home/merkonical/.rvm/gems/ruby-2.6.1/gems/nokogiri-1.10.4/lib/nokogiri/xml/node_set.rb:237:in `each'
2: from /home/merkonical/.rvm/gems/ruby-2.6.1/gems/nokogiri-1.10.4/lib/nokogiri/xml/node_set.rb:237:in `upto'
1: from /home/merkonical/.rvm/gems/ruby-2.6.1/gems/nokogiri-1.10.4/lib/nokogiri/xml/node_set.rb:238:in `block in each'
/home/merkonical/new_nikes/lib/new_nikes/scraper.rb:13:in `block in scrape_shoe': undefined method `<<' for nil:NilClass (NoMethodError)
What are possible fixes I can do for this?
I am working on Ruby
What are possible fixes I can do for this?
#all is nil. nil doesn't have a method named <<. Make sure #all is not nil.
Getting error because you are pushing shoes object into undefined instance variable.
Define #all in action.
def self.scrape_shoe
#doc.css("div.product-card__body").each do |nike|
#all = []
name = nike.css("div.product-card__title").text.strip
price = nike.css("div.product-card__price").text.strip
shoes = self.new
#all << shoes #having error here
end
end
Hope this helps you

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

Ruby script raising unexpected backtrace

I have a method that should raise a custom error with a message. When I catch the error and raise my own custom error, it is still raising and printing the backtrace of the original error. I just want the custom error and message. Code below.
Method:
def load(configs)
begin
opts = {access_token: configs['token'],
api_endpoint: configs['endpoint'],
web_endpoint: configs['site'],
auto_paginate: configs['pagination']}
client = Octokit::Client.new(opts)
repos = client.org_repos(configs['org'])
repos.each do |r|
Project.create(name: r.name)
end
rescue Octokit::Unauthorized
raise GitConfigError, "boom"
end
#rescue Octokit::Unauthorized
end
class GitConfigError < StandardError
end
My test (which is failling):
context 'with incorrect git configs' do
before do
allow(loader).to receive(:load).and_raise Octokit::Unauthorized
end
it { expect{loader.load(configs)}.to raise_error(GitConfigError, "boom" ) }
end
Test Output:
GitProjectLoader#load with incorrect git configs should raise GitConfigError with "boom"
Failure/Error: it { expect{loader.load(configs)}.to raise_error(GitConfigError, "boom" ) }
expected GitConfigError with "boom", got #<Octokit::Unauthorized: Octokit::Unauthorized> with backtrace:
# ./spec/lib/git_project_loader_spec.rb:24:in `block (5 levels) in <top (required)>'
# ./spec/lib/git_project_loader_spec.rb:24:in `block (4 levels) in <top (required)>'
# ./spec/lib/git_project_loader_spec.rb:24:in `block (4 levels) in <top (required)>'
If you intend to test the handling of the Octokit::Unauthorized error, then raise the error anywhere before the rescue kicks in. Preferably, someplace where it would actually be raised.
Something like this, for example:
before do
allow(Octokit::Client).to receive(:new).and_raise(Octokit::Unauthorized)
end
And then:
expect{ loader.load(configs) }.to raise_error(GitConfigError, "boom" )
As a side note, I would discourage enclosing all lines of your method in a begin;rescue;end structure; you should enclose only the lines from which you are expecting errors.
You are not testing your code as you think. You have mocked it out.
The line
allow(loader).to receive(:load).and_raise Octokit::Unauthorized
replaces the load method on loader with a stub which just raises the named error.
Remove your before block, and it should test your code as intended. Note as written it will make a real request via Octokit, unless you mock that out instead.

"ArgumentError: wrong number of arguments (2 for 0)" though method requires two parameters

I have a MiniTest like this:
describe Message do
describe "#is_getting_unavailable" do
let( :message ) { Message.new() }
it "should be false when user does not exist in the database" do
message.handle
assert_equal(false, message.is_getting_unavailable)
end
end
end
Running this gives me complaint from assert_equal:
Message::#is_getting_unavailable#test_0001_should be false when user does not exist in the database
ArgumentError: wrong number of arguments (2 for 0)
test/unit/message_test.rb:148:in `(root)'
org/jruby/RubyBasicObject.java:1703:in `__send__'
org/jruby/RubyKernel.java:2209:in `send'
org/jruby/RubyArray.java:1617:in `each'
org/jruby/RubyArray.java:1617:in `each'
I did not understand this, so I included the test (just before the call of assert_equal):
puts method(:assert_equal).inspect
puts method(:assert_equal).arity
puts method(:assert_equal).source_location.inspect
The output is:
#<Method: #<Class:0x1d1e394d>(Minitest::Assertions)#assert_equal>
-3
["/home/rjung/.rvm/gems/jruby-1.7.4/gems/minitest-5.0.6/lib/minitest/assertions.rb", 155]
So the method is correct, and the arity is correct. What's the issue here?
We also use rr, timecop. Any other questions, that could help me find a solution?
It took me a while, but I could narrow the problem down to this failing test:
require 'minitest/autorun'
describe 'Message' do
let( :message ) { Hash.new }
it "should not fail awkwardly" do
assert_equal false, message.nil?
end
end
The output of this test is
1) Error:
Message#test_0001_should not fail awkwardly:
ArgumentError: wrong number of arguments (2 for 0)
test/unit/message_test.rb:7:in `(root)'
org/jruby/RubyBasicObject.java:1703:in `__send__'
org/jruby/RubyKernel.java:2209:in `send'
org/jruby/RubyArray.java:1617:in `each'
org/jruby/RubyArray.java:1617:in `each'
So I filed a Bug for https://github.com/seattlerb/minitest/issues/343.
Minitest does have a method message that was overwritten, so don't use message as a variable.
What I still wonder is, why the stacktrace says the wrong number of arguments happen in message_test.rb:7, because the method that takes no arguments (message) is definitive called from somewhere else.

Resources