Creating a Special Integer - ruby

I want to define a constant FOO in the namespace of Integer that is similar to Float::NAN in Float, which is itself an instance of Float. It will be used somewhat similar to symbols, i.e., to mark a special case (of an integer). I don't need it to be used in calculation, but I need it to have the following properties:
Its class must be Integer or a subclass of Integer, and it must behave so to methods related to class:
Integer::FOO.kind_of?(Integer) # => true
Optionally (if the class is Integer):
Integer::FOO.class # => Integer
Integer === Integer::FOO # => true
Integer::FOO.instance_of?(Integer) # => true
It must be distinct from (ideally all) other integers:
Integer::FOO == 0 # => false
Ideally, I want it distinct from any other integer, but if that is not possible, I can live with a dirty hack that, say makes Integer::FOO be identical to the largest or the smallest integer, which are the least likely to hit any random given integer.
What is the best way to go about this?

Ruby's metaprogramming methods make it easy to twist a generic object into the shape you desire:
class Integer
FOO = Object.new
end
Integer::FOO.define_singleton_method(:kind_of?) do |klass|
Integer.ancestors.include? klass
end
Integer::FOO.define_singleton_method(:class) do
Integer
end
Integer::FOO.define_singleton_method(:instance_of?) do |klass|
klass == Integer
end
oldteq = Integer.method(:===)
Integer.define_singleton_method(:===) do |obj|
obj == Integer::FOO ? true : oldteq.call(obj)
end
Integer::FOO.kind_of? Integer
# true
Integer::FOO.class
# Integer
Integer === Integer::FOO
# true
Integer::FOO.instance_of? Integer
# true
Integer::FOO == 0
# false
The tricky part is making sure you cover all of the use cases. My code handles all of the requirements you listed but I have no idea what kind of weird side effects such a strange object would create.

Another option is to create a true Integer instance using a C extension:
// IntegerFoo.c
#include "ruby.h"
void Init_integer_foo() {
// this should be the equivalent of "Integer.new"
NEWOBJ_OF(obj, struct RObject, rb_cInteger, T_OBJECT | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 0));
rb_define_const(rb_cInteger, "FOO", (VALUE)obj);
}
# extconf.rb
require 'mkmf'
dir_config('integer_foo')
create_makefile('integer_foo')
After building the extension ...
$ ruby extconf.rb
creating Makefile
$ make
compiling IntegerFoo.c
linking shared-object integer_foo.bundle
... the new constant can be used in Ruby and it seems to work as expected:
require './integer_foo'
Integer::FOO #=> #<Integer:0x007fe40c02c040>
Integer::FOO.kind_of? Integer #=> true
Integer::FOO.class #=> Integer
Integer === Integer::FOO #=> true
Integer::FOO.instance_of? Integer #=> true
Integer::FOO == 0 #=> false

I think the hack of picking an number you won't encounter anywhere is likely to be the cleanest solution.
class Integer
FOO = (1..100).map{rand(10)}.join.to_i
end
Satisfies all of your criteria, aside from being equal to a random 100-digit number.
You can still introduce some custom behavior with this trick:
# Allow singleton methods on Bignums
class Bignum
def singleton_method_added(meth)
true
end
end
class Integer
FOO = (1..100).map{rand(10)}.join.to_i
FOO.define_singleton_method(:to_s){'FOO'}
end
#Disallow singleton methods on Bignums once we've added all we're going to
class Bignum
def singleton_method_added(meth)
super
end
end
p Integer::FOO # FOO
1111111111111111111111111111111.define_singleton_method(:will_raise){}

Related

Ruby Set with custom class to equal basic strings

