Inheritance and Merging

SparkleFormation includes functionality allowing SparklePacks to interact with previous layers when a file is requested from the collection. This functionality makes it easy to slightly modify files provided within previously registered SparklePacks without having to recreate the entire contents of the file. It also allows for creation of new templates based on existing templates.

Template Inheritance

Template inheritance allows a new template to inherit the data structures of an existing template. For example, lets start with a simple template:

SparkleFormation.new(:simple) do
  simple_template true
end

The dumped result of this template is:

{
  "SimpleTemplate": true
}

Suppose that we wanted create a new template that was composed of everything described in the simple template, but had an extra addition. Instead of re-creating the contents in a new file, or attempting to break out components or dynamics that may not be ideal, we can inherit the template instead:

SparkleFormation.new(:advanced, :inherit => :simple) do
  advanced.item 'added'
end

When this template is dumped, it will inherit the simple template and add on to the resultant data structure giving the result:

{
  "SimpleTemplate": true,
  "Advanced": {
    "Item": "added"
  }
}

Inheritance is not restricted to templates at a common level. A new template can inherit templates provided by SparklePacks.

Template Merging

Template merging is only applicable when SparklePacks are in use. Template merging allows direct modification of a specific named template. This strategy is extremely useful when packs may be layering functionality into a template, or the root pack wants to make a specific adjustment without creating a new template.

The default behavior of SparkleFormation when a SparklePack provides a template with the same name as a previously loaded SparklePack, it will overwrite the original template. In some cases, this may not be the desired effect. If a pack would like to make a simple adjustment to the template, this would require duplicating the contents of the original template and appending the customization. Merging allows adding customization without recreation.

Lets assume we have a core SparklePack loaded and it provides us with the simple template:

SparkleFormation.new(:simple) do
  simple_template true
end

Now in our root SparklePack we want to make an adjustment to the simple template directly. We can do this by merging:

SparkleFormation.new(:simple, :layering => :merge) do
  modifier 'spox'
end

When we dump the simple template now we get:

{
  "SimpleTemplate": true,
  "Modifier": "spox"
}

This sort of merging make two strategies possible:

  1. Modifying the final result of a template for a specific need
  2. Modifying at serveral layers to allow SparklePacks to be additive

Component and Dynamic Merging

Merging behavior for components and dynamics follows the same pattern as templates. Adding the :layering => :merge option will cause the item to be merged instead of overwritten.

For components:

SparkleFormation.component(:name, :layering => :merge)

and dynamics:

SparkleFormation.dynamic(:name, :layering => :merge)

Dynamic return value

The return value of a dynamic cannot be inferred. This is due to the freeform nature of dynamics leaving the resulting return value up to the author of the dynamic. When merging dynamics it can be easy to return the wrong value. The library could take care of this and always return the context provided by the initial dynamic, but this behavior is problematic: merges could remove the original context, or may want to change the return context completely. Returning the proper value is left to the author, but SparkleFormation makes it easy to return the previous context.

When the dynamics are merged, SparkleFormation will include an extra key in the options Hash for the dynamic: :previous_layer_result. Now a dynamic can merge in extra changes, and ensure the correct value is returned from the call:

SparkleFormation.dynamic(:name, :layering => :merge) do |name, args={}|
  new.things.added 'here'
  args[:previous_layer_result]
end

Registry Items

Registry items are exempt from the merging behavior described above. Registry items are always overwritten when redefined in higher level SparklePacks.