Category: Code


ZenTest dropped redgreen

July 5th, 2009 — 3:19pm

If you’re used to running autospec for your spec tests, and you recently updated all of your gems, you might notice that the red/green coloring of your terminal disappeared. In fact you might notice that require 'autotest/redgreen' is throwing an exception.

Well I just found out that ZenTest dropped most of it’s plugins (redgreen being one) as of version 4.1.0.

The fix for me was to uninstall ZenTest then install ZenTest 4.0.0.

Maybe someone will give me the better solution? Did the plugin get a gem?

3 comments » | Code

Construction Driven Design

July 4th, 2009 — 5:56pm

[UPDATE] I made significant updates to Siffer because of this post and as a result the code you see here is no longer up-to-date. http://github.com/clinth3o/siffer and look at the Siffer::Xml.

A part of the SIF that I am implementing in Siffer is the Data Models. This part of Siffer could be extremely tedious. There are 101 of these things.

Each data model has it’s own elements (values if you will), which some are repeatable, conditional or mandatory. I also have to be able to output them in XML format. The end goal would be to output something like this for an Address Data Model:

<Address Type="0123">
  <Street>
    <Line1>1 IBM Plaza</Line1>
    <Line2>Suite 2000</Line2>
    <StreetNumber>1</StreetNumber>
    <StreetName>IBM</StreetName>
    <StreetType>Plaza</StreetType>
    <ApartmentType>Suite</ApartmentType>
    <ApartmentNumber>2000</ApartmentNumber>
  </Street>
  <City>Chicago</City>
  <County>Cook</County>
  <StateProvince>IL</StateProvince>
  <Country>US</Country>
  <PostalCode>60611</PostalCode>
  <GridLocation>
    <Latitude>41.850000</Latitude>
    <Longitude>-87.650000</Longitude>
  </GridLocation>
</Address>

I don’t want to write a class for each Data Model (remember there are 101 of them). That would suck. But it’s a required portion of the framework and I have to. So how do I do them in a way that is easy and fun?

I call it Construction Driven Design. I’m not sure I am the first to really come up with this concept. I did some googling and couldn’t find anything so I thought I’d share my idea. So here is the best definition I can come up with:

Defining the template of a class and how you want to write the class prior to any implementation.

Which is to say: Mock up the way you want to code each class, then fill in the details to make it work. The template portion of the definition is the key. First you create how you will “template” each of these similar classes before the “base” class ever exists. The most important part however is the how. You are defining how you want to write all of these classes. And that is where the term “Construction” comes into play. The design of the code is driven by how you want to construct the code physically. The Data Model section of the SIF is really the best example of when to use CDD. The circumstance is:

  • there are 100s of classes to create
  • they all share features and/or functionality
  • you can’t really make them all dynamic or runtime only, rather they have to be “physical”
  • and the most important part: you don’t want to spend the time coding each one with all of the appropriate getters/setters and methods

Let’s look at the Data Model code I created for Siffer, but first let’s look at what we might have to do for just the Address Data Model using the more traditional way:

require 'builder'
class Address

  attr_accessor :type, :street, :city, :county, :state_province
  attr_accessor :country, :postal_code, :grid_location

  def initialize(type, street, city, county, state, country, postal, grid)
    raise "Type is mandatory" unless type
    @type = type
    raise "Street is mandatory" unless street
    @street = street
    raise "City is mandatory" unless city
    @city = city
    @county = county
    raise "State/Province is mandatory" unless state
    @state_province = state
    raise "Postal Code is mandatory" unless postal
    @postal_code = postal
    raise "Country is mandatory" unless country
    @country = country
    @grid_location = grid
  end

  def to_xml
    xml = Builder::XmlMarkup.new
    xml.Address(:type => type) do |body|
      body.Street(street)
      body.City(city)
      body.State(state_province)
      body.County(county)
      body.Country(country)
      body.PostalCode(postal_code)
      body.GridLocation(grid_location)
    end
    xml.target!
  end

end

This would be the simplest form of the Address class. Whew. One down and only 100 more to go! Keep in mind though we are missing the conditional feature as well as repeatable attributes. Now the initialize method just got 5-10 lines longer. And consider this: Address contains elements that are themselves Data Models. Look at Street for example. It has it’s own sub elements. Now we can see that just to accomplish the Address Data Model we might be in for a hour or more of just typing. Bleh.

I don’t want to do this for 101 classes. So I sat down for a few minutes and thought about how I would want to write the classes. Let’s begin CDD!

Here is what I came up with:

class Address
  attribute :type
  element :street, :mandatory
  element :city
  element :county
  element :state_province
  element :country
  element :postal_code
  element :grid_location
end

As you can see, this way I write far few lines. The class definition is very easy to understand and I can control each element for mandatory, conditional and repeatable. I wouldn’t mind doing this for 101 classes!

Now that I have how I want to type each class, I need to implement the code that will make this all work. (a little note about Ruby – it’s beautiful in the way it can accomplish this). First I need a way to capture the method calls attribute and element. Let’s build a module:

module DataElement
  module ClassMethods

    def element(name, type = :o ptional, *conditions)
      class_eval "def #{name};@values[:#{name}];end"
      class_eval "def #{name}=(value);@values[:#{name}] = value;end"
      @mandatory ||= []
      @conditional ||= {}
      @mandatory << name if type == :mandatory
      @conditional[name] = conditions if type == :conditional
    end

    def attribute(name, default = nil)
      @attributes ||= {}
      @attributes[name] = default
    end

  end

  def self.included(base)
    base.extend ClassMethods
  end
