declarative 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85ae72ce17160c8d0d6bbe197358967601d4565d
4
- data.tar.gz: 28b480fc3526c9197fbe02899929c8a0cec4baa4
3
+ metadata.gz: 6e5c86877c99e99dfa9ce880df46435218fcc7a0
4
+ data.tar.gz: e4b808d37b26399bade9158a92040fb882a3c840
5
5
  SHA512:
6
- metadata.gz: 6c2b2d5d60573417e5304f220cf3d1658bda2b5b52601b5ed554fb6447c1f62c5d4fad254c2b28dc68bf231aea8e0215bea5b565ade7189dfb6935efbf6fa534
7
- data.tar.gz: 28abb6da89a87cbb256cce92327945641224cc077ef1f182451ce9695c02ed16aaeace1b5e56714ce948d9fafd4776de1312715893b07676ec0e8f1ca7ba6b44
6
+ metadata.gz: 92ec08dc8dcbe1939a657112edc880b977f16e5b786722a0af007f895399d28d9370415f3db81c2c71e5f270f5be6eeaa10d6b0bcf654f64683113ebe76d639a
7
+ data.tar.gz: e56d957d4b9b29695b861a7e3852cd66aac31f8f3fe0a01dfa343e054a38f6b4c98aa39dcce5f6e61157ac9a055a6d7cee1730ba8f804d003283db611ef280c1
data/CHANGES.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 0.0.10
2
+
3
+ * `Defaults.merge!` will now deprecate non-wrapped `Array` values. The following code is no longer valid (but still works).
4
+
5
+ defaults.merge!( list: [1,2] )
6
+
7
+ Instead, you need to wrap it in a command like `Variables::Append`.
8
+
9
+ defaults.merge!( list: Declarative::Variables::Append( [1,2] ) )
10
+
11
+ The reason for this change is to allow all kinds of operations with defaults variables, such as merges, overrides, append, prepend, and so on.
12
+
13
+ * Introduce `Declarative::Variables.merge` to merge two sets of variables.
14
+ * `Defaults` now uses `Variables` for merge/overide operations.
15
+
1
16
  # 0.0.9
2
17
 
3
18
  * Removing `uber` dependency.
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["apotonick@gmail.com"]
10
10
  spec.summary = %q{DSL for nested schemas.}
11
11
  spec.description = %q{DSL for nested generic schemas with inheritance and refining.}
12
- spec.homepage = ""
12
+ spec.homepage = "https://github.com/apotonick/declarative"
13
13
  spec.license = "MIT"
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
@@ -4,6 +4,7 @@ require "declarative/heritage"
4
4
  require "declarative/defaults"
5
5
  require "declarative/schema"
6
6
  require "declarative/deep_dup"
7
+ require "declarative/variables"
7
8
 
8
9
  module Declarative
9
10
  end
@@ -2,7 +2,7 @@ module Declarative
2
2
  class DeepDup
3
3
  def self.call(args)
4
4
  return Array[*dup_items(args)] if args.is_a?(Array)
5
- return Hash[dup_items(args)] if args.is_a?(Hash)
5
+ return ::Hash[dup_items(args)] if args.is_a?(::Hash)
6
6
  args
7
7
  end
8
8
 
@@ -11,4 +11,4 @@ module Declarative
11
11
  arr.to_a.collect { |v| call(v) }
12
12
  end
13
13
  end
14
- end
14
+ end
@@ -1,16 +1,18 @@
1
1
  module Declarative
2
+ # {Defaults} is a mutable DSL object that collects default directives via #merge!.
3
+ # Internally, it uses {Variables} to implement the merging of defaults.
2
4
  class Defaults
3
5
  def initialize
4
6
  @static_options = {}
5
- @dynamic_options = ->(*) { Hash.new }
7
+ @dynamic_options = ->(*) { {} }
6
8
  end
7
9
 
8
10
  # Set default values. Usually called in Schema::defaults.
9
11
  # This can be called multiple times and will "deep-merge" arrays, e.g. `_features: []`.
10
12
  def merge!(hash={}, &block)
11
- @static_options = Merge.(@static_options, hash)
12
-
13
+ @static_options = Variables.merge( @static_options, handle_array_and_deprecate(hash) )
13
14
  @dynamic_options = block if block_given?