I want to be able to find a custom class in my set given just a string. Like so:
require 'set'
Rank = Struct.new(:name, keyword_init: true) {
def hash
name.hash
end
def eql?(other)
hash == other.hash
end
def ==(other)
hash == other.hash
end
}
one = Rank.new(name: "one")
two = Rank.new(name: "two")
set = Set[one, two]
but while one == "one" and one.eql?("one") are both true, set.include?("one") is still false. what am i missing?
thanks!
Set is built upon Hash, and Hash considers two objects the same if:
[...] their hash value is identical and the two objects are eql? to each other.
What you are missing is that eql? isn't necessarily commutative. Making Rank#eql? recognize strings doesn't change the way String#eql? works:
one.eql?('one') #=> true
'one'.eql?(one) #=> false
Therefore it depends on which object is the hash key and which is the argument to include?:
Set['one'].include?(one) #=> true
Set[one].include?('one') #=> false
In order to make two objects a and b interchangeable hash keys, 3 conditions have to be met:
a.hash == b.hash
a.eql?(b) == true
b.eql?(a) == true
But don't try to modify String#eql? – fiddling with Ruby's core classes isn't recommended and monkey-patching probably won't work anyway because Ruby usually calls the C methods directly for performance reasons.
In fact, making both hash and eql? mimic name doesn't seem like a good idea in the first place. It makes the object's identity ambiguous which can lead to very strange behavior and hard to find bugs:
h = { one => 1, 'one' => 1 }
#=> {#<struct Rank name="one">=>1, "one"=>1}
# vs
h = { 'one' => 1, one => 1 }
#=> {"one"=>1}
what am i missing?
What you are missing is that "one" isn't in your set. one is in your set, but "one" isn't.
Therefore, the answer Ruby is giving you is perfectly correct.
All that you have done with your implementation of Rank is that any two ranks with the same name are considered to be the same by a Hash, Set, or Array#uniq. But, a Rank is not the same as a String.
If you want to be able to have a set-like data structure where you can look up things by one of their attributes, you will have to write it yourself.
Something like (untested):
class RankSet < Set
def [](*args)
super(*args.map(&:name))
end
def each
return enum_for(__callee__) unless block_given?
super {|e| yield e.name }
end
end
might get you started.
Or, instead of writing your own set, you can just use the fact that any arbitrary rank with the right name can be used for lookup:
set.include?(Rank.new(name: "one"))
#=> true
# even though it is a *different* `Rank` object

Ruby code to check for Integer [duplicate]