end

Now I can make the Address class above include this module to get the attribute and element methods:

class Address
  include DataElement
  attribute :type
  element :street, :mandatory
  element :city
  element :county
  element :state_province
  element :country
  element :postal_code
  element :grid_location
end

That's a good look. The include statement defines the class as a data element. Now piece by piece I'll explain the module.

First the element method receives three arguments. The name of the element, the type (mandatory, conditional, repeatable) and the conditions if it's conditional. With those arguments we can create instance methods for each element. This dynamically builds our getters and setters (no more typing by hand!). Then it stores the mandatory and conditional elements for use later to perform validations. The attribute method does the same thing for the attributes of the Data Model.

But we're missing the way to initialize new instances of these Data models in an automated way. Again - we don't want to write an initialize method for all 101 of these classes. Stick it in the module!

  def initialize(values = {})
    write_attributes(values)
    values = remove_attributes(values)
    write(values)
    check_mandatory(values)
    check_conditional(values)
  end

  def write_attributes(values)
    @attributes ||= {}
    unless class_attributes.nil?
      class_attributes.each{|k,v| @attributes[k] = v}
      attr_values = values.slice(*class_attributes.keys)
      attr_values.each{|k,v| @attributes[k] = v}
    end
  end

  def remove_attributes(values)
    values.except(*class_attributes.keys) rescue values
  end

  def write(values)
    @values ||= {}
    values.each{|k,v| @values[k] = v}
  end

  def check_mandatory(values)
    mandatory.each do |element|
      unless values.keys.include?(element)
        raise "#{element.to_s.humanize} is mandatory for #{self.class}."
      end
    end
  end

  def check_conditional(values)
    unless values.keys.any?{|v| conditional.keys.include?(v)}
      conditional.each do |element, conditions|
        unless conditions.any?{|c| values.keys.include?(c)}
          raise "#{element.to_s.humanize} is mandatory for #{self.class}\
           if #{conditions.map{|c| c.to_s.humanize}.join(" or ")} is missing"
        end
      end
    end
  end

  def class_attributes
    self.class.instance_variable_get("@attributes")
  end

  def mandatory
    self.class.instance_variable_get("@mandatory")
  end

  def conditional
    self.class.instance_variable_get("@conditional")
  end

With these methods now in place we can initialize an Address like this:

@street = Street.new(:line_1 => "13618 W. Port Royale")
@grid = GridLocation.new(:longitude => 3.098, :latitude => 4.566)
@address = Address.new(:type =>"0123",
                        :street => @street,
                        :city => "Surprise",
                        :county => "Maricopa",
                        :state_province => "AZ",
                        :country => "US",
                        :postal_code => 85379,
                        :grid_location => @grid)

Hey - I snuck in the Street and GridLocation models there didn't I! Here they are:

class Street
  include DataElement
  element :line_1, :mandatory
  element :line_2
  element :line_3
  element :complex
  element :street_number
  element :street_prefix
  element :street_name
  element :street_type
  element :street_suffix
  element :apartment_type
  element :apartment_number_prefix
  element :apartment_number
  element :apartment_number_suffix
end

class GridLocation
  include DataElement
  element :longitude
  element :latitude
end

And then to get the xml output we need for each of these data models:

  def to_xml
    xml = Builder::XmlMarkup.new
    args = (attributes.nil?) ? self.class.to_s : [self.class.to_s, attributes]
    xml.tag!(*args) { |body|
      @values.each do |key, value|
        if(value.is_a?(DataElement))
          body << value.to_xml
        else
          body.tag!(key.to_s.classify, value)
        end
      end
    }
    xml.target!
  end

  alias :to_s :to_xml

So with all of this now I can create any Data Model I wish like this:

class ConstructionDrivenDesign
  include DataElement
  attribute :type, "kick-ass"
  element :laziness
  element :speed, :conditional, :laziness
end
@cdd = ConstructionDrivenDesign.new(:laziness => true)
@cdd_fast = ConstructionDrivenDesign.new(:type => "mach-1", :speed => "fast")
puts @cdd
puts @cdd_fast
<ConstructionDrivenDesign type="kick-ass"><Lazines>true</Lazines></ConstructionDrivenDesign>
<ConstructionDrivenDesign type="mach-1"><Speed>fast</Speed></ConstructionDrivenDesign>

Hopefully this illustrates Construction Driven Design. It's not rocket science. It's just a way for a lazy developer to get a lot done in the fewest keystrokes.

Comment » | Code

Separating Art from Serious

June 6th, 2009 — 7:12am

Thinking about my work tonight I had a quick vision. I want to be considered an artist. At the same time I want to be considered seriously. And in my head those two things compete. I don’t know why.

When I write code, I have these little fits where I delete whole sections. Why? Because I didn’t like the way it read on the screen. It worked. It solved the problem. But I didn’t like the way it felt. The code didn’t read the way I wanted it too.

Strange right?

And I have these arguments with myself about getting something done for the sake of getting it done. I tell myself “people will take you seriously when you solve something.” But on the way to solving whatever it is, I find myself not satisfied with the work I’ve done for aesthetic artistic reasons.

Somehow I have to separate serious from art. Or make my art serious.

Comment » | Code

Back to top