15
+
14
16
  self
15
17
  end
16
18
 
@@ -19,24 +21,25 @@ module Declarative
19
21
  # TODO: allow to receive rest of options/block in dynamic block. or, rather, test it as it was already implemented.
20
22
  evaluated_options = @dynamic_options.(name, given_options)
21
23
 
22
- options = Merge.(@static_options, evaluated_options)
23
- options = options.merge(given_options)
24
+ options = Variables.merge( @static_options, handle_array_and_deprecate(evaluated_options) )
25
+ options = Variables.merge( options, handle_array_and_deprecate(given_options) ) # FIXME: given_options is not tested!
26
+ end
27
+
28
+ def handle_array_and_deprecate(variables)
29
+ wrapped = Defaults.wrap_arrays(variables)
30
+
31
+ warn "[Declarative] Defaults#merge! and #call still accept arrays and automatically prepend those. This is now deprecated, you should replace `ary` with `Declarative::Variables::Append(ary)`." if wrapped.any?
32
+
33
+ variables.merge(wrapped)
24
34
  end
25
35
 
26
- # Private! Don't use this anywhere.
27
- # Merges two hashes and joins same-named arrays. This is often needed
28
- # when dealing with defaults.
29
- class Merge
30
- def self.call(a, b)
31
- a = a.dup
32
- b.each do |k, v|
33
- a[k] = v and next unless a.has_key?(k)
34
- a[k] = v and next unless a[k].is_a?(Array)
35
- a[k] = a[k] += v # only for arrays.
36
- end
37
-
38
- a
39
- end
36
+ # Wrap arrays in `variables` with Variables::Append so they get appended to existing
37
+ # same-named arrays.
38
+ def self.wrap_arrays(variables)
39
+ Hash[ variables.
40
+ find_all { |k,v| v.instance_of?(Array) }.
41
+ collect { |k,v| [k, Variables::Append(v)] }
42
+ ]
40
43
  end
41
44
  end
42
45
  end
@@ -1,5 +1,5 @@
1
1
  module Declarative
2
- class Definitions < Hash
2
+ class Definitions < ::Hash
3
3
  class Definition
4
4
  def initialize(name, options={}, &block)
5
5
  @options = options.dup
@@ -71,4 +71,4 @@ module Declarative
71
71
  options[:_nested_builder].(options)
72
72
  end
73
73
  end
74
- end
74
+ end
@@ -1,5 +1,6 @@
1
1
  require "declarative/definitions"
2
2
  require "declarative/defaults"
3
+ require "declarative/variables"
3
4
  require "declarative/heritage"
4
5
 
5
6
  module Declarative
@@ -27,6 +28,10 @@ module Declarative
27
28
  def defaults(options={}, &block)
28
29
  heritage.record(:defaults, options, &block)
29
30
 
31
+ # Always convert arrays to Variables::Append instructions.
32
+ options = options.merge( Defaults.wrap_arrays(options) )
33
+ block = wrap_arrays_from_block(block) if block_given?
34
+
30
35
  _defaults.merge!(options, &block)
31
36
  end
32
37
 
@@ -45,6 +50,8 @@ module Declarative
45
50
  default_options[:_defaults] = _defaults
46
51
  default_options[:_nested_builder] = nested_builder if block
47
52
 
53
+ # options = options.merge( Defaults.wrap_arrays(options) )
54
+
48
55
  definitions.add(name, default_options.merge(options), &block)
49
56
  end
50
57
 
@@ -62,6 +69,16 @@ module Declarative
62
69
  class_eval(&options[:_block])
63
70
  end
64
71
  end
72
+
73
+ # When called, executes `block` and wraps all array values in Variables::Append.
74
+ # This is the default behavior in older versions and allows to provide arrays for
75
+ # default values that will be prepended.
76
+ def wrap_arrays_from_block(block)
77
+ ->(*args) {
78
+ options = block.(*args)
79
+ options.merge( Defaults.wrap_arrays( options ) )
80
+ }
81
+ end
65
82
  end
66
83
 
67
84
  module Feature
@@ -78,7 +95,7 @@ module Declarative
78
95
  def register_feature(mod)
79
96
  heritage.record(:register_feature, mod) # this is only for inheritance between decorators and modules!!! ("horizontal and vertical")
80
97
 
