The Top Down View
Mapper & Mapping
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:
...
- look Look at how
@bindings
is handled throughout - See also, the recent DSL backtrack PR: https://github.com/dpla/KriKri/pull/244/files
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):
- https://github.com/dpla/KriKri/blob/3ce75bb56b558b30c10508564d3ddf93f94b1a83/lib/krikri/mapping_dsl/parser_methods.rb#L117-L138
- Are there other places we could surface errors closer to when we write a mapping?