Forum: Ruby numeric?

Posted by Brandon Weaver (Guest)
on 2012-12-27 19:40
(Received via mailing list)
I've found a bit of an annoyance trying to find out if a number is 
numeric
or not. I thought it would probably be a simple string method but I 
found
far more contrived solutions like regex matches. Eventually I settled on
monkey patching string with a Numeric? method using Float(self)! = nil
rescue false.

Is there a better way to go about this? If not, can we get something 
added
to the core?

Thanks for your time,

Brandon
Posted by Jonan S. (jonan_s)
on 2012-12-27 19:50
(Received via mailing list)
You might be better off to ask yourself why you need the type checking
anyway. If you have a method designed to handle an argument that might 
be a
string or an integer you might be trying to do two different things.

If you're sure you want the integer you could just to_i the input.
Posted by Tony Arcieri (Guest)
on 2012-12-27 19:54
(Received via mailing list)
Float(string) is your best bet. Why is this inadequate? Are you trying 
to
decide if a string "looks like a number" but don't want to work with it 
as
a number after that?
Posted by Peter Hickman (Guest)
on 2012-12-27 19:57
(Received via mailing list)
On 27 December 2012 18:50, Jonan Scheffler <jonanscheffler@gmail.com> 
wrote:

> You might be better off to ask yourself why you need the type checking
> anyway. If you have a method designed to handle an argument that might be a
> string or an integer you might be trying to do two different things.
>
> If you're sure you want the integer you could just to_i the input.
>
>
Problem all strings will convert to integers.

"fred".to_i => 0
"69skiddoo".to_i => 69
"".to_i => 0

I suspect that these would not be considered numbers.
Posted by Brandon Weaver (Guest)
on 2012-12-27 19:58
(Received via mailing list)
I can't control null returns on certain statements considering it 
retrieves
data from live devices. If a live device is down it returns null or
similar. There are enough different devices that report different 
variants
of null that in order to be more flexible, numeric is my most viable
option.
Posted by Brandon Weaver (Guest)
on 2012-12-27 20:11
(Received via mailing list)
Trust me, I wish there was a cleaner way to handle this instead of this
inelegant hack I have to make.

To clarify, I work at a WISP that has several different brands of 
antennas.
In order to have an effective and DRY solution, I have to be very 
abstract.
Unfortunatelly the way null or empty is reported is only consistently a
string, making numeric as clean as I can get.

If anyone has a better idea I would love to hear it. I come from a C
background so I still have some bleeding effects from the transfer.
Posted by Damián M. González (igorjorobus)
on 2012-12-27 23:13
I think we need more information, the return values are fixeds? what are 
they?
Posted by Brandon Weaver (Guest)
on 2012-12-27 23:33
(Received via mailing list)
Sorry, I wasn't very clear. I was typing most of that from my Phone.

I'm writing scripts for a wireless ISP, and we use several different 
types
of antennas. They're monitored in several different ways,
SSH/Telnet/SNMP/etc. Annoyingly they all return different values for 
null,
but they're always string based, so a numeric evaluation will quickly 
yield
whether the device is working or down. I could write a more correct
solution in the sense that it's less of a hack with individual classes 
for
every antenna, but the goal is that if we ever get a new type of 
equipment
that it will take minimal coding to get a framework up and running for 
it.

The main concept here is making the code as DRY as possible, and to
abstract the testing as far from the hardware as possible so as to give
more general statistics for the entire network. I'm not particularly 
good
at articulating this one.

One such example is min, max, and avg for multiple fields such as Signal 
to
Noise, Retransmit, and etc. I used instance_variable_get to dynamically
evaluate fields. There are ways in which I could probably use more of
Enumerator, and I still need to sort that out some more.
Posted by Robert Klemme (robert_k78)
on 2012-12-28 00:35
(Received via mailing list)
On Thu, Dec 27, 2012 at 11:32 PM, Brandon Weaver
<keystonelemur@gmail.com> wrote:
> Sorry, I wasn't very clear. I was typing most of that from my Phone.
>
> I'm writing scripts for a wireless ISP, and we use several different types
> of antennas. They're monitored in several different ways,
> SSH/Telnet/SNMP/etc. Annoyingly they all return different values for null,
> but they're always string based, so a numeric evaluation will quickly yield
> whether the device is working or down. I could write a more correct solution
> in the sense that it's less of a hack with individual classes for every
> antenna, but the goal is that if we ever get a new type of equipment that it
> will take minimal coding to get a framework up and running for it.

What's wrong then to use Float() as suggested?

begin
  f = Float(from_device)
  printf "Read value %20.5f\n", f
rescue ArgumentError => e
  # not a float
end

An alternative would be to convert non numeric values to nil - if you
want safe null handling:

f = Float(from_device) rescue nil

> One such example is min, max, and avg for multiple fields such as Signal to
> Noise, Retransmit, and etc. I used instance_variable_get to dynamically
> evaluate fields. There are ways in which I could probably use more of
> Enumerator, and I still need to sort that out some more.

You could use Structs and then:

irb(main):001:0> S=Struct.new :a, :b, :c
=> S
irb(main):002:0> S.members
=> [:a, :b, :c]
irb(main):003:0> S.new.members
=> [:a, :b, :c]
irb(main):004:0> s = S.new 1,2,3
=> #<struct S a=1, b=2, c=3>
irb(main):005:0> s.members
=> [:a, :b, :c]
irb(main):006:0> s.each_pair {|k,v| printf "%p=%p\n", k, v}
:a=1
:b=2
:c=3
=> #<struct S a=1, b=2, c=3>

Kind regards

