Implementing multi-level extends, except for one case
parent
8bd814fc1a
commit
1371bd81bd
|
|
@ -1,5 +1,6 @@
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'pp'
|
require 'pp'
|
||||||
|
require 'squib'
|
||||||
require 'squib/card'
|
require 'squib/card'
|
||||||
require 'squib/progress'
|
require 'squib/progress'
|
||||||
require 'squib/input_helpers'
|
require 'squib/input_helpers'
|
||||||
|
|
@ -101,14 +102,37 @@ module Squib
|
||||||
# @api private
|
# @api private
|
||||||
def load_layout(file)
|
def load_layout(file)
|
||||||
return if file.nil?
|
return if file.nil?
|
||||||
prelayout = YAML.load_file(file)
|
|
||||||
@layout = {}
|
@layout = {}
|
||||||
prelayout.each do |key, value|
|
yml = YAML.load_file(file)
|
||||||
if value.key? "extends"
|
yml.each do |key, value|
|
||||||
@layout[key] = prelayout[value["extends"]].merge prelayout[key]
|
@layout[key] = recurse_extends(yml, key, {})
|
||||||
else
|
end
|
||||||
@layout[key] = value
|
end
|
||||||
end
|
|
||||||
|
# Process the extends
|
||||||
|
# :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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Does this layout entry have an extends field?
|
||||||
|
# i.e. is it a base-case or will it need recursion?
|
||||||
|
# :nodoc:
|
||||||
|
# @api private
|
||||||
|
def has_extends?(yml, key)
|
||||||
|
yml[key].key?('extends')
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_not_visited(key, visited)
|
||||||
|
if visited.key? key
|
||||||
|
raise "Invalid layout: circular extends with '#{key}'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
base:
|
||||||
|
a: 101
|
||||||
|
b: 102
|
||||||
|
c: 103
|
||||||
|
frame:
|
||||||
|
x: 104
|
||||||
|
y: 105
|
||||||
|
b: 106
|
||||||
|
title:
|
||||||
|
extends:
|
||||||
|
- base
|
||||||
|
- frame
|
||||||
|
a: 107
|
||||||
|
x: 108
|
||||||
|
|
@ -6,5 +6,5 @@ title:
|
||||||
y: 50
|
y: 50
|
||||||
width: 100
|
width: 100
|
||||||
subtitle:
|
subtitle:
|
||||||
extends: subtitle
|
extends: title
|
||||||
y: 150
|
y: 150
|
||||||
|
|
@ -94,7 +94,7 @@ describe Squib::Deck do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "applies the single-level extends multiple timess" do
|
it "applies the single-level extends multiple times" do
|
||||||
d = Squib::Deck.new(layout: test_file('single-level-multi-extends.yml'))
|
d = Squib::Deck.new(layout: test_file('single-level-multi-extends.yml'))
|
||||||
expect(d.layout).to \
|
expect(d.layout).to \
|
||||||
eq({'frame' => {
|
eq({'frame' => {
|
||||||
|
|
@ -117,8 +117,69 @@ describe Squib::Deck do
|
||||||
)
|
)
|
||||||
end
|
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 multi-level extends" do
|
||||||
|
d = Squib::Deck.new(layout: test_file('multi-level-extends.yml'))
|
||||||
|
expect(d.layout).to \
|
||||||
|
eq({'frame' => {
|
||||||
|
'x' => 38,
|
||||||
|
'y' => 38,
|
||||||
|
},
|
||||||
|
'title' => {
|
||||||
|
'extends' => 'frame',
|
||||||
|
'x' => 38,
|
||||||
|
'y' => 50,
|
||||||
|
'width' => 100,
|
||||||
|
},
|
||||||
|
'subtitle' => {
|
||||||
|
'extends' => 'title',
|
||||||
|
'x' => 38,
|
||||||
|
'y' => 150,
|
||||||
|
'width' => 100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails on a self-circular extends" do
|
||||||
|
file = test_file('self-circular-extends.yml')
|
||||||
|
expect { Squib::Deck.new(layout: file) }.to \
|
||||||
|
raise_error(RuntimeError, "Invalid layout: circular extends with 'a'")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails on a easy-circular extends" do
|
||||||
|
file = test_file('easy-circular-extends.yml')
|
||||||
|
expect { Squib::Deck.new(layout: file) }.to \
|
||||||
|
raise_error(RuntimeError, "Invalid layout: circular extends with 'a'")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "hard on a easy-circular extends" do
|
||||||
|
file = test_file('hard-circular-extends.yml')
|
||||||
|
expect { Squib::Deck.new(layout: file) }.to \
|
||||||
|
raise_error(RuntimeError, "Invalid layout: circular extends with 'a'")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue