NoMethodError: undefined method `hours' for "1":String - ruby

I am getting this error all the time
#<NoMethodError: undefined method `hours' for "1":String>
UPDATE: I am getting errors for any number not just "1"
and here is the code that I am returning hours. i am using this method
def check_hours(most_recent_snooze)
if most_recent_snooze.duration.nil?
return 0.hours
else
return most_recent_snooze.duration.hours
end
end
and these code uses check_hours(most_recent_snooze) method
def snoozing?
if most_recent_snooze = Snooze.find_by_sensor_id(self.id)
if most_recent_snooze && !(most_recent_snooze.created_at + check_hours(most_recent_snooze) < Time.now)
# snooze is active
return true
else
most_recent_snooze.destroy
return false
end
end
return false
#self.snoozes.active.present? ? true : false
end
def snooze_minutes_remaining
# (60 - (Time.now - self.snoozes.last.created_at)/60).to_i + 1
most_recent_snooze = Snooze.find_by_sensor_id(self.id)
distance_of_time_in_words(Time.now, most_recent_snooze.created_at + check_hours(most_recent_snooze)) if most_recent_snooze
end
Please let me know on where did I go wrong on this code?
UPDATE:
Inside schema.rb, duration is integer
create_table "snoozes", :force => true do |t|
.......
........
.........
t.integer "duration"
end

ActiveSupport's time methods can be applied to Fixnums only, and it seems that some data you are passing in is a string. Perhaps you have a database column in an incorrect format?
A good way to handle this is to use an explicit to_i conversion in your method:
def check_hours(most_recent_snooze)
most_recent_snooze.duration.to_i.hours
end
nil.to_i returns 0, so you don't need the nil check in this case.

Your most_recent_snooze's duration, for some reason is a string. If you can't fix that, try this in check_hours:
def check_hours(most_recent_snooze)
if most_recent_snooze.duration.nil?
return 0.hours
else
return most_recent_snooze.duration.to_i.hours
end
end

Related

Ruby - no implicit conversion of Array into String

