From 75ab0b565f8ec9d33cfc94296e4e838cec925fce Mon Sep 17 00:00:00 2001 From: Andy Meneely Date: Mon, 17 Nov 2014 21:08:57 -0500 Subject: [PATCH] Added support for merging multiple layout files --- CHANGELOG.md | 3 ++- README.md | 43 +++++++++++++++++++++++++++++-- lib/squib/deck.rb | 12 +++++---- samples/custom-layout.yml | 1 + samples/custom-layout2.yml | 15 +++++++++++ samples/layouts.rb | 7 +++++ spec/data/multifile-a.yml | 4 +++ spec/data/multifile-b.yml | 4 +++ spec/data/multifile-extends-a.yml | 8 ++++++ spec/data/multifile-extends-b.yml | 9 +++++++ spec/deck_spec.rb | 24 +++++++++++++++++ 11 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 samples/custom-layout2.yml create mode 100644 spec/data/multifile-a.yml create mode 100644 spec/data/multifile-b.yml create mode 100644 spec/data/multifile-extends-a.yml create mode 100644 spec/data/multifile-extends-b.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index efbbac1..38dfc4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Squib CHANGELOG -## Samples show you can use text instead of symbols +# Custom layouts now support loading & merging multiple files, see README and updated sample +# Samples now show that you can use text instead of symbols ## v0.0.5 * Image rotation for png and svg via `angle` diff --git a/README.md b/README.md index db25fc2..b33c1c1 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,12 @@ Layouts will override Squib's defaults, but are overriden by anything specified * If anything was not yet specified, use what was given in a layout (if a layout was specified in the command and the file was given to the Deck) * If still anything was not yet specified, use what was given in Squib's defaults. +Layouts also allow merging, extending, and combining layouts. The sample demonstrates this, but they are also explained below. See the `layouts.rb` sample found [here](https://github.com/andymeneely/squib/tree/master/samples/) + +{include:file:samples/layouts.rb} + +### Merge Keys and `extends` + Since Layouts are in Yaml, we have the full power of that data format. One particular feature you should look into are ["merge keys"](http://www.yaml.org/YAML_for_ruby.html#merge_key). With merge keys, you can define base styles in one entry, then include those keys elsewhere. For example: ```yaml @@ -193,9 +199,42 @@ yang: x: += 50 ``` -See the `use_layout` sample found [here](https://github.com/andymeneely/squib/tree/master/samples/) +### Multiple layout files + +Squib also supports the combination of multiple layout files. As shown in the above example, if you provide an `Array` of files then Squib will merge them sequentially. Colliding keys will be completely re-defined by the later file. Extends is processed after _each_ file. YAML merge keys are NOT supported across multiple files (use extends instead). Here's a demonstrative example: + +```yaml +# load order: a.yml, b.yml + +############## +# file a.yml # +############## +grandparent: + x: 100 +parent_a: + extends: grandparent + x: += 10 # evaluates to 110 +parent_b: + extends: grandparent + x: += 20 # evaluates to 120 + +############## +# file b.yml # +############## +child_a: + extends: parent_a + x: += 3 # evaluates to 113 +parent_b: # redefined + extends: grandparent + x: += 30 # evaluates to 130 +child_b: + extends: parent_b + x: += 3 # evaluates to 133 +``` -{include:file:samples/use_layout.rb} +This can hopefully be helpful for: + * Creating a base layout for structure, and one for color (for easier color/black-and-white switching) + * Sharing base layouts with other designers ## Configuration File diff --git a/lib/squib/deck.rb b/lib/squib/deck.rb index d766453..f85468d 100644 --- a/lib/squib/deck.rb +++ b/lib/squib/deck.rb @@ -50,6 +50,7 @@ module Squib # @param cards [Integer] the number of cards in the deck # @param dpi [Integer] the pixels per inch when rendering out to PDF or calculating using inches. # @param config [String] the file used for global settings of this deck + # @param layout [String, Array] load a YML file of custom layouts. Multiple files are merged sequentially, redefining collisons. See README and sample for details. # @param block [Block] the main body of the script. # @api public def initialize(width: 825, height: 1125, cards: 1, dpi: 300, config: 'config.yml', layout: nil, &block) @@ -105,12 +106,13 @@ module Squib # Load the layout configuration file, if exists # @api private - def load_layout(file) - return if file.nil? + def load_layout(files) @layout = {} - yml = YAML.load_file(file) - yml.each do |key, value| - @layout[key] = recurse_extends(yml, key, {}) + Array(files).each do |file| + yml = @layout.merge(YAML.load_file(file)) + yml.each do |key, value| + @layout[key] = recurse_extends(yml, key, {}) + end end end diff --git a/samples/custom-layout.yml b/samples/custom-layout.yml index 0742a4c..fc1140e 100644 --- a/samples/custom-layout.yml +++ b/samples/custom-layout.yml @@ -1,3 +1,4 @@ +# Used in the layouts.rb sample in conjunction with custom-layout2.yml frame: x: 38 y: 38 diff --git a/samples/custom-layout2.yml b/samples/custom-layout2.yml new file mode 100644 index 0000000..9c94832 --- /dev/null +++ b/samples/custom-layout2.yml @@ -0,0 +1,15 @@ +# Used in the layouts.rb sample in conjunction with custom-layout.yml +# +# When used with custom-layout.yml loaded first, this layout overrides subtitle +subtitle: + x: 150 + y: 150 + width: 575 + height: 60 + align: left + valign: middle + font_size: 25 +# This one is completely new +description: + extends: subtitle + y: += 350 diff --git a/samples/layouts.rb b/samples/layouts.rb index 990d77c..98f0c21 100644 --- a/samples/layouts.rb +++ b/samples/layouts.rb @@ -32,3 +32,10 @@ Squib::Deck.new(layout: 'custom-layout.yml') do save_png prefix: 'layout_' end + +Squib::Deck.new(layout:['custom-layout.yml', 'custom-layout2.yml']) do + text str: 'The Title', layout: :title # from custom-layout.yml + text str: 'The Subtitle', layout: :subtitle # redefined in custom-layout2.yml + text str: 'The Description', layout: :description # from custom-layout2.yml + save_png prefix: 'layout2_' +end diff --git a/spec/data/multifile-a.yml b/spec/data/multifile-a.yml new file mode 100644 index 0000000..cbef6f1 --- /dev/null +++ b/spec/data/multifile-a.yml @@ -0,0 +1,4 @@ +title: + x: 100 +subtitle: + x: 200 \ No newline at end of file diff --git a/spec/data/multifile-b.yml b/spec/data/multifile-b.yml new file mode 100644 index 0000000..5b24bf0 --- /dev/null +++ b/spec/data/multifile-b.yml @@ -0,0 +1,4 @@ +title: # redefined + x: 300 +desc: + x: 400 \ No newline at end of file diff --git a/spec/data/multifile-extends-a.yml b/spec/data/multifile-extends-a.yml new file mode 100644 index 0000000..55202aa --- /dev/null +++ b/spec/data/multifile-extends-a.yml @@ -0,0 +1,8 @@ +grandparent: + x: 100 +parent_a: + extends: grandparent + x: += 10 # evaluates to 110 +parent_b: + extends: grandparent + x: += 20 # evaluates to 120, for now... diff --git a/spec/data/multifile-extends-b.yml b/spec/data/multifile-extends-b.yml new file mode 100644 index 0000000..00db94c --- /dev/null +++ b/spec/data/multifile-extends-b.yml @@ -0,0 +1,9 @@ +child_a: + extends: parent_a + x: += 3 # evaluates to 113 +parent_b: # redefined + extends: grandparent + x: += 30 # evaluates to 130 +child_b: + extends: parent_b + x: += 3 # evaluates to 133 \ No newline at end of file diff --git a/spec/deck_spec.rb b/spec/deck_spec.rb index 958a65c..4fc2533 100644 --- a/spec/deck_spec.rb +++ b/spec/deck_spec.rb @@ -183,6 +183,30 @@ describe Squib::Deck do raise_error(RuntimeError, 'Invalid layout: circular extends with \'a\'') end + it 'redefines keys on multiple layouts' do + a = test_file('multifile-a.yml') + b = test_file('multifile-b.yml') + d = Squib::Deck.new(layout: [a, b]) + expect(d.layout).to eq({ + 'title' => { 'x' => 300 }, + 'subtitle' => { 'x' => 200 }, + 'desc' => { 'x' => 400 } + }) + end + + it 'evaluates extends on each file first' do + a = test_file('multifile-extends-a.yml') + b = test_file('multifile-extends-b.yml') + d = Squib::Deck.new(layout: [a, b]) + expect(d.layout).to eq({ + 'grandparent' => { 'x' => 100 }, + 'parent_a' => { 'x' => 110, 'extends' => 'grandparent' }, + 'parent_b' => { 'x' => 130, 'extends' => 'grandparent' }, + 'child_a' => { 'x' => 113, 'extends' => 'parent_a' }, + 'child_b' => { 'x' => 133, 'extends' => 'parent_b' } + }) + end + end end