A constructor in following code receives a DateTime object in the parameter
class Test
attr_accessor :dateTime
# Takes DateTime object as input
def initialize(dateTime)
#dateTime = dateTime
end
end
How can I validate if dateTime parameter passed to the constructor is valid DateTime object or not?
One way to find out is by using:
if dateTime.class == DateTime
But is there a better way to do it?
Remember, dateTime is DateTime object and not a string
You can check it by dateTime.is_a?(DateTime) it will return boolean
Maybe use is_a? or kind_of?, to be flexible with potential subclasses.
http://www.ruby-doc.org/core/classes/Object.html#M001033
Try using the is_a? method, this way if the object is an instance of your target class (DateTime) or a subclass then you can accept it:
dateTime.is_a?(DateTime)
If all you want is to make sure that you get an instance of DateTime (or a subclass), then the other "is is_a?" answers are what you want.
However, you should consider being a little more forgiving of your inputs. What if someone hands you a string like "2011-06-28 23:31:11"? To most people, that's a DateTime even though Ruby thinks it is an instance of String. If you want to be friendlier, you could try DateTime.parse this:
begin
dt = dt.is_a?(DateTime) ? dt : DateTime.parse(dt)
rescue ArgumentError
# Do your failure stuff here
end
Or, if you're in Rails:
begin
dt = dt.to_datetime
rescue ArgumentError, NoMethodError
# Do your failure stuff here
end
These approaches give you a lot of flexibility without losing anything in the process. Be forgiving of your input but strict in your output.
For reference, in Rails 3, the following have to_datetime methods:
Date
DateTime
Time
String
Related
I am trying to use method_missing to convert dollar to different currencies.
class Numeric
##currency={"euro"=>2, "yen"=>6}
def method_missing(method_id,*args,&block)
method_id.to_s.gsub!(/s$/,'') #get rid of s in order to handle "euros"
##currency.has_key?(method_id) ? self*##currency[method_id] : super
end
end
> 3.euro #expect to return 6
NoMethodError: undefined method 'euro' for 3:Fixnum
from (pry):24:in 'method_missing'
> 3.euros #expect to return 6
NoMethodError: undefined method 'euros' for 3:Fixnum
from (pry):24:in 'method_missing'
I guess 3.euro isn't working because :euro.to_s.gsub!(/s$/,'') returns nil. I am not sure why it returns no method error.
Thanks for any help.
When method_missing will be called, then euro will be assigned to the method_id as a symbol. But your ##currency hash holds all keys as a strings, you need to convert them as symbols.
method_id.to_s.gsub!(/s$/,'') no way will change the actual object method_id. Because method_id.to_s will give you a new string object, and #gsub! will work on this only. No way you are changing the method_id, it remains as it is. Better to use non-bang one, because it will give you the actual object if no change made, or changed object, if change is made, then you need to assign this return value to a new variable.
With your ##currency, ##currency.has_key?(method_id) evaluated as false and super class method_missing has been called. Why? As method_id didn't convert into strings, which you expected may happened.
But, if you want to respond for both like euro or euros, then
class Numeric
##currency={"euro" => 2, "yen" => 6}
def method_missing(method_id,*args,&block)
#get rid of s in order to handle "euros"
new_method_id = method_id.to_s.gsub(/s$/,'')
##currency.has_key?(new_method_id) ? self*##currency[new_method_id] : super
end
end
3.euros # => 6
3.euro # => 6
gsub! modifies a string in place and returns nil. That won't work very well with the string you're using, which is a temporary created by to_s and never stored in a variable. Also, you are not even storing the result anywhere anyway. Why should gsub! on a string be expected to modify symbols, which are immutable anyway?
Try using gsub instead, which returns the modified string and leaves the caller alone. You'll also need to store the return value.
real_method_name = method_id.to_s.gsub(/s$/, "")
Also: The reason 3.euro didn't work is because your hash uses strings as keys but method_id is passed to the method as a symbol. If you didn't have to do string manipulations (to remove s suffixes, in this case), I would have suggested to just use symbols as your hash keys. As it is, though, you need to do string operations anyway, so my answer uses strings.
Is there a way to match an argument's attribute value in rspec? Checking the documentation it looks like there's other matchers available, such as anything, an_instance_of, and hash_including - but nothing to check the value of an object's attribute.
Example - suppose I have this instance method:
class DateParser
def parse_year(a_date)
puts a_date.year
end
end
Then I can write an expectation like this:
dp = DateParser.new
expect(dp).to receive(:parse_year).with(some_matcher)
What I want for some_matcher to check that parse_year is called with any object that has an attribute year that has the value 2014. Is this possible with the out-of-the-box argument matchers in rspec, or does a custom one have to be written?
You can pass a block and set expectations about the argument(s) within the block:
describe DateParser do
it "expects a date with year 2014" do
expect(subject).to receive(:parse_year) do |date|
expect(date.year).to eq(2014)
end
subject.parse_year(Date.new(2014,1,1))
end
end
Maybe something using a double for the passed-in date?
date = double()
date.should_receive(:year)
DateParser.new.parse_year(date)
It's not clear what you mean by the date needing to be 2014. But you could add .and_return(2014) to it to get that behavior from the double.
I am not sure if an object I pass to a method is of the proper type. I might pass a string to a function that can only handle integers. What about some kind of runtime ensurance? I couldn't see a better option than:
def someFixNumMangler(input)
raise "wrong type: integer required" unless input.class == FixNum
other_stuff
end
Any better alternatives?
Use the Kernel#Integer method to convert the input before using it. It will raise an ArgumentError when the input could not be converted to an integer in any reasonable fashion.
def my_method(number)
number = Integer(number)
# do something with number, which is now guaranteed to be an integer
end
I recommend Avdi Grimm's new book Confident Ruby for more insight into this.
If you really need to do type checks, then yes, you only have runtime checking. Code in the question is ok. You can also use .is_a?.
def someFixNumMangler(input)
raise "wrong type: integer required" unless input.is_a?(FixNum)
other_stuff
end
The checks may take different forms. If you expect, say, a string and you call string methods on it (upcase, gsub, etc), the code will blow up if anything other than string is passed. Unless, of course, you pass an object that is not a string, but behaves just like one (has the same methods that you call). This is the essence of duck typing.
What if your method looked like this?
def someFixNumMangler(input)
input = input.to_i
puts "got this: #{input} of #{input.class}"
end
someFixNumMangler(10)
someFixNumMangler('42')
someFixNumMangler(File)
# >> got this: 10 of Fixnum
# >> got this: 42 of Fixnum
# ~> -:2:in `someFixNumMangler': undefined method `to_i' for File:Class (NoMethodError)
# ~> from -:9:in `<main>'
As long as an argument responds to #to_i, you don't actually care what its type is.
I created the following extension
class String
def is_a_number? s # check if string is either an INT or a FLOAT (12, 12.2, 12.23 would return true)
s.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
end
How can I make it work as a chained method?
is_a_number?("10") # returns true
"10".is_a_number? # returns an error (missing arguments)
Update
Thanks sawa, mikej and Ramon for their answers. As suggested, I changed the class to Object and got rid of the argument (s):
class Object
def is_a_number? # check if string is either an INT or a FLOAT (12, 12.2, 12.23 would return true)
to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) != nil
end
end
It now works perfectly fine:
23.23.is_a_number? # > true
Thanks guys...
When you write "10".is_a_number?, you already have the object "10" you want to check for, which is the receiver of is_a_number?, so your method doesn't need to take any parameters.
Because match is an instance method on String, you don't need to specify a receiver for it. It will just operate on the same object on which is_a_number? was called. Because you know you already have a String object, the to_s isn't needed either.
Just write it as:
class String
# check if string is either an INT or a FLOAT (12, 12.2, 12.23 would return true)
def is_a_number?
match(/\A[+-]?\d+?(\.\d+)?\Z/) != nil
end
end
Ramon's suggestion that you may want to put your extension on Object rather than on String is a good point if you don't know if the object you're testing is going to be a string.
Also, what you're describing isn't really what is meant by method chaining; it's just calling a method on an object. Method chaining is where the return types of methods are set up so that several methods can be called in sequence e.g in Rails, something like
User.where(:name => 'Mike').limit(3) # find the first 3 Mikes
is an example of method chaining.
It seems like you want to patch Object instead of String (since you are calling to_s):
class Object
def is_a_number?
to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/).nil?
end
end
You could also look at replacing with it with validates numericality: true on your model.
If I have a custom Ruby class representing some string type, as in
class MyString
end
Which functions should I implement in order to make the following use cases possible:
Passing a Ruby string whenever a MyString is expected
Passing a MyString whenever a Ruby string is expected
Comparing a Ruby string with a MyString value (it shouldn't matter whether I use s == t or t == s).
I saw various interesting functions like to_s, cmp, == and eq already, but it's not clear to me when each of them is called.
My concrete use case is that I'm writing a Ruby extension using the C API which exposes functions taking (and returning) values of a custom string type (QString, to be precise) which my extension also registers. However, I'd like to make those custom strings behave as intuitive as possible. Unfortunately I can't just return Ruby strings from my C code since it should be possible to call Qt methods on the strings.
There are at least three approaches:
class MyString < String; ...; end
Define #to_s
Define #to_str
Doing both #2 and #3 will make the object act very much like a real String even if it isn't a subclass.
#to_s is an explicit converter, meaning it must appear in Ruby code to work.
#to_str is an implicit converter, meaning the Ruby interpreter will attempt to call it when it wants a String but is given something else.
Update:
Here is an example of some fun you can have with to_str:
begin
open 1, 'r'
rescue TypeError => e
p e
end
class Fixnum
def to_str; to_s; end
end
open 1, 'r'
When run, the first open fails with TypeError but the second proceeds to looking for 1.
#<TypeError: can't convert Fixnum into String>
fun.rb:9:in `initialize': No such file or directory - 1 (Errno::ENOENT)
from fun.rb:9:in `open'
Although it's tempting to sub-class String to give it a new initialize method that will import these QString-type strings, you may just want to tack on an extension to String that helps with the conversion so you don't have to re-implement a version of String itself.
For instance, with two methods you could pretty much have this done:
class String
def self.from_qstring(qstring)
new(...)
end
def to_qstring
# ...
end
end
Having multiple storage types for String is not going to be a problem until you start comparing them, but given that Ruby's String is quite robust, writing a work-alike is difficult.
It's not generally a good idea to subclass classes that were built by someone else in Ruby, because too many things can go wrong. (You might, for example, override an internal method without knowing it.)
1) define Mystring.to_s to get automatic conversion from a Mystring to a String.
2) Not sure what you mean by this. If you want a String method that returns a Mystring, you will have to monkey-patch String:
Class String
def to_mystring
return Mystring.new(self)
end
end
3) to get t == s (assuming s is an instance of String and t an instance of Mystring) define <=>. To get s == t you will have to monkey patch String again, though.
Since I was looking for something similar, but none of the other answers worked for me, I'll post what did work for me.
Found in this blog post which discourage the use of inheriting String and instead use simple delegator.
Inheriting from SimpleDelegator create an object which delegate everything to a string of your choice but on which you add behavior as you see fit.
class ChunkyBacon < SimpleDelegator
def initialize(content)
#content = content
super #content
end
def chunky_bacon?
#content == 'chunky_bacon'
end
end
test = ChunkyBacon.new('choco pizza') # => 'choco pizza'
test.chunky_bacon? # => false