Error while passing argument list to Superclass - ruby

Sorry if the question is unclear as I'm new to Ruby.
I have a Parent class (not implemented by me) Reports that has a method query defined as:
class Reports
def self.query(id:, is_active: false, is_timestamp: false, version: DEFAULT_VERSION, limit: DEFAULT_LIMIT)
<<code>>
end
I have defined a child class Report that inherits Reports and defined the same method query as below:
class Report < Reports
def self.q_version(id)
<<some logic to decide version>>
end
def self.query(id:, is_active: false, is_timestamp: false, limit: DEFAULT_LIMIT)
version = q_version(id)
super(id, is_active, is_timestamp, version, limit)
end
Now when I run the code, I'm getting an argument error as such:
ArgumentError: wrong number of arguments (given 5, expected 0; required keyword: id)
I suspect I'm not doing the super call correctly but couldn't figure out which part.
so any help would be appreciated.

The method's signature tells that it expects keyword arguments like this:
def self.query(id:, is_active: false, is_timestamp: false, limit: DEFAULT_LIMIT)
version = q_version(id)
super(id: id, is_active: is_active, is_timestamp: is_timestamp, version: version, limit: limit)
end
Or you could use the new shorthand hash syntax when you are on Ruby 3.1+:
def self.query(id:, is_active: false, is_timestamp: false, limit: DEFAULT_LIMIT)
version = q_version(id)
super(id:, is_active:, is_timestamp:, version:, limit:)
end

Related

RSpec mock method inside of select loop

I want to test simple class which iterate through array of hashes and return only those with status Pending which were updated more than 2 days ago.
class FetchPending
PROJECT_KEY = 'TPFJT'
TWO_DAYS = Time.now - 2 * 24 * 60 * 60
def call
project.select do |issue|
issue.fields.dig('status', 'name') == 'Pending' &&
DateTime.parse(issue.fields.dig('updated')) < TWO_DAYS
end
end
private
def project
#project ||= Jira::ProjectConnection.new(PROJECT_KEY).call
end
end
How to test fields method which is a method of Jira-Ruby gem. I think it comes from here (Field class in resource of gem) because nowhere else have I found fields method.
Here are my thoughts after debugging:
project.class - Array
issue.class - JIRA::Resource::Issue
my natural thinking was:
before do
# (...) some other mocks
allow(JIRA::Resource::Issue).to receive(:fields)
end
But I'm getting an error:
Failure/Error: allow(JIRA::Resource::Issue).to receive(:fields)
JIRA::Resource::Issue does not implement: fields
I have been struggling with this problem for DAYS, I'm pretty desperate here. How to mock this method?
Here is my rest of my specs:
RSpec.describe FetchPending do
subject { described_class.new }
let(:project_hash) do
[
{
'key': 'TP-47',
'fields': {
'status': {
'name': 'Pending'
},
'assignee': {
'name': 'michael.kelso',
'emailAddress': 'michael.kelso#example.com'
},
'updated': '2020-02-19T13:20:50.539+0100'
}
}
]
end
let(:project) { instance_double(Jira::ProjectConnection) }
before do
allow(Jira::ProjectConnection).to receive(:new).with(described_class::PROJECT_KEY).and_return(project)
allow(project).to receive(:call).and_return(project_hash)
allow(JIRA::Resource::Issue).to receive(:fields)
end
it 'return project hash' do
expect(subject.call).include(key[:'TP-47'])
end
and_return is generally used for returning a value (such as a string or an integer) or sequence of values, but for objects you sometimes need use a block. Additionally, if call is a valid method on a Jira::ProjectConnection object that returns the value of project_hash, you can directly mock its behavior when declaring your instance double (this functionality is unclear from the Relish docs bc they are kinda terrible). Something like this will probably work:
let(:project) { instance_double(Jira::ProjectConnection, call: project_hash) }
before do
# Ensure new proj conns always return mocked 'project' obj
allow(Jira::ProjectConnection).to receive(:new).with(
described_class::PROJECT_KEY
) { project }
end
If it still doesn't work, try temporarily replacing described_class::PROJECT_KEY with anything to debug; this can help you confirm if you specified the wrong arg(s) being sent to new.
With regard to the error message, it looks like JIRA::Resource::Issue doesn't have a fields attribute/method, though fields appears to be nested in attrs? The JIRA::Resource::Project#issues method also translates the issues in the JSON into Issue objects, so if you're using that method you will need to change the contents of project_hash.

RSpec validation fails with little explaination

