diff --git a/lib/squib/deck.rb b/lib/squib/deck.rb index 541affa..881ab20 100644 --- a/lib/squib/deck.rb +++ b/lib/squib/deck.rb @@ -109,17 +109,24 @@ module Squib end end - # Process the extends + # Process the extends recursively # :nodoc: # @api private def recurse_extends(yml, key, visited ) assert_not_visited(key, visited) return yml[key] unless has_extends?(yml, key) visited[key] = key - parent_key = yml[key]['extends'] - return yml[key].merge(recurse_extends(yml, parent_key, visited)) do |key, child_val, parent_val| - child_val #child overrides parent when merging + parent_keys = [yml[key]['extends']].flatten + h = {} + parent_keys.each do |parent_key| + from_extends = yml[key].merge(recurse_extends(yml, parent_key, visited)) do |key, child_val, parent_val| + child_val #child overrides parent when merging + end + h = h.merge(from_extends) do |key, older_sibling, younger_sibling| + younger_sibling #when two siblings have the same entry, the "younger" (lower one) overrides + end end + return h end # Does this layout entry have an extends field? @@ -130,6 +137,9 @@ module Squib yml[key].key?('extends') end + # Safeguard against malformed circular extends + # :nodoc: + # @api private def assert_not_visited(key, visited) if visited.key? key raise "Invalid layout: circular extends with '#{key}'" diff --git a/spec/data/multi-extends-single-entry.yml b/spec/data/multi-extends-single-entry.yml index fe90c6f..805c98b 100644 --- a/spec/data/multi-extends-single-entry.yml +++ b/spec/data/multi-extends-single-entry.yml @@ -1,14 +1,14 @@ -base: +aunt: a: 101 b: 102 c: 103 -frame: +uncle: x: 104 y: 105 b: 106 -title: +child: extends: - - base - - frame + - uncle + - aunt a: 107 x: 108 diff --git a/spec/deck_spec.rb b/spec/deck_spec.rb index ab28f83..43d7719 100644 --- a/spec/deck_spec.rb +++ b/spec/deck_spec.rb @@ -117,28 +117,30 @@ describe Squib::Deck do ) end - # it "applies multiple extends in a single rule" do - # d = Squib::Deck.new(layout: test_file('multi-extends-single-entry.yml')) - # expect(d.layout).to \ - # eq({'base' => { - # 'x' => 38, - # 'y' => 38, - # }, - # 'frame' => { - # 'extends' => 'frame', - # 'x' => 38, - # 'y' => 50, - # 'width' => 100, - # }, - # 'title' => { - # 'extends' => 'frame', - # 'x' => 75, - # 'y' => 150, - # 'width' => 150, - # }, - # } - # ) - # end + it "applies multiple extends in a single rule" do + d = Squib::Deck.new(layout: test_file('multi-extends-single-entry.yml')) + expect(d.layout).to \ + eq({'aunt' => { + 'a' => 101, + 'b' => 102, + 'c' => 103, + }, + 'uncle' => { + 'x' => 104, + 'y' => 105, + 'b' => 106, + }, + 'child' => { + 'extends' => ['uncle','aunt'], + 'a' => 107, # my own + 'b' => 102, # from the younger aunt + 'c' => 103, # from aunt + 'x' => 108, # my own + 'y' => 105, # from uncle + }, + } + ) + end it "applies multi-level extends" do d = Squib::Deck.new(layout: test_file('multi-level-extends.yml'))