On Dec 13, 2011, at 5:12 AM, Robert Klemme wrote:

> On Tue, Dec 13, 2011 at 12:41 AM, Chaim Keren-Tzion
> <chaim / intercomp.co.il> wrote:
>> Hi,
>> I've just started using Ruby last week and have a somewhat complex =
task to
>> complete in a short amount of time and nobody local to ask.
>>=20
>> Here is what I'm trying to find:
>> Given two arrays containing IP addresses like the ones below, how =
would I
>> search for the first element in 'servers' that pattern matches and =
element
>> in 'nics' where only the first 2 parts of the IP addresses need to =
match,
>> like 192.168.*.* or 10.14.*.* or 98.139.*.*
>>=20
>> servers =3D Array["192.168.0.251","10.14.0.142","98.139.180.149"]
>> nics =3D Array["10.10.0.255","173.194.37.16","10.14.0.170"]
>>=20
>> I've got some kind of beginning with the code below but I'm stuck. =
Any
>> hints?
>>=20
>> ----------------
>> log_server =3D "nothing"
>>=20
>> until log_server !=3D "nothing" servers.each |thisip| do
>>=20
>> # Consider only the first two parts of the 'thisip' IP address =
(192.168.*.*
>> or 10.14.*.* or 98.139.*.*)
>> # Compare it with each element in 'nics'
>> # Set 'log_server' equal to the first value of 'thisip' that pattern
>> matches an element in 'nics'
>> log_server =3D thisip
>>=20
>> end
>> ----------------
>=20
> I would approach this like this:
>=20
> 1. Write a method which receives two arguments (servers and nics of =
course).
> 2. Let the method start by preparing the data, i.e. #map both arrays
> into something which is quicker to match.
> 3. iterate by doing servers_converted.each or maybe
> servers_converted.each_with_index and returning from the method on
> first match.
> 4. return nil at the end of the method (nothing found) or raise an
> exception depending on the wanted semantics
>=20
> Now, how to do the matching?  I would not use regular expressions for
> the matching as you really want to match numeric values.  Conversion
> could use ip.scan(/\d+/).map(&:to_i).  You could use Array#[] to
> obtain a two element Array from a four element Array.
>=20
> You could as well search for a gem which deals with IP addresses.
> Since the problem is so common chances are that such a beast exists.
>=20
> Kind regards
>=20
> robert
>=20
> --=20
> remember.guy do |as, often| as.you_can - without end
> http://blog.rubybestpractices.com/
>=20

Rather than search for a gem, look no further than the standard library =
and you'll come across the IPAddr library. (It's been in there long =
before 1.9.3 so you're almost certain to have it.)

$ irb
irb(main):001:0> RUBY_VERSION
=3D> "1.9.3"
irb(main):002:0> require 'ipaddr'
irb(main):003:0> servers =3D ["192.168.0.251", "10.14.0.142",  =
"98.139.180.149"].map {|ip| IPAddr.new(ip)}
irb(main):004:0> nics    =3D [ "10.10.0.255", "173.194.37.16", =
"10.14.0.170"   ].map {|ip| IPAddr.new("#{ip}/16")}
irb(main):005:0> log_server =3D servers.detect {|ip| nics.any? {|nic| =
nic.include? ip } }
=3D> #<IPAddr: IPv4:10.14.0.142/255.255.255.255>
irb(main):006:0> log_server.to_s
=3D> "10.14.0.142"

The /16 added to the mapping of nics is the number of bits in the =
network mask.

So translating Robert's approach:

1. Write a methods that receives two arguments, servers and nics (as =
arrays of IP strings). (Optionally, a third argument that gives the bits =
in the netmask, perhaps defaulting to 16.)
2. map the Strings to IPAddrs
3. detect (find) the first server having an IPAddr that is included in =
the nic's network.
4. (there is no step 4 ;-)

-Rob