How to test for a time span parameter? - ruby-on-rails

I'm struggling with the following issue:
$ rails c
Loading development environment (Rails 3.2.1)
irb(main):001:0> 2.class
=> Fixnum
irb(main):002:0> Fixnum === 2
=> true
irb(main):003:0> 2.hours.class
=> Fixnum
irb(main):004:0> Fixnum === 2.hours
=> false
irb(main):005:0>
I'd like to test whether some specified parameter is a symbol or a time span. The way I thought would be the natural way in Ruby/Rails is:
case param
when :today then
# do this...
when Fixnum then
# do that...
else
raise ArgumentError ...
end
As far as I can tell from ActiveSupport's source code === is not overridden for Fixnum. So, what am I doing wrong?

You can see from the console, that 2.hours can't be Fixnum, because it's #inspect method is overridden. It just pretends to be Fixnum, but it is ActiveSupport::Duration (see the source)
> 2.hours
=> 7200 seconds
> 2.hours.to_i
=> 7200
Better check if it responds to some methods. If it responds to to_i, it is not a symbol.
> :today.respond_to?(:to_i)
=> false
> 2.hours.respond_to?(:to_i)
=> true

Related

Ruby variable value set to true

I am new to Ruby/ Ruby on Rails. I wrote the below code to get a boolean value from api. The API call failed and it went to the rescue block. But for some reason, it set the value to true. I don't understand how that happened.
#is_attached = OnDeck.api.check_is_attached(#decision.application_number, current_user)
Api call / client wrapper Code
def check_is_attached(app_number, user)
begin
client.check_is_attached(app_number, user.auth_token)
rescue OnDeckException::MerchantApiException => e
Rails.logger.error("Caught exception #{e} while calling check_mbs_attached for app_number : #{app_number}")
end
end
The rails logger returns true on successfully logging:
[2] pry(main)> Rails.logger.error("Caught exception")
Caught exception
=> true
Because that is the last line executed in the method, that value is returned as ruby has implicit return.
Rails.logger.error(string)
returns true as can be seen:
2.3.1 :002 > Rails.logger.error('foo')
foo
=> true

With regional locale, `pluralize` doesn't work but `translate` does

I've got this behaviour that I can't explain:
$ rails console
Loading development environment (Rails 4.2.7.1)
irb(main):001:0> I18n.locale
=> :"en-GB"
irb(main):002:0> I18n.available_locales
=> [:en, :"en-GB"]
irb(main):003:0> 'bear'.pluralize
=> "bears"
irb(main):004:0> 'bear'.pluralize(2, :"en-GB")
=> "bear" # <- sadness here
irb(main):005:0> 'bear'.pluralize(2, :en)
=> "bears"
irb(main):006:0> I18n.translate("gst")
=> "VAT" # <- correct translation from 'config/locales/en-GB.yml'
irb(main):007:0> ActiveSupport::Inflector.pluralize('bear', :en)
=> "bears"
irb(main):008:0> ActiveSupport::Inflector.pluralize('bear', :'en-GB')
=> "bear"
My <rails_root>/uk/config/locales/en-GB.yml:
en-GB:
gst: VAT
How come the regionalised locale is available, in use, and works well with translations but not with pluralisation? Just in case, I've put
config.i18n.fallbacks = { :'en-GB' => :en } in my config/application.rb, but without effect. I've got no clue on where I should investigate further...
Any ideas?
Thank you.
Ok, this has been fixed in Rails 5 thanks to this patch

Difference between Ruby’s Hash and ActiveSupport’s HashWithIndifferentAccess

