Peachy

Peachy dynamically slurps XML from an underlying XML DOM, creating Ruby methods on the fly to match the elements and attributes of the XML.

Source available at github.com/njpearman/Peachy

Install

The Peachy gem is available as you would expect. Run:

gem install peachy

then

require 'peachy'

in irb / your codebase to get going.

Usage

The Peachy::Proxy is the key class in Peachy. Create a new instance of a Peachy::Proxy by passing in a raw XML string

proxy = Peachy::Proxy.new('<xml><node>Peachy</node></xml>')

Once you have a Proxy, it’s straightforward to drill down through the XML by node name:

puts 'Contents: ' + proxy.xml.node.value
=> Contents: Peachy

Call #value on a childless node to get the contents of the node, such as the example above.

Peachy expects method names to be called in the Ruby convention of lowercase with underscores. It will do its best to match method names to elements and attributes following different conventions. Currently, this is camelCaseNames, PascalCaseNames, hyphen-separated-names and period.separated.names.

More detailed usage examples can be found in the .rb files in the /test directory.

Getting the underlying XML

It’s possible to call #to_s on any node in the tree to get the underlying XML at that point in the tree, such as:

puts 'XML: ' + proxy.xml.node.to_s
=> XML: <node>Peachy</node>

The exact representation of the XML will depend on the underlying XML parser that is being used, but the XML will be valid and correct.

XML parsing

Peachy tries to determine which XML parser to load when it is first used. Nokogiri is currently the first choice, defaulting to REXML if Nokogiri is not available. Peachy requires the appropriate XML parser gem at runtime and, as such, I haven’t included Nokogiri as a dependency in the gemspec. It will use Nokogiri when it’s available; otherwise REXML will be loaded and used at runtime.

It is possible to extend out the parser support, for example Hpricot or LibXML, so let me know if there are any other XML parsers that you’d like Peachy to support.

A quick note about Nokogiri and XML namespaces: when Nokogiri creates a new XML node, it currently strips all namespaces from the document. This simplification of the underlying XML is necessary so that the interface that Peachy presents to the user is still straightforward even when namespaces are set within the XML.

Elements and Attributes

Currently, elements and attributes are accessed in almost exactly the same way; call a method on your current node matching the attribute or element name that is required next. Elements need to have #value called on them to get the contents of the element, however.

E.g.

proxy = Peachy::Proxy.new('<peachy version="1.0.0"><node>Peachy is here.</node></peachy>')
puts "Element contents: " + proxy.peachy.node.value
=> Element contents: Peachy is here
puts "Element attribute: " + proxy.peachy.version
=> Element attribute: 1.0.0

Peachy is just for slurping XML, so this convention should make it easy to know how to access the property that you’re after, be they elements or attributes.

Collections

Peachy allows collections to be traversed as arrays in the following way:

proxy = Peachy::Proxy.new('<peachy><node>One</node><node>Two</node><node>Three</node></peachy>')
puts "First node: " + proxy.peachy.node[0].value
=> First node: One
puts "Second node: " + proxy.peachy.node[1].value
=> Second node: Two

Note that a child of a Peachy Proxy can be either an array, or another proxy, and never both. The intent is that a consumer of some XML would expect something to be a single child all of the time, or a collection all of the time. It doesn’t make sense to treat a particular node as a singleton in some circumstances and a collection containing one element in others.

No method name match

By default, Peachy will raise a NoMatchingXmlPart error if a method call does not match a child node of the current location. It’s possible to globally switch of this behaviour and return nil when no child node is found. This might be desirable if you cannot be certain of the XML that you are trying to interpret until runtime.

Toggle between silent and noisy messages in Peachy using:

Peachy.be_quiet
Peachy.be_loud