The purpose of this gem is to provide a simple way to manage the merge of different hashes (layers) according to priority and different merge policies.
Moved to Gitlab because of MS-phobia.
Add this line to your application's Gemfile:
gem 'super_stack'
And then execute:
$ bundle
Or install it yourself as:
$ gem install super_stack
The manager contains your different layers (hashes basically), allows you to set priorities among them, and provides a policy to merge them.
To use the manager, you just need to:
require 'super_stack'
manager = SuperStack::Manager.new
This is from the manager, that you will get the result of the merge of the different layers. Use manager[]
to access
the result of the merge of all layers as a hash. It will be done according to the priority the layers have and the merge
policy chosen.
You can directly access to a particular key of the resulting merging by simply doing manager[:your_key]
like you would
do with a regular Hash
.
SuperStack::Manager
itself has no Hash
in its ancestors, whereas SuperStack::Manager#[]
that you can access
through manager[]
is actually the Hash
resulting of the merge of the layers).
None of the layers is modified by the manager, although you can nevertheless access them with the
SuperStack::Manager#layers
method.
manager = SuperStack::Manager.new
puts manager.class # => SuperStack::Manager
puts manager[].class # => Hash
puts manager.layers.class # => Hash
1.0.0
were trying to give an indifferent access to the merged hash for strings
and symbols, ie manager[:an_entry]
was giving the same result as manager['an_entry']
.
This is clearly wrong and not consistent everywhere (only valid for the 'root' nodes).
Starting with version 1.0.0
this is no more the case. Nevertheless a compatibility mode is provided for
applications relying on the legacy mechanism, you just need to do:
require 'super_stack'
SuperStack.compatibility_mode = true
or alternatively, you can do:
require 'super_stack/old'
which is equivalent.
Layers are actually simple hashes that include the SuperStack::LayerWrapper
module. Therefore you can create a layer by
different means:
- by invoking
SuperStack::Layer.new
. You can use you all options you would use on a hash. - by calling
SuperStack::LayerWrapper.from_hash(your_hash)
. That will just add the moduleSuperStack::LayerWrapper
to your hash. - by adding manually adding the module to your hash (
your_hash.extend SuperStack::LayerWrapper
), which is strictly equivalent to the previous method.
When you create a new layer from scratch or by extending your own hash, it has automatically a name assigned, and no
particular priority. but as soon as it is added to a manager by doing either manager << your_hash_or_layer
or
manager.add_layer(your_hash_or_layer)
, it will see its name automatically changed (numbers automatically added) if
the name conflicts with another layer already handled by the manager.
You can notice by the way that it gives a third way to create a layer from a hash, as when adding a hash to a manager,
it automatically adds the SuperStack::LayerWrapper
module to the hash.
Layers can be populated from a yaml file anytime using the load
method:
layer = SuperStack::Layer.new.load 'a_file_somewhere'
# Once loaded you can get the file name used to load the layer anytime
puts layer.file_name
# And you can load or reload the layer
layer.has_file? # => true
layer.load
layer.reload
On top of this you can reload all the layers which have an associated file at once using the manager. If a layer has
no associated file_name
, it won't be altered.
layer1 = SuperStack::Layer.new.load 'a_file_somewhere'
layer1 = SuperStack::Layer.new.load 'another_file_somewhere'
manager = SuperStack::Manager.new
manager << layer1
manager << layer2
manager.reload_layers
Layers can of course be:
- Removed (using the manager's
remove_layer(layer_or_layer_name)
method). - Enabled or disabled (using the manager's
disable_layer(layer_or_layer_name)
andenable_layer(layer_or_layer_name)
methods).
Of course these methods have an impact on the write_layer
if applied to it. Check tests (run rspec -f d
) for
more info.
You can get the list of merge policies by doing SuperStack::MergePolicies.list
, but basically, four types currently
exist:
SuperStack::MergePolicies::KeepPolicy
, that when merging two layers will keep the first one (the one you are merging to).SuperStack::MergePolicies::OverridePolicy
, that when merging two layers will keep the second one(the one you are merging with).SuperStack::MergePolicies::StandardMergePolicy
, that will perform the ruby standardHash#merge
method. There are a lot of limitations with it (like not recursive, not merging arrays within hash etc... read ruby doc for more). This is the default merge methodSuperStack::MergePolicies::FullMergePolicy
is actually using the deep_merge gem to merge two hashes. It is fully merging two hashes including arrays etc... Only when two types are incompatible (like Array replacing a String), the second one replaces the first. Much more complete implementation than the one in ActiveSupport. The way it is used in the gem is compliant with both the plain Ruby and the Rails implementations (see the documentation)
The manager has a default_merge_policy
, but each layer can have its own merge_policy
. By default the internal merge
process will use the default_merge_policy
except if a layer specifies its own.
In most cases you will just have to set the merge policy at the manager level using default_merge_policy=
.
The alternative is to set the policy at the layer level using merge_policy=
- Fork it ( http://github.com/lbriais/super_stack/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request