From 262ab20f8915f6941d6db3a3d4df7f2d604057b6 Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Mon, 6 Jul 2020 17:10:32 +0100 Subject: [PATCH 1/7] Add $delete directive which allows deleting a config sub-tree --- lib/frise/defaults_loader.rb | 6 +++++- lib/frise/loader.rb | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/frise/defaults_loader.rb b/lib/frise/defaults_loader.rb index 42d7657..09ceb57 100644 --- a/lib/frise/defaults_loader.rb +++ b/lib/frise/defaults_loader.rb @@ -10,10 +10,11 @@ module Frise class DefaultsLoader SYMBOLS = %w[$all $optional].freeze - def initialize(include_sym: '$include', content_include_sym: '$content_include', schema_sym: '$schema') + def initialize(include_sym: '$include', content_include_sym: '$content_include', schema_sym: '$schema', delete_sym: '$delete') @include_sym = include_sym @content_include_sym = content_include_sym @schema_sym = schema_sym + @delete_sym = delete_sym end def widened_class(obj) @@ -37,6 +38,9 @@ def merge_defaults_obj(config, defaults) else merge_defaults_obj({}, defaults) end + elsif config == @delete_sym + config + elsif defaults_class == 'Array' && config_class == 'Array' defaults + config diff --git a/lib/frise/loader.rb b/lib/frise/loader.rb index 81cbfa9..724b347 100644 --- a/lib/frise/loader.rb +++ b/lib/frise/loader.rb @@ -13,6 +13,7 @@ class Loader def initialize(include_sym: '$include', content_include_sym: '$content_include', schema_sym: '$schema', + delete_sym: '$delete', pre_loaders: [], validators: nil, exit_on_fail: true) @@ -20,6 +21,7 @@ def initialize(include_sym: '$include', @include_sym = include_sym @content_include_sym = content_include_sym @schema_sym = schema_sym + @delete_sym = delete_sym @pre_loaders = pre_loaders @validators = validators @exit_on_fail = exit_on_fail @@ -27,7 +29,8 @@ def initialize(include_sym: '$include', @defaults_loader = DefaultsLoader.new( include_sym: include_sym, content_include_sym: content_include_sym, - schema_sym: schema_sym + schema_sym: schema_sym, + delete_sym: delete_sym ) end @@ -40,6 +43,7 @@ def load(config_file, global_vars = {}) end config = process_includes(config, [], config, global_vars) if @include_sym + config = omit_deleted(config) config = process_schemas(config, [], global_vars) if @schema_sym config end @@ -160,6 +164,17 @@ def merge_at(config, at_path, to_merge) config.merge(head => merge_at(config[head], tail, to_merge)) end + # returns the config without the keys whose values are @delete_sym + def omit_deleted(config) + config.each_with_object({}) do |(k, v), new_hash| + if v.is_a?(Hash) + new_hash[k] = omit_deleted(v) + else + new_hash[k] = v unless v == @delete_sym + end + end + end + # builds the symbol table for the Liquid renderization of a file, based on: # - `root_config`: the root of the whole config # - `at_path`: the current path @@ -170,7 +185,7 @@ def build_symbol_table(root_config, at_path, config, global_vars, include_conf) extra_vars = (include_conf['vars'] || {}).map { |k, v| [k, root_config.dig(*v.split('.'))] }.to_h extra_consts = include_conf['constants'] || {} - (config ? merge_at(root_config, at_path, config) : root_config) + omit_deleted(config ? merge_at(root_config, at_path, config) : root_config) .merge(global_vars) .merge(extra_vars) .merge(extra_consts) From 7281ef7d2b584d926ea232e9c0c4f811fe5989f6 Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Mon, 6 Jul 2020 17:10:40 +0100 Subject: [PATCH 2/7] Add tests --- spec/fixtures/_defaults/loader_test13.yml | 2 ++ spec/fixtures/_defaults/loader_test2.yml | 2 ++ spec/fixtures/_schemas/loader_test2.yml | 1 + spec/fixtures/loader_test13.yml | 5 +++++ spec/fixtures/loader_test13_include.yml | 6 ++++++ spec/fixtures/loader_test2_all_alt.yml | 1 + spec/frise/defaults_loader_spec.rb | 20 ++++++++++++++++++ spec/frise/loader_spec.rb | 25 ++++++++++++++++++----- 8 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 spec/fixtures/_defaults/loader_test13.yml create mode 100644 spec/fixtures/loader_test13.yml create mode 100644 spec/fixtures/loader_test13_include.yml diff --git a/spec/fixtures/_defaults/loader_test13.yml b/spec/fixtures/_defaults/loader_test13.yml new file mode 100644 index 0000000..4be8fc8 --- /dev/null +++ b/spec/fixtures/_defaults/loader_test13.yml @@ -0,0 +1,2 @@ +bar: "str3" +baz: "str4" diff --git a/spec/fixtures/_defaults/loader_test2.yml b/spec/fixtures/_defaults/loader_test2.yml index 031d146..ef6dc54 100644 --- a/spec/fixtures/_defaults/loader_test2.yml +++ b/spec/fixtures/_defaults/loader_test2.yml @@ -7,3 +7,5 @@ description: "Description of {{ name }} ({{ _extra.a }})" {% else %} description: "Description of {{ name }}" {% endif %} + +other: "plain" diff --git a/spec/fixtures/_schemas/loader_test2.yml b/spec/fixtures/_schemas/loader_test2.yml index c0d2a9c..644117f 100644 --- a/spec/fixtures/_schemas/loader_test2.yml +++ b/spec/fixtures/_schemas/loader_test2.yml @@ -1,3 +1,4 @@ id: String name: String description: String +other: String? diff --git a/spec/fixtures/loader_test13.yml b/spec/fixtures/loader_test13.yml new file mode 100644 index 0000000..0fccb59 --- /dev/null +++ b/spec/fixtures/loader_test13.yml @@ -0,0 +1,5 @@ +$include: + - "{{ _file_dir }}/loader_test13_include.yml" + +foo: $delete +bar: "str" diff --git a/spec/fixtures/loader_test13_include.yml b/spec/fixtures/loader_test13_include.yml new file mode 100644 index 0000000..0136bee --- /dev/null +++ b/spec/fixtures/loader_test13_include.yml @@ -0,0 +1,6 @@ +$include: + - "{{ _file_dir }}/defaults/loader_test13.yml" + +foo: "str2" +bar: $delete +baz: $delete diff --git a/spec/fixtures/loader_test2_all_alt.yml b/spec/fixtures/loader_test2_all_alt.yml index 1aba2b0..9d1d600 100644 --- a/spec/fixtures/loader_test2_all_alt.yml +++ b/spec/fixtures/loader_test2_all_alt.yml @@ -2,3 +2,4 @@ __custom_sch: ["{{ _file_dir }}/_schemas/loader_test2.yml"] __custom_inc: ["{{ _file_dir }}/_defaults/loader_test2.yml"] name: "My Object" +other: __custom_del diff --git a/spec/frise/defaults_loader_spec.rb b/spec/frise/defaults_loader_spec.rb index 6c4add9..1c5f73b 100644 --- a/spec/frise/defaults_loader_spec.rb +++ b/spec/frise/defaults_loader_spec.rb @@ -112,4 +112,24 @@ .to raise_error 'Cannot merge config {"$content_include"=>["str.txt"]} (String) ' \ 'with default {"str"=>"abc", "int"=>4, "bool"=>true} (Hash)' end + + it 'should override defaults when value is $delete' do + conf = { + 'str' => '$delete', + 'int' => '$delete', + 'bool' => '$delete', + 'arr' => '$delete', + 'obj' => { 'key1' => '$delete', 'key3' => '$delete' } + } + conf = DefaultsLoader.new.merge_defaults(conf, fixture_path('all_types.yml')) + expect(conf['str']).to eq '$delete' + expect(conf['int']).to eq '$delete' + expect(conf['bool']).to eq '$delete' + expect(conf['arr']).to eq '$delete' + expect(conf['obj']).to eq( + 'key1' => '$delete', + 'key2' => 'value2', + 'key3' => '$delete' + ) + end end diff --git a/spec/frise/loader_spec.rb b/spec/frise/loader_spec.rb index ecb5659..0ff54b4 100644 --- a/spec/frise/loader_spec.rb +++ b/spec/frise/loader_spec.rb @@ -72,12 +72,16 @@ def validators.short_string(_, str) expect(conf).to eq( 'id' => 'myobj', 'name' => 'My Object', - 'description' => 'Description of My Object (42)' + 'description' => 'Description of My Object (42)', + 'other' => 'plain' ) end - it 'should allow using a different key or no key for inclusions and schemas' do - loader = Loader.new(include_sym: '__custom_inc', schema_sym: '__custom_sch', exit_on_fail: false) + it 'should allow using a different key or no key for inclusions/schemas/deletes' do + loader = Loader.new(include_sym: '__custom_inc', + schema_sym: '__custom_sch', + delete_sym: '__custom_del', + exit_on_fail: false) conf = loader.load(fixture_path('loader_test2_all_alt.yml'), '_id' => 'myobj') expect(conf).to eq( @@ -158,7 +162,8 @@ def validators.short_string(_, str) expect(conf).to eq( 'id' => 'myobj', 'name' => 'My Object', - 'description' => 'Description of My Object' + 'description' => 'Description of My Object', + 'other' => 'plain' ) conf = loader.load(fixture_path('loader_test2_templated.yml'), '_with_schema' => true) @@ -171,7 +176,8 @@ def validators.short_string(_, str) expect(conf).to eq( 'id' => 'myobj', 'name' => 'My Object', - 'description' => 'Description of My Object' + 'description' => 'Description of My Object', + 'other' => 'plain' ) end @@ -257,4 +263,13 @@ def validators.short_string(_, str) " - At variable1.value2: missing required value\n" ).to_stdout.and raise_error(SystemExit) end + + it 'should delete sub-tree when value is $delete' do + loader = Loader.new(exit_on_fail: false) + + conf = loader.load(fixture_path('loader_test13.yml')) + expect(conf).to eq( + 'bar' => 'str' + ) + end end From 8538a88aa4df0438f0a55b506370db43f6e6e553 Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Mon, 6 Jul 2020 17:30:12 +0100 Subject: [PATCH 3/7] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f76e582..cef8e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 0.4.1 (tbd) + +- New features + - `$delete` directive is now available in config files, allowing users to delete parts of the + config sub-tree ([#20](https://github.com/velocidi/frise/pull/20)). + ### 0.4.0 (November 29, 2019) - Breaking changes From 0df7867f7270fc174e3c5884aaa29575ec96a23a Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Tue, 7 Jul 2020 12:34:56 +0100 Subject: [PATCH 4/7] Move omit_deleted call inside of process_includes --- lib/frise/loader.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/frise/loader.rb b/lib/frise/loader.rb index 724b347..03086d9 100644 --- a/lib/frise/loader.rb +++ b/lib/frise/loader.rb @@ -43,7 +43,6 @@ def load(config_file, global_vars = {}) end config = process_includes(config, [], config, global_vars) if @include_sym - config = omit_deleted(config) config = process_schemas(config, [], global_vars) if @schema_sym config end @@ -69,18 +68,19 @@ def process_includes(config, at_path, root_config, global_vars, include_confs_st # process $include directives config, next_include_confs = extract_include(config, at_path) include_confs = next_include_confs + include_confs_stack - if include_confs.empty? - config.map { |k, v| [k, process_includes(v, at_path + [k], root_config, global_vars)] }.to_h - else - Lazy.new do - include_conf = include_confs.first - rest_include_confs = include_confs[1..-1] - symbol_table = build_symbol_table(root_config, at_path, config, global_vars, include_conf) - included_config = Parser.parse(include_conf['file'], symbol_table) - config = @defaults_loader.merge_defaults_obj(config, included_config) - process_includes(config, at_path, merge_at(root_config, at_path, config), global_vars, rest_include_confs) - end - end + res = if include_confs.empty? + config.map { |k, v| [k, process_includes(v, at_path + [k], root_config, global_vars)] }.to_h + else + Lazy.new do + include_conf = include_confs.first + rest_include_confs = include_confs[1..-1] + symbol_table = build_symbol_table(root_config, at_path, config, global_vars, include_conf) + included_config = Parser.parse(include_conf['file'], symbol_table) + config = @defaults_loader.merge_defaults_obj(config, included_config) + process_includes(config, at_path, merge_at(root_config, at_path, config), global_vars, rest_include_confs) + end + end + omit_deleted(res) end def process_schema_includes(schema, at_path, global_vars) From 980bca5e40482ec41303211486a120a7ab6ab72a Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Tue, 7 Jul 2020 12:35:51 +0100 Subject: [PATCH 5/7] Don't parse delete_sym if nil and use .nil? comparisons --- lib/frise/loader.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/frise/loader.rb b/lib/frise/loader.rb index 03086d9..247a882 100644 --- a/lib/frise/loader.rb +++ b/lib/frise/loader.rb @@ -42,8 +42,8 @@ def load(config_file, global_vars = {}) config = pre_loader.call(config) end - config = process_includes(config, [], config, global_vars) if @include_sym - config = process_schemas(config, [], global_vars) if @schema_sym + config = process_includes(config, [], config, global_vars) unless @include_sym.nil? + config = process_schemas(config, [], global_vars) unless @schema_sym.nil? config end @@ -80,7 +80,7 @@ def process_includes(config, at_path, root_config, global_vars, include_confs_st process_includes(config, at_path, merge_at(root_config, at_path, config), global_vars, rest_include_confs) end end - omit_deleted(res) + @delete_sym.nil? ? res : omit_deleted(res) end def process_schema_includes(schema, at_path, global_vars) From fcd7e0f67c35b465ddd0ee781de940a2b2061ba6 Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Tue, 7 Jul 2020 12:36:28 +0100 Subject: [PATCH 6/7] Test to ensure that liquid does not see $delete values --- spec/fixtures/loader_test13_include.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/fixtures/loader_test13_include.yml b/spec/fixtures/loader_test13_include.yml index 0136bee..912d5e4 100644 --- a/spec/fixtures/loader_test13_include.yml +++ b/spec/fixtures/loader_test13_include.yml @@ -4,3 +4,4 @@ $include: foo: "str2" bar: $delete baz: $delete +liquid: {% if foo %}true{% endif %} From b04a3ee9722c4b3a496da69db1f37f8e5d05b8c3 Mon Sep 17 00:00:00 2001 From: Bruno Maia Date: Tue, 7 Jul 2020 12:37:57 +0100 Subject: [PATCH 7/7] Test that top level deletes values when intermediate includes are nil --- spec/fixtures/_defaults/loader_test13.yml | 1 + spec/fixtures/loader_test13.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/fixtures/_defaults/loader_test13.yml b/spec/fixtures/_defaults/loader_test13.yml index 4be8fc8..e7770c9 100644 --- a/spec/fixtures/_defaults/loader_test13.yml +++ b/spec/fixtures/_defaults/loader_test13.yml @@ -1,2 +1,3 @@ bar: "str3" baz: "str4" +other: "str5" diff --git a/spec/fixtures/loader_test13.yml b/spec/fixtures/loader_test13.yml index 0fccb59..8d1d367 100644 --- a/spec/fixtures/loader_test13.yml +++ b/spec/fixtures/loader_test13.yml @@ -3,3 +3,4 @@ $include: foo: $delete bar: "str" +other: $delete