Ruby Findings

digging for gems

ieeemac.rb, why let python have all the fun?

Posted by Bill Marquette Tue, 01 Apr 2008 04:07:00 GMT

I was a little bored tonight and thought I’d respond to a post over Happy Python with some code. Thanks for the inspiration Matt!

ruby>> require 'ieeemac'
# => true  
ruby>> macs = Mac.find_macs `ifconfig -a`
# => [#<Mac:0x1357f40 @mac=["00", "16", "cb", "95", "13", "50"]>, #<Mac:0x1357f2c @mac=["00", "16", "cb", "ff", "fe", "5d"]>, #<Mac:0x1357d74 @mac=["00", "17", "f2", "41", "ec", "ec"]>, #<Mac:0x1357c20 @mac=["00", "50", "56", "c0", "00", "08"]>, #<Mac:0x1357ae0 @mac=["00", "50", "56", "c0", "00", "01"]>, #<Mac:0x135798c @mac=["00", "1c", "42", "00", "00", "00"]>, #<Mac:0x13577e8 @mac=["00", "1c", "42", "00", "00", "01"]>]  
ruby>> macs[0].to_format :cisco
# => "0016.cb95.1350"  
ruby>> macs[0].to_cisco
# => "0016.cb95.1350"  

Read the rest of this post for the full class.

# We got your MAC manipulation here
class Mac
  #bare:    001122334455
  #windows: 00-11-22-33-44-55
  #unix?:   00:11:22:33:44:55
  #cisco:   0011.2233.4455  
  VALID_MACS=/[0-9a-f]{12}|[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}|[0-9a-f]{4}\.[0-9a-f]{4}\.[0-9a-f]{4}/

  def initialize(str)
    if ismac?(str)
      # Convert to internal octet representation
      @mac = str.gsub(/[.:-]/,'').scan(/../)
    else
      raise ArgumentError, "Invalid MAC", caller
    end
  end

  # return all the valid MAC's in a given string as an array
  def self.find_macs(str)
    macs = str.scan VALID_MACS
    ret = []
    macs.each { |mac| ret << Mac.new(mac) }
    ret
  end

  def to_format(fmt)
    # Convert to symbol for ease of use
    fmt = fmt.to_sym
    case fmt
    when :bare
      to_bare
    when :windows
      to_windows
    when :unix
      to_unix
    when :cisco
      to_cisco
    end
  end

  def ismac?(str)
    VALID_MACS =~ str
  end

  def to_bare
    @mac.join('')
  end
  alias :mac :to_bare

  def to_windows
    @mac.join('-')
  end
  def to_unix
    @mac.join(':')
  end
  def to_cisco
    sprintf("%s%s.%s%s.%s%s", @mac[0],@mac[1],@mac[2],@mac[3],@mac[4],@mac[5])
  end
end

# macs = Mac.find_macs(`ifconfig -a`)
# macs.each do |mac|
#   puts "BARE:    #{mac.to_format(:bare)}"
#   puts "WINDOWS: #{mac.to_format(:windows)}"
#   puts "UNIX:    #{mac.to_format(:unix)}"
#   puts "CISCO:   #{mac.to_format(:cisco)}"
# end

Posted in | 2 comments |

Message queues in ruby

Posted by Bill Marquette Thu, 27 Dec 2007 18:59:00 GMT

Sometimes you run across neat and interesting libraries when you are reading up on something completely different. Case in point, via another blog, I stumbled on Reliable Messaging with Ruby. This looks to solve a problem I haven’t yet run into, but I know I’ll find a use for it in the future (maybe for a game I’m slowly working on, or a work project). As of today, there haven’t been any commits to the project for two years, but it’s entirely possible there are no bugs (except for the one I found below) and the author considers it feature complete.

Current feature list:

  • Simple API.
  • Transction processing.
  • Disk-based and MySQL message stores.
  • Best effort, repeated and once-only delivery semantics.
  • Priority queues, message expiration, dead-letter queue.
  • Message selectors.
  • Local and remote queue managers using DRb.

Installation was a breeze

$ sudo gem install reliable-msg -y

For testing, I chose a disk queue, but the library also supports mysql for the message queue.

Note: I used sudo here as my normal user has no access to write the config file - were I to care about this install, I’d spend the time figuring out how to run the queue manager as a non-privileged user.

$ sudo queues install disk foo
Created queues configuration file: /Library/Ruby/Gems/1.8/gems/reliable-msg-1.1.0/queues.cfg

Start up the queue manager:

$ sudo queues manager start
Loaded queues configuration from: /Library/Ruby/Gems/1.8/gems/reliable-msg-1.1.0/queues.cfg
Using message store: disk
Accepting requests at: druby://localhost:6438

I had some issues with drb ACL’s that appear to be due to ACL ordering. After changing line 238 of queue-manager.rb from:

