declarative 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
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