81
- defaults.merge!(_features: [mod])
98
+ defaults.merge!( _features: Variables::Append([mod]) )
82
99
  end
83
100
  end
84
101
  end
@@ -1,4 +1,14 @@
1
1
  module Declarative
2
+ def self.Inspect(obj)
3
+ string = obj.inspect
4
+
5
+ if obj.is_a?(Proc)
6
+ elements = string.split("/")
7
+ string = "#{elements.first}#{elements.last}"
8
+ end
9
+ string.gsub(/0x\w+/, "")
10
+ end
11
+
2
12
  module Inspect
3
13
  def inspect
4
14
  string = super
@@ -35,4 +45,4 @@ module Declarative
35
45
  super.extend(Declarative::Inspect)
36
46
  end
37
47
  end
38
- end
48
+ end
@@ -0,0 +1,38 @@
1
+ module Declarative
2
+ # Implements the pattern of maintaining a hash of key/values (usually "defaults")
3
+ # that are mutated several times by user and library code (override defaults).
4
+ #
5
+ # The Variables instance then represents the configuration data to be processed by the
6
+ # using library (e.g. Representable or Trailblazer).
7
+ class Variables
8
+ class Proc < ::Proc
9
+ end
10
+
11
+ # @return Hash hash where `overrides` is merged onto `defaults` respecting Merge, Append etc.
12
+ def self.merge(defaults, overrides)
13
+ defaults = defaults.merge({}) # todo: use our DeepDup. # TODO: or how could we provide immutability?
14
+
15
+ overrides.each do |k, v|
16
+ if v.is_a?(Variables::Proc)
17
+ defaults[k] = v.( defaults[k] )
18
+ else
19
+ defaults[k] = v
20
+ end
21
+ end
22
+
23
+ defaults
24
+ end
25
+
26
+ def self.Merge(merged_hash)
27
+ Variables::Proc.new do |original|
28
+ (original || {}).merge( merged_hash )
29
+ end
30
+ end
31
+
32
+ def self.Append(appended_array)
33
+ Variables::Proc.new do |original|
34
+ (original || []) + appended_array
35
+ end
36
+ end
37
+ end # Variables
38
+ end
@@ -1,3 +1,3 @@
1
1
  module Declarative
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -63,26 +63,37 @@ class DefaultsOptionsTest < Minitest::Spec
63
63
  describe "multiple Defaults#merge!" do
64
64
  it "merges arrays automatically" do
65
65
  defaults.merge!(a: 1, b: 2)
66
- defaults.merge!( b: 3, _features: ["A"])
67
- defaults.merge!( _features: ["B", "C"])
66
+ defaults.merge!( b: 3, _features: Declarative::Variables::Append(["A"]) )
67
+ defaults.merge!( _features: Declarative::Variables::Append(["B", "C"]) )
68
68
  defaults.(nil, {}).inspect.must_equal "{:a=>1, :b=>3, :_features=>[\"A\", \"B\", \"C\"]}"
69
69
  end
70
70
 
71
71
  it "what" do
72
- defaults.merge!(_features: ["A"]) do |name, options|
73
- { _features: ["B", "D"] }
72
+ defaults.merge!( _features: Declarative::Variables::Append(["A"]) ) do |name, options|
73
+ { _features: Declarative::Variables::Append( ["B", "D"] ) }
74
74
  end
75
75
 
76
76
  defaults.(nil, {}).inspect.must_equal "{:_features=>[\"A\", \"B\", \"D\"]}"
77
77
  end
78
78
  end
79
- end
80
79
 
81
- class DefaultsMergeTest < Minitest::Spec
82
- it do
83
- a = { a: "a", features: ["b"] }
84
- b = { a: "a", features: ["c", "d"], b: "b" }
80
+ describe "deprecation" do
81
+ require 'stringio'
82
+ before do
83
+ @old_stderr = $stderr
84
+ $stderr = StringIO.new
85
+ end
86
+
87
+ after { $stderr = @old_stderr }
88
+
89
+ it "prints deprecation twice" do
90
+ defaults.merge!( _features: ["A"] ) do |name, options|
91
+ { _features: ["B", "D"] }
92
+ end
85
93
 