@drb_server = DRb::DRbServer.new drb_uri, self, :tcp_acl=>ACL.new(drb["acl"].split(" "), ACL::ALLOW_DENY)

to:

@drb_server = DRb::DRbServer.new drb_uri, self, :tcp_acl=>ACL.new(drb["acl"].split(" "), ACL::DENY_ALLOW)

I was able to have my test program run. Not sure why I had to make the change, but the queue manager is still denying non localhost connections after it, so I’m not terribly concerned.

$ ruby q.rb
Local: Hello queue master
Queue: Hello queue master

And the contents of q.rb:

require 'rubygems'
require 'reliable-msg'

world = String.new "Hello queue master"
queue = ReliableMsg::Queue.new 'my-queue'
queue.put world
msg = queue.get
puts "Local: #{world}"
puts "Queue: #{msg.object}"

I’m going to let this library permeate my subconscious and find a use for it sometime in the near future.

There is a doc for integrating this library with rails at Reliable Messaging with Rails. Also, AP4R appears to use Reliable Messaging for it’s queueing and looks like a well polished Rails plugin. I don’t have time to look at AP4R now, so I’ll leave a post on that for another day.

Posted in , | 1 comment |

Using Active Record from outside of Rails

Posted by Art Green Sun, 14 Oct 2007 16:26:00 GMT

I’ve read a bunch of conflicting advice on how to use active record models defined in a Rails application from outside Rails.

The following is the result of experimenting with others’ advice plus my own digging around:

require 'rubygems'
require 'active_record'
require '/path/to/rails/config/environment'

This should allow you to use your Rails models just like you would in a Rails controller:

#!/usr/local/bin/ruby

require 'rubygems'
require 'active_record'
require '/var/www/railsapp/config/environment'

m = MyModel.new
m.find_all.each { |row|
  puts row.some_column
}

Posted in , | 1 comment |

Dot quad mask to CIDR

Posted by Art Green Sat, 22 Sep 2007 05:01:00 GMT

def dqtocidr( mask )
  bitcount = 0
  mask.split('.').each { |octet|
    o = octet.to_i
    bitcount += (o & 1) and (o >>= 1) until o == 0
  }
  return bitcount
end

irb(main):016:0> dqtocidr(‘128.0.0.0’) => 1

irb(main):017:0> dqtocidr(‘192.0.0.0’) => 2

irb(main):018:0> dqtocidr(‘224.0.0.0’) => 3

irb(main):019:0> dqtocidr(‘240.0.0.0’) => 4

irb(main):020:0> dqtocidr(‘248.0.0.0’) => 5

irb(main):021:0> dqtocidr(‘252.0.0.0’) => 6

irb(main):022:0> dqtocidr(‘254.0.0.0’) => 7

irb(main):023:0> dqtocidr(‘255.0.0.0’) => 8

Posted in | no comments |

Object destruction

Posted by Art Green Fri, 07 Sep 2007 17:48:00 GMT

Ruby does not provide programmer defined destruction methods. In C++ you can define a method that is messaged when the object instance is destroyed. This method can perform clean-up operations such as deleting temporary files.

Ruby, however, destroys objects dynamically during a scheduled garbage collection. This means that, during a run, it is impossible to know when an object instance will be destroyed. This fact combined with the lack of a destruction method can create headaches when there is a need to clean-up during object destruction.

Since there is no direct support for a destructor method, you must call a custom function, or more specific a proc object, when the garbage collector is about to destroy the object. As stated before it is unpredictable when this occurs.

Also if such a finalizer object has a reference to the orignal object, this may prevent the original object to get garbage collected.

Because of this problem, the finalize method below is a class method and not a instance method. So if you need to free resources for an object, like closing a socket or killing a spawned subprocess, you should do it explicitly with the ObjectSpace class.

class MyClass
  def initialize
    ObjectSpace.define_finalizer(self,
     self.class.method(:finalize).to_proc)
  end

  def MyClass.finalize(id)
    puts "Object #{id} dying at #{Time.new}"
  end
end

# test code
3.times {
    MyClass.new
}
ObjectSpace.garbage_collect

Posted in | no comments |

Multiple class initialization methods

Posted by Art Green Thu, 06 Sep 2007 01:18:00 GMT

Here’s a quick run-down on the development of multiple initialize methods for Ruby classes: Multiple Initialize Methods.

The author looks at the subject from a domain language idiom perspective. I used the information to provide multiple creation interfaces for a class.

Quick example:

Class Archive
  def Archive.create( archive_name )
    return self.new( archive_name, :create )
  end

  def Archive.open( archive_name )
    return self.new( archive_name, :open )
  end

  def initialize( archive_name, mode )
    # do interesting stuff
  end
end

arch = Archive.open("some_existing_file")
arch = Archive.create("some_new_file")

Posted in , | no comments |


html>