Numeric?

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

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.

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?

On 27 December 2012 18:50, Jonan S. [email protected]
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.

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.

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.

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.

I think we need more information, the return values are fixeds? what are
they?

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 K.

On Thu, Dec 27, 2012 at 11:32 PM, Brandon W.
[email protected] 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
=> #
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
=> #

Kind regards

robert

I’ve seen a similar solution as well. I’ve just monkey patched string
with
the float conversion.

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.

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

On Fri, Dec 28, 2012 at 5:41 AM, Damin M. Gonzlez
[email protected] 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
irb(main):003:0> begin; i = Integer(buffer); puts “int”; rescue
ArgumentError; puts “no int”; end
no int
=> nil

  1. 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

On Fri, Dec 28, 2012 at 1:00 AM, Brandon W.
[email protected] 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

On Fri, Dec 28, 2012 at 2:01 PM, Damin M. Gonzlez
[email protected] 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

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.

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.

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.