86
- Declarative::Defaults::Merge.(a, b).must_equal({:a=>"a", :features=>["b", "c", "d"], :b=>"b"})
94
+ defaults.(nil, {}).inspect.must_equal "{:_features=>[\"A\", \"B\", \"D\"]}"
95
+
96
+ $stderr.string.must_equal %{[Declarative] Defaults#merge! and #call still accept arrays and automatically prepend those. This is now deprecated, you should replace `ary` with `Declarative::Variables::Append(ary)`.\n}*2
97
+ end
87
98
  end
88
99
  end
@@ -0,0 +1,65 @@
1
+ require "test_helper"
2
+
3
+ class DSLOptionsTest < Minitest::Spec
4
+ let(:defaults) { { id: 1, connections: { first: 1, second: 2 }, list: [3] } }
5
+
6
+ Variables = Declarative::Variables
7
+
8
+ after do
9
+ Declarative::Inspect(defaults).must_equal %{{:id=>1, :connections=>{:first=>1, :second=>2}, :list=>[3]}}
10
+ end
11
+
12
+ #- Merge
13
+ it "merges Merge over original" do
14
+ options = Variables.merge(
15
+ defaults,
16
+ connections: Variables::Merge( second: 3, third: 4 )
17
+ )
18
+
19
+ options.must_equal( { id: 1, connections: { first: 1, second: 3, third: 4 }, :list=>[3] } )
20
+ end
21
+
22
+ it "accepts Procs" do
23
+ options = Variables.merge(
24
+ defaults,
25
+ connections: proc = ->(*) { raise }
26
+ )
27
+
28
+ options.must_equal( { id: 1, connections: proc, :list=>[3] } )
29
+ end
30
+
31
+ it "overrides original without Merge" do
32
+ options = Variables.merge(
33
+ defaults, connections: { second: 3, third: 4 } )
34
+
35
+ options.must_equal( { id: 1, connections: { second: 3, third: 4 }, :list=>[3] } )
36
+ end
37
+
38
+ it "creates new hash if original not existent" do
39
+ options = Variables.merge(
40
+ defaults,
41
+ bla: Variables::Merge( second: 3, third: 4 )
42
+ )
43
+
44
+ options.must_equal( {:id=>1, :connections=>{:first=>1, :second=>2}, :list=>[3], :bla=>{:second=>3, :third=>4}} )
45
+ end
46
+
47
+ #- Append
48
+ it "appends to Array" do
49
+ options = Variables.merge(
50
+ defaults,
51
+ list: Variables::Append( [3, 4, 5] )
52
+ )
53
+
54
+ options.must_equal( { id: 1, connections: { first: 1, second: 2 }, :list=>[3, 3, 4, 5] } )
55
+ end
56
+
57
+ it "creates new array if original not existent" do
58
+ options = Variables.merge(
59
+ defaults,
60
+ another_list: Variables::Append( [3, 4, 5] )
61
+ )
62
+
63
+ options.must_equal( { id: 1, connections: { first: 1, second: 2 }, :list=>[3], :another_list=>[3, 4, 5] } )
64
+ end
65
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: declarative
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-28 00:00:00.000000000 Z
11
+ date: 2017-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -74,13 +74,15 @@ files:
74
74
  - lib/declarative/heritage.rb
75
75
  - lib/declarative/schema.rb
76
76
  - lib/declarative/testing.rb
77
+ - lib/declarative/variables.rb
77
78
  - lib/declarative/version.rb
78
79
  - test/defaults_test.rb
79
80
  - test/definitions_test.rb
80
81
  - test/heritage_test.rb
81
82
  - test/schema_test.rb
82
83
  - test/test_helper.rb
83
- homepage: ''
84
+ - test/variables_test.rb
85
+ homepage: https://github.com/apotonick/declarative
84
86
  licenses:
85
87
  - MIT
86
88
  metadata: {}
@@ -100,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
102
  version: '0'
101
103
  requirements: []
102
104
  rubyforge_project:
103
- rubygems_version: 2.6.3
105
+ rubygems_version: 2.6.8
104
106
  signing_key:
105
107
  specification_version: 4
106
108
  summary: DSL for nested schemas.
@@ -110,3 +112,4 @@ test_files:
110
112
  - test/heritage_test.rb
111
113
  - test/schema_test.rb
112
114
  - test/test_helper.rb
115
+ - test/variables_test.rb