I've created an RSpec test to simply test if my model is valid with the given info, it should be, yet my test is still failing. I'm hoping someone can see why since I've stared at this all day yesterday.
I'm also using MongoDB (not sure if that matters).
models/stock.rb
class Stock
include Mongoid::Document
field :symbol, type: String
field :last_trade_price, type: Integer
field :ask, type: Integer
field :change, type: Integer
field :change_percent, type: String
field :market_cap, type: String
field :avg_volume, type: Integer
field :change_from_year_high, type: Integer
field :change_from_year_low, type: Integer
field :change_from_year_high_percent, type: Integer
field :change_from_year_low_percent, type: Integer
field :year_high, type: Integer
field :year_low, type: Integer
field :day_high, type: Integer
field :day_low, type: Integer
field :day_range, type: String
field :ebitda, type: String
field :eps_estimate_current_year, type: Integer
field :eps_estimate_next_year, type: Integer
field :eps_estimate_next_quarter, type: Integer
validates :symbol, :last_trade_price, :ask, :change, :change_percent, :market_cap,
:avg_volume, :change_from_year_high, :change_from_year_low, :change_from_year_high_percent,
:change_from_year_low_percent, :year_high, :year_low, :day_high, :day_low, :day_range,
:ebitda, :eps_estimate_current_year, :eps_estimate_next_year, :eps_estimate_next_quarter, presence: true
validates :last_trade_price, :ask, :change, :avg_volume,
:change_from_year_high, :change_from_year_low, :change_from_year_high_percent,
:change_from_year_low_percent, :year_high, :year_low, :day_high, :day_low,
:eps_estimate_current_year, :eps_estimate_next_year, :eps_estimate_next_quarter, numericality: true
validates_uniqueness_of :symbol
end
spec/factories.rb
FactoryGirl.define do
factory :stock do
symbol "AAPL"
last_trade_price 92.51
ask 92.78
change -0.91
change_percent "-0.91 - -0.97"
market_cap "512.93B"
avg_volume 37776500
change_from_year_high -40.46
change_from_year_low 0.66
change_from_year_high_percent -30.43
change_from_year_low_percent 0.72
year_high 132.97
year_low 91.85
day_high 93.57
day_low 92.46
day_range "92.46 - 93.57"
ebitda "82.79B"
eps_estimate_current_year 8.29
eps_estimate_next_year 9.15
eps_estimate_next_quarter 1.67
end
end
spec/models/stock_spec.rb
describe Stock do
let(:stock) { build(:stock) }
it "should be valid if all information is provided" do
expect(stock).to be_valid
end
end
My output from running the rspec test is:
Failures:
1) Stock should be valid if all information is provided
Failure/Error: expect(stock).to be_valid
expected `#<Stock _id: 5734dd60b8066872f6000000, symbol: "AAPL", last_trade_price: 92, ask: 92, change: 0, change_percent: "-0.91 - -0.97", market_cap: "512.93B", avg_volume: 37776500, change_from_year_high: -40, change_from_year_low: 0, change_from_year_high_percent: -30, change_from_year_low_percent: 0, year_high: 132, year_low: 91, day_high: 93, day_low: 92, day_range: "92.46 - 93.57", ebitda: "82.79B", eps_estimate_current_year: 8, eps_estimate_next_year: 9, eps_estimate_next_quarter: 1>.valid?` to return true, got false
# ./spec/models/stock_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.02311 seconds (files took 1.72 seconds to load)
1 examples, 1 failure
Failed examples:
rspec ./spec/models/stock_spec.rb:4 # Stock should be valid if all information is provided
Randomized with seed 36574
From looking at the error, it seems that all of the information was built into the factory test object, so I'm unsure why the test is getting false instead of the true it's expecting.
Thanks for any help!
You can test what fields are giving an error by modifiying the spec:
describe Stock do
let(:stock) { build(:stock) }
it "should be valid if all information is provided" do
#expect(stock).to be_valid
stock.valid?
expect(stock.errors.full_messages).to eq []
end
end
However even as such the spec has very little actual value - you're just testing that your factory has all the required fields. If it didn't you would get failures in other specs anyways.
Also if you are grouping a bunch of similar validations by type you might want to use the longhand methods instead as it is much easier to read:
validates_presence_of :symbol, :last_trade_price, :ask, :change, :change_percent, :market_cap,
:avg_volume, :change_from_year_high, :change_from_year_low, :change_from_year_high_percent,
:change_from_year_low_percent, :year_high, :year_low, :day_high, :day_low, :day_range,
:ebitda, :eps_estimate_current_year, :eps_estimate_next_year, :eps_estimate_next_quarter
Added
When defining factories you should use sequences or computed properties to ensure that unique fields are unique - otherwise your validations will fail if you create more than one record from your factory!
FactoryGirl.define do
factory :stock do
sequence :symbol do |n|
"TEST-#{n}"
end
last_trade_price 92.51
ask 92.78
change -0.91
change_percent "-0.91 - -0.97"
market_cap "512.93B"
avg_volume 37776500
change_from_year_high -40.46
change_from_year_low 0.66
change_from_year_high_percent -30.43
change_from_year_low_percent 0.72
year_high 132.97
year_low 91.85
day_high 93.57
day_low 92.46
day_range "92.46 - 93.57"
ebitda "82.79B"
eps_estimate_current_year 8.29
eps_estimate_next_year 9.15
eps_estimate_next_quarter 1.67
end
end
Gems like FFaker are really helpful here. See the FactoryGirl docs for more info.
Also you should use a gem like database_cleaner (Yes it works for mongoid) to clean out your database between specs - the reason your validation is currently failing is that you have residual test state from some other test which is effecting the result.