I am getting an error when executing my test.
Failure/Error: expect(industry_sic_code).to include page.sic_code
TypeError:
no implicit conversion of Array into String
# ./spec/os/bal/company/company_filter_clean_harbors_industries_stub.rb:62:in `block (2 levels) in <top (required)>'
The Method:
def sic_code
subtables = #b.table(:class => 'industry-codes').tables(:class => 'industry-code-table')
subtables.each do |subtable|
if subtable.tbody.h4.text == "US SIC 1987:"
subtable.tr.next_siblings.each do |tr|
codes = tr.cell
puts codes.text.to_s
end
end
end
end
The Test:
it 'Given I search for a random Clean Harbors Industry' do
#Pick a random clean industry from the file
data = CSV.foreach(file_path, headers: true).map{ |row| row.to_h }
random = data.sample
random_industry = random["Class"]
industry_sic_code = random["SIC Code"]
end
it 'Then the result has the expected SIC code' do
page = DetailPage.new(#b)
page.view
expect(industry_sic_code).to include page.sic_code
end
I have tried to implicitly change each variable to a string but it still complain about the array issue.
When I include some puts statments, I get some really wonky responses. The method itself returns the expected result.
When I used the method in the test I end up with the code gibberish below.
here are the sic codes from the method
5511
Here are the codes from the test
#<Watir::Table:0x00007fa3cb23f020>
#<Watir::Table:0x00007fa3cb23ee40>
#<Watir::Table:0x00007fa3cb23ec88>
#<Watir::Table:0x00007fa3cb23ead0>
#<Watir::Table:0x00007fa3cb23e918>
#<Watir::Table:0x00007fa3cb23e738>
#<Watir::Table:0x00007fa3cb23e580>
Your sic_code method returns subtables array, that's why you have this error. It doesn't matter that the method puts something, every method in ruby implicitly returns result of its last line, in your case it is subtables.each do ... end, so you have an array.
You need to explicitly return needed value. Not sure if I correctly understood what are you doing in your code, but try something like this:
def sic_code
subtables = #b.table(:class => 'industry-codes').tables(:class => 'industry-code-table')
result = [] # you need to collect result somewhere to return it later
subtables.each do |subtable|
if subtable.tbody.h4.text == "US SIC 1987:"
subtable.tr.next_siblings.each do |tr|
codes = tr.cell
result << codes.text.to_s
end
end
end
result.join(', ')
end

Code not actually asserting in RSpec?

I'm new to Ruby and in various open source software I've noticed a number of "statements" in some RSpec descriptions that appear not to accomplish what they intended, like they wanted to make an assertion, but didn't. Are these coding errors or is there some RSpec or Ruby magic I'm missing? (Likelihood of weirdly overloaded operators?)
The examples, with #??? added to the suspect lines:
(rubinius/spec/ruby/core/array/permutation_spec.rb)
it "returns no permutations when the given length has no permutations" do
#numbers.permutation(9).entries.size == 0 #???
#numbers.permutation(9) { |n| #yielded << n }
#yielded.should == []
end
(discourse/spec/models/topic_link_spec.rb)
it 'works' do
# ensure other_topic has a post
post
url = "http://#{test_uri.host}/t/#{other_topic.slug}/#{other_topic.id}"
topic.posts.create(user: user, raw: 'initial post')
linked_post = topic.posts.create(user: user, raw: "Link to another topic: #{url}")
TopicLink.extract_from(linked_post)
link = topic.topic_links.first
expect(link).to be_present
expect(link).to be_internal
expect(link.url).to eq(url)
expect(link.domain).to eq(test_uri.host)
link.link_topic_id == other_topic.id #???
expect(link).not_to be_reflection
...
(chef/spec/unit/chef_fs/parallelizer.rb)
context "With :ordered => false (unordered output)" do
it "An empty input produces an empty output" do
parallelize([], :ordered => false) do
sleep 10
end.to_a == [] #???
expect(elapsed_time).to be < 0.1
end
(bosh/spec/external/aws_bootstrap_spec.rb)
it "configures ELBs" do
load_balancer = elb.load_balancers.detect { |lb| lb.name == "cfrouter" }
expect(load_balancer).not_to be_nil
expect(load_balancer.subnets.sort {|s1, s2| s1.id <=> s2.id }).to eq([cf_elb1_subnet, cf_elb2_subnet].sort {|s1, s2| s1.id <=> s2.id })
expect(load_balancer.security_groups.map(&:name)).to eq(["web"])
config = Bosh::AwsCliPlugin::AwsConfig.new(aws_configuration_template)
hosted_zone = route53.hosted_zones.detect { |zone| zone.name == "#{config.vpc_generated_domain}." }
record_set = hosted_zone.resource_record_sets["\\052.#{config.vpc_generated_domain}.", 'CNAME'] # E.g. "*.midway.cf-app.com."
expect(record_set).not_to be_nil
record_set.resource_records.first[:value] == load_balancer.dns_name #???
expect(record_set.ttl).to eq(60)
end
I don't think there is any special behavior. I think you've found errors in the test code.
This doesn't work because there's no assertion, only a comparison:
#numbers.permutation(9).entries.size == 0
It would need to be written as:
#numbers.permutation(9).entries.size.should == 0
Or using the newer RSpec syntax:
expect(#numbers.permutation(9).entries.size).to eq(0)

undefined method error in ruby selenium

I am using ruby with selenium and my code is as follows:
$num=1
def isElementPresent(xpathExpression)
allElements=#driver.find_elements(:xpath,xpathExpression)
if (allElements.size==0)
return true
end
else
return false
end
while Demo.isElementPresent(str1+$num.to_s+str2)
text=#driver.find_element(:xpath,str1+$num.to_s+str2).text
$num+=1
puts "text is:#{text}"
#driver.find_element(:xpath,str1+$num.to_s+str2).click
puts #driver.title
#driver.navigate.back
end
end
I'm getting an undefined method error for while Demo.isElementPresent(str1+$num.to_s+str2).
Any help is appreciated
As per my understanding, Your condition should be:
if (allElements.size>0)
return true
As if size is 0. That means no element is present.
Also, in this case your function definition should end before you are calling it.
Try following code:
$num=1
def isElementPresent(xpathExpression)
allElements=#driver.find_elements(:xpath,xpathExpression)
if (allElements.size>0)
return true
end
else
return false
end
end
while isElementPresent(str1+$num.to_s+str2) do
text=#driver.find_element(:xpath,str1+$num.to_s+str2).text
$num+=1
puts "text is:#{text}"
#driver.find_element(:xpath,str1+$num.to_s+str2).click
puts #driver.title
#driver.navigate.back
end
Here I have made two changes: First, for the condition I explained about and Second, Ending the definition of function before your loop.
Please let me know if it works as intended.

Dynamically check if a field in JSON is nil without using eval

Here's an extract of the code that I am using:
def retrieve(user_token, quote_id, check="quotes")
end_time = Time.now + 15
match = false
until Time.now > end_time || match
#response = http_request.get(quote_get_url(quote_id, user_token))
eval("match = !JSON.parse(#response.body)#{field(check)}.nil?")
end
match.eql?(false) ? nil : #response
end
private
def field (check)
hash = {"quotes" => '["quotes"][0]',
"transaction-items" => '["quotes"][0]["links"]["transactionItems"]'
}
hash[check]
end
I was informed that using eval in this manner is not good practice. Could anyone suggest a better way of dynamically checking the existence of a JSON node (field?). I want this to do:
psudo: match = !JSON.parse(#response.body) + dynamic-path + .nil?
Store paths as arrays of path elements (['quotes', 0]). With a little helper function you'll be able to avoid eval. It is, indeed, completely inappropriate here.
Something along these lines:
class Hash
def deep_get(path)
path.reduce(self) do |memo, path_element|
return unless memo
memo[path_element]
end
end
end
path = ['quotes', 0]
hash = JSON.parse(response.body)
match = !hash.deep_get(path).nil?

change value by reference in ruby

I implemeting async thread manager and I want to pass reference to thread, where it should save the results of his work. And then when all thread finished i will handle all results.
What I need is to know how to work with 'references'.
lets assume I have variable result (or hash[:result1]), I want to pass it to the thread like
def test_func
return 777;
end
def thread_start(result)
Thread.new do
result = test_func;
end
end
and I want is to get following result
result = 555
thread_start(result);
#thread_wait_logic_there
result == 777; #=> true
hash = {:res1 => 555};
thread_start(hash[:res1])
#thread_wait_logic_there
hash[:res1]==777 #=> true
what should I chnage in my code to make it work?
Ruby version is 1.9.3
You can pass entrire hash to function:
def test_func
return 777;
end
def thread_start(hash, key)
Thread.new do
hash[key] = test_func;
end
end
Then this will work:
hash = {:res1 => 555};
thread_start(hash, :res1)
hash[:res1]==777 #=> true
Also if you want to be sure that you getting result after computations finished you must wait for thread, like this:
hash = {:res1 => 555};
thread_start(hash, :res1).join
hash[:res1]==777 #=> true
Edit: Added key,join

Resources