Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The Top Down View

MapperMapping

Mapper supplies the most front-facing interface to the DSL: #define and #map. It keeps a registry of defined mappings, connecting them to a name symbol; #map runs the mapping over a set of records.

Mapping, as the name suggests, represents the actual defined mapping. It holds information about the class of the original record parser and the target record. It also gives us #process_record, which instantiates a new target record and uses the mapping to populate it. 

By including MappingDSL, Mapping provides access to the language implementation used to specify the mappings:

The DSL

The DSL provides an interface to make "Declarations" through #method_missing.  There are two main kinds of declarations:

  • Simple PropertyDeclarations; and
  • ChildDeclarations

All undefined method calls on a Mapping are treated as property declarations. The method name is the property name, the arguments are passed to the Declaration; and the resulting declarations are collected up in the properties hashmap.

A declaration is an object with a #to_proc method proc method that gives us a closure accepting a target and a record. The record is the source data (the parsed OriginalRecord) and the target is the ActiveModel/ActiveTriples-like object it gets to altermutate. The Declaration's job is to hold the information needed to set the right values to the right properties when the mapping is processed. It also promises to call #call, passing record, for any values it tries to set.

The rest of the language is provided through the ParserMethods mixin, which provides access to an OriginalRecord as a "parsed" tree. It gives us #record and #header methods, which return a RecordProxy. This object holds onto messages we want to send to the record when we process the mapping, and it exposes a #call method that replays that "call chain" back on the record, this will eventually be invoked by a declaration.

...

The value processing work happens here, at the ValueArray. This is the interface the parsed record exposes for manipulating it's value. The technique used is sometimes called "method chaining"; each method call returns an instance of the same class, allowing repeated calls to effectively change the state of the base object.

...

Declarations

What is going on in #to_proc? This is some of the scarier code in the DSL:

...

RecordProxy

#method_missing can be used to bad effect. We deploy some tricks to make sure RecordProxy breaks at definition time (rather than on each processed record):