What is the difference between Ruby’s Hash and ActiveSupport’s HashWithIndifferentAccess? Which is the best for dynamic hashes?
Below is the simple example that will show you difference between simple ruby hash & a "ActiveSupport::HashWithIndifferentAccess"
HashWithIndifferentAccess allows us to access hash key as a symbol or string
Simple Ruby Hash
$ irb
2.2.1 :001 > hash = {a: 1, b:2}
=> {:a=>1, :b=>2}
2.2.1 :002 > hash[:a]
=> 1
2.2.1 :003 > hash["a"]
=> nil
ActiveSupport::HashWithIndifferentAccess
2.2.1 :006 > hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1, b:2)
NameError: uninitialized constant ActiveSupport
from (irb):6
from /home/synerzip/.rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'
2.2.1 :007 > require 'active_support/core_ext/hash/indifferent_access'
=> true
2.2.1 :008 > hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1, b:2)
=> {"a"=>1, "b"=>2}
2.2.1 :009 > hash[:a]
=> 1
2.2.1 :010 > hash["a"]
=> 1
class HashWithIndifferentAccess is inherited from ruby "Hash" & above special behavior is added in it.
In Ruby Hash:
hash[:key]
hash["key"]
are different. In HashWithIndifferentAccess as the name suggests, you can access key either way.
Quoting official documentation to this:
Implements a hash where keys :foo and "foo" are considered to be the
same.
and
Internally symbols are mapped to strings when used as keys in the
entire writing interface (calling []=, merge, etc). This mapping
belongs to the public interface. For example, given:
hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
You are
guaranteed that the key is returned as a string:
hash.keys # => ["a"]

How to check if a variable exists with a value without "undefined local variable or method"?

This is a common pattern: If a variable doesn't exist I get an undefined local variable or method error.
The existing code has if variable_name.present? but this didn't account for the variable not existing.
How can I check the value of the variable and also account for it not existing at all?
I've tried:
if (defined? mmm) then
if mmm.present? then
puts "true"
end
end
but Ruby still checks that inner mmm.present? and throws "no such variable" when it doesn't exist.
I'm sure there's a common pattern/solution to this.
Change the present? to != '' and use the && operator which only tries to evaluate the seond expression if the first one is true:
if defined?(mmm) && (mmm != '') then puts "yes" end
But actually as of 2019 this is no longer needed as both the below work
irb(main):001:0> if (defined? mm) then
irb(main):002:1* if mm.present? then
irb(main):003:2* p true
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> if (defined? mm) then
irb(main):007:1* p mm
irb(main):008:1> end
=> nil
On Ruby on Rails
if defined?(mm) && mm.present?
puts "acceptable variable"
end
On IRB
if defined?(mm) && !mm.blank? && !mm.nil?
puts "acceptable variable"
end
It can make sure you won't get undefined variable or nil or empty value.
Understand how defined? works
a = 1
defined?(a) # => "local-variable"
b = nil
defined?(b) # => "local-variable"
c = ""
defined?(c) # => "local-variable"
d = []
defined?(d) # => "local-variable"
$e = 'text'
defined?($e) # => "global-variable"
defined?(f) # => nil
defined?($g) # => nil
Note that defined? checks variable in the scope it is.
Why you need defined?
When there is possible of undefined variable presence, you cannot just check it with only .nil? for eaxample, you will have a chance to get NameError.
a = nil
a.nil? # => true
b.nil? # => NameError: undefined local variable or method `b'

Date range in ruby/rails

I want to get date range between from and till in Rails seed.
When I try to generate date range ((Date.today - 10)..Date.today) exception occurred.
Exception message: bad value for range
But in the Rails Console everything all right.
I think ActiveSupport are reasonable for that (my debugger told me that).
Ralls 3.1.3
What's going on?
You can understand what's going on by splitting the two edges and check their class like so:
Date.today.class # => Date
(Date.today - 10).class # => Date
((Date.today - 10)..Date.today).each {|d| puts d.class} # => 10 Date works for me
The error you're experiencing is something like this:
('a'..10) # => ArgumentError: bad value for range
Can you post the classes of your 2 edges of the range?
(Date.today - 10).class => ?
Date.today.class => ?
Have you overwritten any class in your rails environment? Does it work in irb?
PS: As you're in rails you can use 10.days.ago but you'll need to use to_date as it's a ActiveSupport::TimeWithZone
begin
((Date.today - 10)..Date.today).each { |date| puts date }
rescue
$! # => #<NameError: uninitialized constant Date>
end
require 'date'
((Date.today - 10)..Date.today).each { |date| puts date }
# >> 2012-04-06
# >> 2012-04-07
# >> 2012-04-08
# >> 2012-04-09
# >> 2012-04-10
# >> 2012-04-11
# >> 2012-04-12
# >> 2012-04-13
# >> 2012-04-14
# >> 2012-04-15
# >> 2012-04-16

Resources