How to send params to a method?

I am trying to make a query to Webmaster Tool api using the Ruby Client.
params = {
start_date: "2015-01-14",
end_date: "2015-01-14"
}
AuthWebmastersService.query_search_analytics("http://www.ex.com/", params)
When I'm trying to make that request I get ArgumentError (unknown keywords: start_date, end_date), why is this happening?
Here is the method definition.
It doesn't work as expected, because Ruby converts your hash to keyword arguments, i.e.
query_search_analytics("...", {start_date: "2015-01-14", end_date: "2015-01-14"})
becomes:
query_search_analytics("...", start_date: "2015-01-14", end_date: "2015-01-14")
To get the expected result, you have to append an empty hash:
query_search_analytics("http://www.ex.com/", params, {})
This is a ruby issue with auto-expanding the last argument if is a hash.
Two workarounds:
1 - Use a proper object instead of a hash:
params = Google::Apis::WebmastersV3::SearchAnalyticsQueryRequest.new(
start_date: "2015-01-14",
end_date: "2015-01-14"
)
AuthWebmastersService.query_search_analytics("http://www.ex.com/", params)
2 - Append an empty hash as a param:
params = {
start_date: "2015-01-14",
end_date: "2015-01-14"
}
AuthWebmastersService.query_search_analytics("http://www.ex.com/", params, {})
This error:
ArgumentError (unknown keywords: start_date, end_date)
is telling you that you specified the wrong keyword attributes.
Your method takes:
def query_search_analytics(site_url, search_analytics_query_request_object = nil, fields: nil, quota_user: nil, user_ip: nil, options: nil, &block)
site_url as first argument
search_analytics_query_request_object - as second argument with default value nil
multiple keyword arguments (and a block)
When you call your method like you wrote:
site_url will have value "http://www.ex.com/"
search_analytics_query_request_object will be nill
and hash will be applied to keyword arguments and ruby will raise the error as there are no startDate and endDate keyword argument
What you need to do is to:
query_search_analytics("http://www.ex.com/", options: params)
Because it only takes the keyword arguments fields, quota_user, user_ip, options, and start_date, end_date are not among them.

Mongoid Capped Collection

I'm trying to create a capped collection with Mongoid. I have a definition as follows:
class Customer
include Mongoid::Document
store_in(collection: 'customers')
field: n, type: String, as: :name
field: a, type: String, as: :address
field: z, type: String, as: :zip
end
I've been referencing the documentation but can't figure out how to make a capped collection in this portion of the code. I've tried removing the store_in line and replacing it with session.command(create: "customers", capped: true, size: 10000000, max: 1000) to no avail. Is session supposed to be replaced with something? Or am I going about this incorrectly?
Mongoid does not provide a mechanism for creating capped collections on the fly - you will need to create these yourself via the Mongo console.

Sinatra activerecord initialize

I got a strange situation.Could somebody give me advise ?
I am developing an App with
Ruby1.8.7
Sinatra 1.4.4
Activerecord 3.2.14
Mysql 5.6.19
I almost finish developing but at the last moment I got stack.
I have two tables in MySQL.
CREATE TABLE items(
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
type text,
keyword text,
postid INT,
created_at datetime NOT NULL);
CREATE TABLE comments(
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
comment text,
yourname INT,
postid INT,
created_at datetime NOT
NULL);
In Sinatra app , I declared class.
class Comment < ActiveRecord::Base end
class Item < ActiveRecord::Base end
For debugging purpose , I wrote this code and run.
get "/l" do
# New comment and set initial value.
y={:yourname =>"3",:comment =>"commenttest"}
com = Comment.new(y)
p com.attribute_names()
p com
# New items and set initial value.
kensaku = {:type=>"000"}
k = Item.new(kensaku)
p k.attribute_names()
p k
k.type="555"
p k
end
So now I found very interesting things on console.
Comment class succeeded to new with initial value.
But Item class succeeded to new but it is not set initial value.
I wonder why it happens ?
#-- Comment class
["postid", "id", "comment", "created_at", "yourname"]
#<Comment id: nil, comment: "commenttest", yourname: 3, postid: nil, created_at: nil>
#-- Item class
["type", "postid", "id", "keyword", "created_at"]
#<Item id: nil, type: nil, keyword: nil, postid: nil, created_at: nil>
#<Item id: nil, type: "555", keyword: nil, postid: nil, created_at: nil>
The column name type is a reserved word in ActiveRecord:
While these column names are optional, they are in fact reserved by
Active Record. Steer clear of reserved keywords unless you want the
extra functionality. For example, type is a reserved keyword used to
designate a table using Single Table Inheritance (STI). If you are not
using STI, try an analogous keyword like "context", that may still
accurately describe the data you are modeling.

Resources