Many times when I'm creating a prototype of an application with Ruby I'll create my classes using a simple Struct technique I learned from a friend. This technique of using the Struct class makes my code shorter, and is at least as readable as writing a class out using any other method.
For example, in the following sample Ruby code, I define a simple Person
class using this Struct
shortcut:
class Person < # a define the fields for my version of a "Person" Struct.new(:first_name, :last_name, :address1, :address2, :city, :state, :zip) end
Using this technique to define my Person
class, I can then treat my class just like I normally would, using getter and setter methods to work with the fields, as shown in this larger class example:
class Person < # a define the fields for my version of a "Person" Struct.new(:first_name, :last_name, :address1, :address2, :city, :state, :zip) # a method to print out a csv record for the current Person. def print_csv_record # use the ternary operator to use one output format or the other last_name.length==0 ? printf(",") : printf("\"%s\",", last_name) first_name.length==0 ? printf(",") : printf("\"%s\",", first_name) address1.length==0 ? printf(",") : printf("\"%s\",", address1) address2.length==0 ? printf(",") : printf("\"%s\",", address2) city.length==0 ? printf(",") : printf("\"%s\",", city) state.length==0 ? printf(",") : printf("\"%s\",", state) # no commas on this last field zip.length==0 ? printf("") : printf("\"%s\"", zip) printf("\n") end end
As you can see, my print_csv_record
method accesses each field that I defined in my Struct.new
declaration. Pretty simple, and pretty cool, right?
If you haven't used the Struct
class like this before, here's a quick introduction to it from its documentation on the Ruby doc site:
A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class. The Struct class is a generator of specific classes, each one of which is defined to hold a set of variables and their accessors.
Accessing your class fields
As you might guess, we can also access our getters and setters from outside our Ruby class. The following code snippet shows how I create an array of Person
objects later on in my code, and how I access the class fields I need:
people = Array.new # loop through each record in the csv file, adding each record to our array f = File.open(input_file, "r") f.each_line { |line| words = line.split(',') p = Person.new # do a little work here to get rid of double-quotes and blanks p.last_name = words[0].tr_s('"', '').strip p.first_name = words[1].tr_s('"', '').strip p.address1 = words[2].tr_s('"', '').strip p.address2 = words[3].tr_s('"', '').strip p.city = words[4].tr_s('"', '').strip p.state = words[5].tr_s('"', '').strip p.zip = words[6].tr_s('"', '').strip people.push(p) } # a simple block to sort the data by the last_name field people.sort! { |a,b| a.last_name.downcase <=> b.last_name.downcase } # print out all the sorted records (just print to stdout) people.each { |p| p.print_csv_record }
There are several other ways you can use the Ruby Struct
class to simplify your Ruby class definitions, and I encourage you to read the Struct documentation page for further examples.
Other notes
Of course you can also define class fields and then use the attr_reader, attr_writer, or attr_accessor methods to define access to those fields, but for most of my work, I prefer this shorter and simpler approach using the Struct
class.