robert
Posted by Brandon Weaver (Guest)
on 2012-12-28 01:05
(Received via mailing list)
I've already sorted them into classes and objects, so instance variables
are created for every antenna and other such things.

On Thu, Dec 27, 2012 at 5:27 PM, Robert Klemme
Posted by Grant Schoep (matobinder)
on 2012-12-28 05:22
> Problem all strings will convert to integers.
>
> "fred".to_i => 0
> "69skiddoo".to_i => 69
> "".to_i => 0
>
> I suspect that these would not be considered numbers.


In these cases, I just double convert i.e.

irb(main):016:0> buffer = 'fred'
=> "fred"
irb(main):017:0> buffer.to_i.to_s == buffer
=> false

And then
irb(main):001:0> buffer = '42'
=> "42"
irb(main):002:0> buffer.to_i.to_s == buffer
=> true
Posted by Brandon Weaver (Guest)
on 2012-12-28 05:34
(Received via mailing list)
I've seen a similar solution as well. I've just monkey patched string 
with
the float conversion.
Posted by Damián M. González (igorjorobus)
on 2012-12-28 05:41
> In these cases, I just double convert i.e.
>
> irb(main):016:0> buffer = 'fred'
> => "fred"
> irb(main):017:0> buffer.to_i.to_s == buffer
> => false

 Have to say that that's very cleaver. Very good solution.
Posted by Robert Klemme (robert_k78)
on 2012-12-28 12:36
(Received via mailing list)
On Fri, Dec 28, 2012 at 5:41 AM, Damin M. Gonzlez
<lists@ruby-forum.com> wrote:
>> In these cases, I just double convert i.e.
>>
>> irb(main):016:0> buffer = 'fred'
>> => "fred"
>> irb(main):017:0> buffer.to_i.to_s == buffer
>> => false
>
>  Have to say that that's very cleaver. Very good solution.

Sorry to disagree.  There are more clever solutions:

Use an Integer and deal with the exception.

1. immediately

irb(main):001:0> buffer = 'fred'
=> "fred"
irb(main):002:0> i = Integer(buffer)
ArgumentError: invalid value for Integer(): "fred"
        from (irb):2:in `Integer'
        from (irb):2
        from /usr/bin/irb:12:in `<main>'
irb(main):003:0> begin; i = Integer(buffer); puts "int"; rescue
ArgumentError; puts "no int"; end
no int
=> nil

2. by converting the value to nil if it is not a number

irb(main):004:0> j = Integer(buffer) rescue nil
=> nil
irb(main):005:0> if j; puts "int"; else puts "no int"; end
no int
=> nil

Kind regards

robert
Posted by Robert Klemme (robert_k78)
on 2012-12-28 12:41
(Received via mailing list)
On Fri, Dec 28, 2012 at 1:00 AM, Brandon Weaver 
<keystonelemur@gmail.com> wrote:
> I've already sorted them into classes and objects, so instance variables are
> created for every antenna and other such things.

The more I think about it the more I do believe it is responsibility
of the "driver" (i.e. the bit that fetches the data) to return _proper
data_.  In this case it would mean: do not return numbers as strings.
If values are invalid return a special value for that; this value
could be nil or one or more symbols depending on how many states need
to be represented.

The using code should expect data properly typed so it can do its 
business.

Another thought: if you create instance variables on the fly for
sensors then a Hash is probably a better alternative.  You could use a
specific class as values which encapsulates the data along with meta
data (valid, available, taken at...).  Example

SensorData = Struct.new :name, :value, :taken_at do
  def valid?
    value # nil is invalid
  end
end

Kind regards

robert
Posted by Damián M. González (igorjorobus)
on 2012-12-28 14:01
> The more I think about it the more I do believe it is responsibility
> of the "driver" (i.e. the bit that fetches the data) to return _proper
> data_.  In this case it would mean: do not return numbers as strings.
> If values are invalid return a special value for that; this value
> could be nil or one or more symbols depending on how many states need
> to be represented.
>
> The using code should expect data properly typed so it can do its
> business.

 Yes that ensure a proper work, but he says that at any time can enter a 
new antenna, and he wants to quickly put it working, so what we know is 
that all the null values are returned as strings. Perhaps just the null 
values are always returned as strings, the others values meaby are 
returned as Fixnums, so he wants to handle strings.
Posted by Robert Klemme (robert_k78)
on 2012-12-28 15:13
(Received via mailing list)
On Fri, Dec 28, 2012 at 2:01 PM, Damin M. Gonzlez
<lists@ruby-forum.com> wrote:
>  Yes that ensure a proper work, but he says that at any time can enter a
> new antenna, and he wants to quickly put it working,

And where is the problem with my approach?  Does it prevent getting
new devices to work quickly?

> so what we know is
> that all the null values are returned as strings. Perhaps just the null
> values are always returned as strings, the others values meaby are
> returned as Fixnums, so he wants to handle strings.

I'd rather not speculate but hear Brandon's comment on this.  Also,
even if what you say is true it still does not prevent the "driver"
layer to convert "null" strings into nil or something other meaningful
value.

Cheers

robert
Posted by Brandon Weaver (Guest)
on 2012-12-28 18:11
(Received via mailing list)
It uses ssh and SNMP to retrieve data. They return different strings, 
all
some variation of null, if the antenna is unreachable from the Au. I
decided to opt out of a multi conditional approach to every possible
variation of the word null.
Posted by Brian Candler (candlerb)
on 2013-01-02 09:56
A common example:

while new_sock = sock.accept
  Thread.new(new_sock) do |s|
     ... do stuff with 's'
  end
end

If you just use new_sock directly within the thread, then its value may 
change before you use it, because if a new incoming connection arrives 
the outer loop will reassign a new value to it.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.