Aimred Developer Blog November 2009 Archive

RCAP 0.3 Released

I’ve just pushed out RCAP 0.3. This is a bugfix release and fixes some issues when parsing from YAML documents.

RCAP 0.2 Released

I’ve just pushed out the RCAP 0.2 gems. This release adds a whole bunch of textual goodness for developers. The main features in this release are

  • YAML Support
  • inspect/to_s implemented across all RCAP classes

For further information check out the RCAP project page, or you can read some release notes below.

YAML

The major feature in this release is support for YAML. YAML is a plain text serialization format designed to be easily readable and editable by both human and machine. RCAP has custom YAML generation and parsing methods to produce a YAML document that is as human friendly as possible. The following code

alert.to_yaml

will produce the following YAML document

Identifier: 2a1ba96d-16e4-4f52-85ea-0258c1440bd5
Sender: cape_town_disaster_relief@capetown.municipal.za
Sent: 2009-11-19T02:41:29+02:00
Status: Actual
Message Type: Alert
Scope: Public
Information: 
- Language: en-ZA
  Categories: [Transport, Fire]
  Event: Liquid Petroleoum Tanker Fire
  Urgency: Immediate
  Severity: Severe
  Certainty: Observed
  Headline: LIQUID PETROLEOUM TANKER FIRE ON N2 INCOMING FREEWAY
  Description: |-
    A liquid petroleoum tanker has caught fire on the N2 incoming freeway 1km
    after the R300 interchange.  Municipal fire fighting crews have been dispatched.
    Traffic control officers are on the scene and have diverted traffic onto
    alternate routes.

Alert messgaes can be read in from text files containing data formatted in YAML as generated by Alert#to_yaml.

 parsed_alert = RCAP::Alert.from_yaml( alert.to_yaml )

Inspect

I’ve written before on this blog that I believe objects should be as transparent to the end user as possible, and so I’ve tried to apply that to RCAP.

The larger complex classes in RCAP – Alert, Info and Area – have specially designed inspect methods making them easily readable by developers and users when viewed in an IRb command console. Here is an is a log of a console session showing the output for Alert and Info.

 1 >> alert
 2 => 
 3 .-------------------------------------------------------------.
 4 |ALERT                                                        |
 5 |-------------------------------------------------------------|
 6 |Identifier:   a5d154d5-4074-4de5-9ce9-98c6ccb4c5f9           |
 7 |Sender:       cape_town_disaster_relief@capetown.municipal.za|
 8 |Sent:         2009-11-20T12:33:24+02:00                      |
 9 |Status:       Actual                                         |
10 |Message Type: Alert                                          |
11 |Source:                                                      |
12 |Scope:        Public                                         |
13 |Restriction:                                                 |
14 |Addresses:                                                   |
15 |Code:                                                        |
16 |Note:                                                        |
17 |References:                                                  |
18 |Incidents:                                                   |
19 |Information:                                                 |
20 |  Liquid Petroleoum Tanker Fire(Immediate/Severe/Observed)   |
21 '-------------------------------------------------------------'
22 >> alert.infos.first
23 => 
24 .----------------------------------------------------------------------------------.
25 |INFO                                                                              |
26 |----------------------------------------------------------------------------------|
27 |Language:       en-ZA                                                             |
28 |Categories:     Transport Fire                                                    |
29 |Event:          Liquid Petroleoum Tanker Fire                                     |
30 |Response Types:                                                                   |
31 |Urgency:        Immediate                                                         |
32 |Severity:       Severe                                                            |
33 |Certainty:      Observed                                                          |
34 |Audience:                                                                         |
35 |Event Codes:    []                                                                |
36 |Effective:                                                                        |
37 |Onset:                                                                            |
38 |Expires:                                                                          |
39 |Sender Name:                                                                      |
40 |Headline:       LIQUID PETROLEOUM TANKER FIRE ON N2 INCOMING FREEWAY              |
41 |Description:                                                                      |
42 |  A liquid petroleoum tanker has caught fire on the N2 incoming freeway 1km       |
43 |  after the R300 interchange.  Municipal fire fighting crews have been dispatched.|
44 |  Traffic control officers are on the scene and have diverted traffic onto        |
45 |  alternate routes.                                                               |
46 |Instruction:                                                                      |
47 |Web:                                                                              |
48 |Contact:                                                                          |
49 |Parameters:                                                                       |
50 |                                                                                  |
51 |Resources:                                                                        |
52 |                                                                                  |
53 |Area:                                                                             |
54 |                                                                                  |
55 '----------------------------------------------------------------------------------'

