mandag 24. mai 2010

Parsing the /etc/passwd file with Ruby

I decided to write a program to parse the /etc/passwd file in my favourite scripting language. The file has seven fields: user, password, UID, GID, GECOS, home and shell.

Writing this snippet of code, I used some metaprogramming features in Ruby that I learned from Metaprogramming Ruby by Paolo Perrotta, like "OpenStruct", Dynamic Methods and method_missing(). I created a structure to hold the field information for each line in the file like this:

class PasswdFile
class PasswdEntry
def initialize
@attributes = {}
end

def method_missing(name, *args)
attribute = name.to_s
if attribute =~ /=$/
@attributes[attribute.chop] = args[0]
else
@attributes[attribute]
end
end

def import(line)
field_names = [:user, :password, :uid, :gid, :gecos, :home, :shell]
fields = line.split(":")
puts "Error: Not a passwd line, not 7 fields" unless fields.length == 7
field_names.each do |field_name|
self.send("#{field_name}=", fields[field_names.index(field_name)])
end
end
end

attr_reader :filename
def initialize(filename="/etc/passwd")
@entries = []
import(filename)
end

def import(filename)
File.open(filename, "r").each do |line|
entry = PasswdEntry.new
entry.import line
@entries << entry
end
end

def each
@entries.each do |entry|
yield entry
end
end

def print
field_names = [:user, :password, :uid, :gid, :gecos, :home, :shell]

@entries.each do |entry|
puts "ENTRY:"
field_names.each do |field_name|
puts " #{field_name}: " + entry.send("#{field_name}")
end
end
end
end

To show an example of useage, we can print each field, like this:

entries = PasswdFile.new
entries.print

1 kommentar:

Matteo sa...

Hi,
I would like to have more info about the method:

def each
@entries.each do |entry|
yield entry
end
end

Exactly, What it do?