Browse Source

Implementing multi-level extends, except for one case

dev
Andy Meneely 11 years ago
parent
commit
1371bd81bd
  1. 38
      lib/squib/deck.rb
  2. 14
      spec/data/multi-extends-single-entry.yml
  3. 2
      spec/data/multi-level-extends.yml
  4. 65
      spec/deck_spec.rb

38
lib/squib/deck.rb

@ -1,5 +1,6 @@
require 'yaml'
require 'pp'
require 'squib'
require 'squib/card'
require 'squib/progress'
require 'squib/input_helpers'
@ -101,14 +102,37 @@ module Squib
# @api private
def load_layout(file)
return if file.nil?
prelayout = YAML.load_file(file)
@layout = {}
prelayout.each do |key, value|
if value.key? "extends"
@layout[key] = prelayout[value["extends"]].merge prelayout[key]
else
@layout[key] = value
end
yml = YAML.load_file(file)
yml.each do |key, value|
@layout[key] = recurse_extends(yml, key, {})
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

14
spec/data/multi-extends-single-entry.yml

@ -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

2
spec/data/multi-level-extends.yml

@ -6,5 +6,5 @@ title:
y: 50
width: 100
subtitle:
extends: subtitle
extends: title
y: 150

65
spec/deck_spec.rb

@ -94,7 +94,7 @@ describe Squib::Deck do
)
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'))
expect(d.layout).to \
eq({'frame' => {
@ -117,8 +117,69 @@ 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 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

Loading…
Cancel
Save