To String

Along with inspect I’ve also implemented logical and consistent (I hope) to_s methods on all RCAP classes. These are mainly designed to produce a label describing the object that can be displayed on a single line. Below are examples for Alert and Info.

1 >> alert.to_s
2 => "cape_town_disaster_relief@capetown.municipal.za/a5d154d5-4074-4de5-9ce9-98c6ccb4c5f9/2009-11-20T12:33:24+02:00"
3 >> alert.infos.first.to_s
4 => "Liquid Petroleoum Tanker Fire(Immediate/Severe/Observed)"

Neat Ruby Tricks: File.open Return Values

Back when I started using Ruby I would often read in data from a file as follows

1 file = File.new( 'data.txt' )
2 parsed_data = parse( file )
3 file.close

Later I switched to using File.open which handles closing the file for you

1 parsed_data = nil # Required otherwise parsed_data will be nil outside the block
2 File.open( 'data.txt' ) do |file|
3   parsed_data = parse( file )
4 end

Recently I realised, and felt pretty stupid for not having realised it earlier, that File.open will return the last expression evaluated in it’s block. Which means the above can be rewritten as

1 parsed_data = File.open( 'data.txt' ) do |file|
2   parse( file )
3 end

or as a much more elegent single line version (and now my preferred method)

1 parsed_data = File.open( 'data.txt' ){ |file| parse( file )}

Comparing Objects With Many Attributes

If you’re implementing your own == method for a complex class you sometimes end up with code that looks like this

1 def ==( other )
2   self.attribute_1 == other.attribute_1 &&
3   self.attribute_2 == other.attribute_2 &&
4   self.attribute_3 == other.attribute_3 &&
5   # Code snipped for brevity
6   self.attribute_19 == other.attribute_19 &&
7   self.attribute_20 == other.attribute_20
8 end

If you’re not paying attention you could end up comparing the wrong attributes or comparing two attributes of the same object or even the same attribute with itself. Similarily leaving out a && can cause all code before that point to be ignored. Using some of the built in features of Ruby and it’s core API we can almost eliminate this as well as make the code easier to read and maintain.

Firstly, thanks to Array#==

1 [ self.attribute_1, self.attribute_2 ] == [ other.attribute_1, other.attribute_2 ]

is equivalent to

1 self.attribute_1 == other.attribute_1 && self.attribute_2 == other.attribute_2

If we combine that with the fact that we can return values from a lambda, the first code listing at the top can be rewritten as

1 def ==( other )
2   attribute_values_of = lambda{ |object| [ object.attribute_1,
3                                            object.attribute_2,
4                                            # Code snipped for brevity
5                                            object.attribute_20 ]}
6   attribute_values_of[ self ] == attribute_values_of[ other ]
7 end

By setting the attribute values that are returned in a lambda that is applied to both objects in the comparison you can ensure that all attributes are correctly compared. Adding new attributes to the comparison entails merely adding them into the returned array.

Announcing RCAP - Common Alerting Protocol for Ruby

Over the past month I’ve been scratching a bit of a coding itch and implemented the Common Alerting Protocol as a Ruby gem called RCAP.

The Common Alerting Protocol (CAP) is an XML-based data format for exchanging public warnings and emergencies between alerting technologies. CAP allows a warning message to be consistently disseminated simultaneously over many warning systems to many applications. CAP increases warning effectiveness and simplifies the task of activating a warning for responsible officials. – CAP@Wikipedia

About Aimred

Aimred is a specialist Ruby and Ruby on Rails development house and consultancy based in Cape Town, South Africa.

We provide Ruby and Ruby on Rails development, consulting and training services to businesses and organisations of all sizes. If you want to find out how we can help you, contact us at info@aimred.com.