I need a function, is_an_integer, where
"12".is_an_integer? returns true.
"blah".is_an_integer? returns false.
How can I do this in Ruby? I would write a regex but I'm assuming there is a helper for this that I am not aware of.
Well, here's the easy way:
class String
def is_integer?
self.to_i.to_s == self
end
end
>> "12".is_integer?
=> true
>> "blah".is_integer?
=> false
I don't agree with the solutions that provoke an exception to convert the string - exceptions are not control flow, and you might as well do it the right way. That said, my solution above doesn't deal with non-base-10 integers. So here's the way to do with without resorting to exceptions:
class String
def integer?
[ # In descending order of likeliness:
/^[-+]?[1-9]([0-9]*)?$/, # decimal
/^0[0-7]+$/, # octal
/^0x[0-9A-Fa-f]+$/, # hexadecimal
/^0b[01]+$/ # binary
].each do |match_pattern|
return true if self =~ match_pattern
end
return false
end
end
You can use regular expressions. Here is the function with #janm's suggestions.
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
end
An edited version according to comment from #wich:
class String
def is_i?
/\A[-+]?\d+\z/ === self
end
end
In case you only need to check positive numbers
if !/\A\d+\z/.match(string_to_check)
#Is not a positive number
else
#Is all good ..continue
end
You can use Integer(str) and see if it raises:
def is_num?(str)
!!Integer(str)
rescue ArgumentError, TypeError
false
end
It should be pointed out that while this does return true for "01", it does not for "09", simply because 09 would not be a valid integer literal. If that's not the behaviour you want, you can add 10 as a second argument to Integer, so the number is always interpreted as base 10.
Ruby 2.6.0 enables casting to an integer without raising an exception, and will return nil if the cast fails. And since nil mostly behaves like false in Ruby, you can easily check for an integer like so:
if Integer(my_var, exception: false)
# do something if my_var can be cast to an integer
end
"12".match(/^(\d)+$/) # true
"1.2".match(/^(\d)+$/) # false
"dfs2".match(/^(\d)+$/) # false
"13422".match(/^(\d)+$/) # true
You can do a one liner:
str = ...
int = Integer(str) rescue nil
if int
int.times {|i| p i}
end
or even
int = Integer(str) rescue false
Depending on what you are trying to do you can also directly use a begin end block with rescue clause:
begin
str = ...
i = Integer(str)
i.times do |j|
puts j
end
rescue ArgumentError
puts "Not an int, doing something else"
end
class String
def integer?
Integer(self)
return true
rescue ArgumentError
return false
end
end
It isn't prefixed with is_. I find that silly on questionmark methods, I like "04".integer? a lot better than "foo".is_integer?.
It uses the sensible solution by sepp2k, which passes for "01" and such.
Object oriented, yay.
The Best and Simple way is using Float
val = Float "234" rescue nil
Float "234" rescue nil #=> 234.0
Float "abc" rescue nil #=> nil
Float "234abc" rescue nil #=> nil
Float nil rescue nil #=> nil
Float "" rescue nil #=> nil
Integer is also good but it will return 0 for Integer nil
I prefer:
config/initializers/string.rb
class String
def number?
Integer(self).is_a?(Integer)
rescue ArgumentError, TypeError
false
end
end
and then:
[218] pry(main)> "123123123".number?
=> true
[220] pry(main)> "123 123 123".gsub(/ /, '').number?
=> true
[222] pry(main)> "123 123 123".number?
=> false
or check phone number:
"+34 123 456 789 2".gsub(/ /, '').number?
A much simpler way could be
/(\D+)/.match('1221').nil? #=> true
/(\D+)/.match('1a221').nil? #=> false
/(\D+)/.match('01221').nil? #=> true
Personally I like the exception approach although I would make it a little more terse:
class String
def integer?(str)
!!Integer(str) rescue false
end
end
However, as others have already stated, this doesn't work with Octal strings.
This might not be suitable for all cases simplely using:
"12".to_i => 12
"blah".to_i => 0
might also do for some.
If it's a number and not 0 it will return a number. If it returns 0 it's either a string or 0.
def isint(str)
return !!(str =~ /^[-+]?[1-9]([0-9]*)?$/)
end
Here's my solution:
# /initializers/string.rb
class String
IntegerRegex = /^(\d)+$/
def integer?
!!self.match(IntegerRegex)
end
end
# any_model_or_controller.rb
'12345'.integer? # true
'asd34'.integer? # false
And here's how it works:
/^(\d)+$/is regex expression for finding digits in any string. You can test your regex expressions and results at http://rubular.com/.
We save it in a constant IntegerRegex to avoid unnecessary memory allocation everytime we use it in the method.
integer? is an interrogative method which should return true or false.
match is a method on string which matches the occurrences as per the given regex expression in argument and return the matched values or nil.
!! converts the result of match method into equivalent boolean.
And declaring the method in existing String class is monkey patching, which doesn't change anything in existing String functionalities, but just adds another method named integer? on any String object.
Ruby 2.4 has Regexp#match?: (with a ?)
def integer?(str)
/\A[+-]?\d+\z/.match? str
end
For older Ruby versions, there's Regexp#===. And although direct use of the case equality operator should generally be avoided, it looks very clean here:
def integer?(str)
/\A[+-]?\d+\z/ === str
end
integer? "123" # true
integer? "-123" # true
integer? "+123" # true
integer? "a123" # false
integer? "123b" # false
integer? "1\n2" # false
Expanding on #rado's answer above one could also use a ternary statement to force the return of true or false booleans without the use of double bangs. Granted, the double logical negation version is more terse, but probably harder to read for newcomers (like me).
class String
def is_i?
self =~ /\A[-+]?[0-9]+\z/ ? true : false
end
end
For more generalised cases (including numbers with decimal point),
you can try the following method:
def number?(obj)
obj = obj.to_s unless obj.is_a? String
/\A[+-]?\d+(\.[\d]+)?\z/.match(obj)
end
You can test this method in an irb session:
(irb)
>> number?(7)
=> #<MatchData "7" 1:nil>
>> !!number?(7)
=> true
>> number?(-Math::PI)
=> #<MatchData "-3.141592653589793" 1:".141592653589793">
>> !!number?(-Math::PI)
=> true
>> number?('hello world')
=> nil
>> !!number?('hello world')
=> false
For a detailed explanation of the regex involved here, check out this blog article :)
One liner in string.rb
def is_integer?; true if Integer(self) rescue false end
I'm not sure if this was around when this question is asked but
for anyone that stumbles across this post, the simplest way is:
var = "12"
var.is_a?(Integer) # returns false
var.is_a?(String) # returns true
var = 12
var.is_a?(Integer) # returns true
var.is_a?(String) # returns false
.is_a? will work with any object.

Comparison of Classes using the `===` (subsumption operator)

The fact that TypeOfClass === TypeOfClass is false strikes me as counter-intuitive. In the following code, even if field.class is the same class, it evaluates to false:
case field.class
when Fixnum, Float
field + other_field
when Date, DateTime, Time
field
else
puts 'WAT?'
end
I did this:
Fixnum === Fixnum # => false
Class === Class # => true
I found another thread:
Integer === 3 # => true
Fixnum === 3 # => true
3.class # => Fixnum
I fail to find a reason for this language design. What were the language designers thinking when they baked in this behavior?
I think this is relevant to the answer provided in another thread. It is not unnatural to assume that Numeric === Integer since an Integer is a more specific type of Numeric. But, it isn't:
Numeric === Integer #=> false
I think case statements or === requires caution. If this operator is what we think it is , then, a Numeric should be a Numeric, an Integer should be a Numeric, etc.
Does anyone have an explanation of why this feature doesn't extend to classes? It seems like it would be easy enough to return true if the compared class is a member of the class' ancestors.
Based on an answer submitted below, the code was originally classifying Time (as extended by ActiveSupport:CoreExtensions::Integer::Time and ActiveSupport:CoreExtensions::Float::Time):
Timeframe = Struct.new(:from, :to) do
def end_date
case self.to
when Fixnum, Float
self.from + self.to
when Date, DateTime, Time
self.to
else
raise('InvalidType')
end
end
end
and in the console, I get:
tf = Timeframe.new(Time.now, 5.months)
# => #<struct Timeframe from=Tue Dec 10 11:34:34 -0500 2013, to=5 months>
tf.end_date
# => RuntimeError: InvalidType
# from timeframe.rb:89:in `end_date'
I do not really see the problem here. For classes, the case equality operator asks whether the left hand argument is an instance of the class (or any subclass). So Fixnum === Fixnum really asks: "Is the Fixnum class itself a subclass of Fixnum?" No it is not.
Is the class Class itself a class? Class === Class, yes it is.
The point of the operator is that you should not need to go look for the class. What is wrong with using the case statement without the .class method in the beginning?
case field
when Fixnum, Float
field + other_field
when Date, DateTime, Time
field
else
puts 'WAT?'
end
If you have a more complex example you can write your own lambdas to make the case statement easier:
field_is_number = -> x {[Fixnum, Float].include? x.class}
field_is_time = -> x {[Date, DateTime, Time].include? x.class}
case field.class
when field_is_number
field + other_field
when field_is_time
field
else
puts 'WAT?'
end
That's Module#=== and its intended behavior:
mod === obj → true or false
Case Equality—Returns true if anObject is an instance of mod or one of
mod’s descendants. Of limited use for modules, but can be used in case
statements to classify objects by class.
It simply returns obj.kind_of? mod:
Fixnum === Fixnum #=> false
Fixnum.kind_of? Fixnum #=> false
Class === Class #=> true
Class.kind_of? Class #=> true
String === "foo" #=> true
"foo".kind_of? String #=> true
3 is both, an Integer and a Fixnum because of its class hierarchy:
3.kind_of? Integer #=> true
3.kind_of? Fixnum #=> true
3.class.ancestors #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Numeric is not an Integer, it's a Class:
Numeric.kind_of? Integer #=> false
Numeric.kind_of? Class #=> true
But 3, (2/3) and 1.23 are all Numeric:
3.kind_of? Numeric #=> true
Rational(2, 3).kind_of? Numeric #=> true
1.23.kind_of? Numeric #=> true
Bottom line: for case statements, just use case obj instead of case obj.class.
Update
You are getting this error because 5.months doesn't return an Integer, but a ActiveSupport::Duration:
Integer === 5.months #=> false
ActiveSupport::Duration === 5.months #=> true
Calling your method with 5.months.to_i or adding ActiveSupport::Duration to your classes should fix it.
If one of the operands is a class, it is checking whether the second one is this class instance. If they are both classes it will return false unless at least one of them is Class.
Note that Class is both a class and an instance of itself - it's probably biggest ruby weird TBH, but it makes perfect sense.
The reason I would vote for keeping this logic is that we can write those nice case statements without adding .class to objects.
Summary:
ClassName === object <=> object.kind_of? ClassName
However, if you really want to override this use:
class Class
def ===(object)
return object == self if object.is_a? Class
super
end
end

Checking if a variable is an integer

Does Rails 3 or Ruby have a built-in way to check if a variable is an integer?
For example,
1.is_an_int #=> true
"dadadad#asdasd.net".is_an_int #=> false?
You can use the is_a? method
>> 1.is_a? Integer
=> true
>> "dadadad#asdasd.net".is_a? Integer
=> false
>> nil.is_a? Integer
=> false
If you want to know whether an object is an Integer or something which can meaningfully be converted to an Integer (NOT including things like "hello", which to_i will convert to 0):
result = Integer(obj) rescue false
Use a regular expression on a string:
def is_numeric?(obj)
obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
If you want to check if a variable is of certain type, you can simply use kind_of?:
1.kind_of? Integer #true
(1.5).kind_of? Float #true
is_numeric? "545" #true
is_numeric? "2aa" #false
If you're uncertain of the type of the variable (it could be a string of number characters), say it was a credit card number passed into the params, so it would originally be a string but you want to make sure it doesn't have any letter characters in it, I would use this method:
def is_number?(obj)
obj.to_s == obj.to_i.to_s
end
is_number? "123fh" # false
is_number? "12345" # true
#Benny points out an oversight of this method, keep this in mind:
is_number? "01" # false. oops!
There's var.is_a? Class (in your case: var.is_a? Integer); that might fit the bill. Or there's Integer(var), where it'll throw an exception if it can't parse it.
You can use triple equal.
if Integer === 21
puts "21 is Integer"
end
A more "duck typing" way is to use respond_to? this way "integer-like" or "string-like" classes can also be used
if(s.respond_to?(:match) && s.match(".com")){
puts "It's a .com"
else
puts "It's not"
end
In case you don't need to convert zero values, I find the methods to_i and to_f to be extremely useful since they will convert the string to either a zero value (if not convertible or zero) or the actual Integer or Float value.
"0014.56".to_i # => 14
"0014.56".to_f # => 14.56
"0.0".to_f # => 0.0
"not_an_int".to_f # 0
"not_a_float".to_f # 0.0
"0014.56".to_f ? "I'm a float" : "I'm not a float or the 0.0 float"
# => I'm a float
"not a float" ? "I'm a float" : "I'm not a float or the 0.0 float"
# => "I'm not a float or the 0.0 float"
EDIT2 : be careful, the 0 integer value is not falsey it's truthy (!!0 #=> true) (thanks #prettycoder)
EDIT
Ah just found out about the dark cases... seems to only happen if the number is in first position though
"12blah".to_i => 12
To capitalize on the answer of Alex D, using refinements:
module CoreExtensions
module Integerable
refine String do
def integer?
Integer(self)
rescue ArgumentError
false
else
true
end
end
end
end
Later, in you class:
require 'core_ext/string/integerable'
class MyClass
using CoreExtensions::Integerable
def method
'my_string'.integer?
end
end
I have had a similar issue before trying to determine if something is a string or any sort of number whatsoever. I have tried using a regular expression, but that is not reliable for my use case. Instead, you can check the variable's class to see if it is a descendant of the Numeric class.
if column.class < Numeric
number_to_currency(column)
else
column.html_safe
end
In this situation, you could also substitute for any of the Numeric descendants: BigDecimal, Date::Infinity, Integer, Fixnum, Float, Bignum, Rational, Complex
Basically, an integer n is a power of three, if there exists an integer x such that n == 3x.
So to verify that you can use this functions
def is_power_of_three(n)
return false unless n.positive?
n == 3**(Math.log10(n)/Math.log10(3)).to_f.round(2)
end
Probably you are looking for something like this:
Accept "2.0 or 2.0 as an INT but reject 2.1 and "2.1"
num = 2.0
if num.is_a? String num = Float(num) rescue false end
new_num = Integer(num) rescue false
puts num
puts new_num
puts num == new_num

How to check if a Ruby object is a Boolean

I can't seem to check if an object is a boolean easily. Is there something like this in Ruby?
true.is_a?(Boolean)
false.is_a?(Boolean)
Right now I'm doing this and would like to shorten it:
some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))
Simplest way I can think of:
# checking whether foo is a boolean
!!foo == foo
I find this to be concise and self-documenting:
[true, false].include? foo
If using Rails or ActiveSupport, you can even do a direct query using in?
foo.in? [true, false]
Checking against all possible values isn't something I'd recommend for floats, but feasible when there are only two possible values!
There is no Boolean class in Ruby, the only way to check is to do what you're doing (comparing the object against true and false or the class of the object against TrueClass and FalseClass). Can't think of why you would need this functionality though, can you explain? :)
If you really need this functionality however, you can hack it in:
module Boolean; end
class TrueClass; include Boolean; end
class FalseClass; include Boolean; end
true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true
As stated above there is no boolean class just TrueClass and FalseClass however you can use any object as the subject of if/unless and everything is true except instances of FalseClass and nil
Boolean tests return an instance of the FalseClass or TrueClass
(1 > 0).class #TrueClass
The following monkeypatch to Object will tell you whether something is an instance of TrueClass or FalseClass
class Object
def boolean?
self.is_a?(TrueClass) || self.is_a?(FalseClass)
end
end
Running some tests with irb gives the following results
?> "String".boolean?
=> false
>> 1.boolean?
=> false
>> Time.now.boolean?
=> false
>> nil.boolean?
=> false
>> true.boolean?
=> true
>> false.boolean?
=> true
>> (1 ==1).boolean?
=> true
>> (1 ==2).boolean?
=> true
If your code can sensibly be written as a case statement, this is pretty decent:
case mybool
when TrueClass, FalseClass
puts "It's a bool!"
else
puts "It's something else!"
end
An object that is a boolean will either have a class of TrueClass or FalseClass so the following one-liner should do the trick
mybool = true
mybool.class == TrueClass || mybool.class == FalseClass
=> true
The following would also give you true/false boolean type check result
mybool = true
[TrueClass, FalseClass].include?(mybool.class)
=> true
So try this out (x == true) ^ (x == false) note you need the parenthesis but this is more beautiful and compact.
It even passes the suggested like "cuak" but not a "cuak"... class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)
Note: See that this is so basic that you can use it in other languages too, that doesn't provide a "thing is boolean".
Note 2: Also you can use this to say thing is one of??: "red", "green", "blue" if you add more XORS... or say this thing is one of??: 4, 5, 8, 35.
This gem adds a Boolean class to Ruby with useful methods.
https://github.com/RISCfuture/boolean
Use:
require 'boolean'
Then your
true.is_a?(Boolean)
false.is_a?(Boolean)
will work exactly as you expect.
No. Not like you have your code. There isn't any class named Boolean. Now with all the answers you have you should be able to create one and use it. You do know how to create classes don't you? I only came here because I was just wondering this idea myself. Many people might say "Why? You have to just know how Ruby uses Boolean". Which is why you got the answers you did. So thanks for the question. Food for thought. Why doesn't Ruby have a Boolean class?
NameError: uninitialized constant Boolean
Keep in mind that Objects do not have types. They are classes. Objects have data. So that's why when you say data types it's a bit of a misnomer.
Also try rand 2 because rand 1 seems to always give 0. rand 2 will give 1 or 0
click run a few times here.
https://repl.it/IOPx/7
Although I wouldn't know how to go about making a Boolean class myself. I've experimented with it but...
class Boolean < TrueClass
self
end
true.is_a?(Boolean) # => false
false.is_a?(Boolean) # => false
At least we have that class now but who knows how to get the right values?

Resources