dry-initializer 0.11.0 → 1.1.0

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +4 -61
  4. data/.travis.yml +18 -11
  5. data/CHANGELOG.md +108 -43
  6. data/Gemfile +1 -0
  7. data/Rakefile +6 -0
  8. data/benchmarks/options.rb +4 -4
  9. data/benchmarks/params.rb +1 -1
  10. data/benchmarks/profiler.rb +28 -0
  11. data/benchmarks/with_types.rb +5 -9
  12. data/benchmarks/with_types_and_defaults.rb +2 -4
  13. data/benchmarks/without_options.rb +3 -3
  14. data/dry-initializer.gemspec +1 -1
  15. data/lib/dry/initializer/attribute.rb +92 -0
  16. data/lib/dry/initializer/builder.rb +76 -72
  17. data/lib/dry/initializer/exceptions/default_value_error.rb +8 -0
  18. data/lib/dry/initializer/exceptions/params_order_error.rb +8 -0
  19. data/lib/dry/initializer/exceptions/type_constraint_error.rb +7 -0
  20. data/lib/dry/initializer/option.rb +62 -0
  21. data/lib/dry/initializer/param.rb +54 -0
  22. data/lib/dry/initializer.rb +77 -13
  23. data/spec/enhancement_spec.rb +18 -0
  24. data/spec/missed_default_spec.rb +2 -2
  25. data/spec/optional_spec.rb +16 -6
  26. data/spec/options_var_spec.rb +39 -0
  27. data/spec/repetitive_definitions_spec.rb +38 -18
  28. data/spec/several_assignments_spec.rb +41 -0
  29. data/spec/type_constraint_spec.rb +6 -5
  30. metadata +15 -20
  31. data/lib/dry/initializer/errors/default_value_error.rb +0 -6
  32. data/lib/dry/initializer/errors/order_error.rb +0 -7
  33. data/lib/dry/initializer/errors/plugin_error.rb +0 -6
  34. data/lib/dry/initializer/errors/redefinition_error.rb +0 -5
  35. data/lib/dry/initializer/errors/type_constraint_error.rb +0 -5
  36. data/lib/dry/initializer/errors.rb +0 -10
  37. data/lib/dry/initializer/mixin.rb +0 -77
  38. data/lib/dry/initializer/plugins/base.rb +0 -47
  39. data/lib/dry/initializer/plugins/default_proc.rb +0 -28
  40. data/lib/dry/initializer/plugins/signature.rb +0 -28
  41. data/lib/dry/initializer/plugins/type_constraint.rb +0 -21
  42. data/lib/dry/initializer/plugins/variable_setter.rb +0 -30
  43. data/lib/dry/initializer/plugins.rb +0 -10
  44. data/lib/dry/initializer/signature.rb +0 -61
  45. data/spec/plugin_registry_spec.rb +0 -45
  46. data/spec/renaming_options_spec.rb +0 -20
@@ -5,7 +5,7 @@ describe "type constraint" do
5
5
  before do
6
6
  class Test::Foo
7
7
  extend Dry::Initializer::Mixin
8
- param :foo, type: Dry::Types["strict.string"], optional: true
8
+ param :foo, Dry::Types["strict.string"], optional: true
9
9
  end
10
10
  end
11
11
 
@@ -28,20 +28,21 @@ describe "type constraint" do
28
28
  context "if optional value not set" do
29
29
  subject { Test::Foo.new }
30
30
 
31
- it "completes the initialization" do
32
- expect { subject }.not_to raise_error
31
+ it "not applicable to Dry::Initializer::UNDEFINED" do
32
+ expect(subject.instance_variable_get(:@foo))
33
+ .to eq Dry::Initializer::UNDEFINED
33
34
  end
34
35
  end
35
36
  end
36
37
 
37
38
  context "by invalid constraint" do
38
39
  it "raises TypeError" do
39
- expect {
40
+ expect do
40
41
  class Test::Foo
41
42
  extend Dry::Initializer::Mixin
42
43
  param :foo, type: String
43
44
  end
44
- }.to raise_error(TypeError)
45
+ end.to raise_error(TypeError)
45
46
  end
46
47
  end
47
48
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-initializer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Kochnev (marshall-lee)
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-01-02 00:00:00.000000000 Z
12
+ date: 2017-01-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -91,6 +91,7 @@ files:
91
91
  - benchmarks/options.rb
92
92
  - benchmarks/params.rb
93
93
  - benchmarks/params_vs_options.rb
94
+ - benchmarks/profiler.rb
94
95
  - benchmarks/several_defaults.rb
95
96
  - benchmarks/with_defaults.rb
96
97
  - benchmarks/with_types.rb
@@ -99,34 +100,27 @@ files:
99
100
  - dry-initializer.gemspec
100
101
  - lib/dry-initializer.rb
101
102
  - lib/dry/initializer.rb
103
+ - lib/dry/initializer/attribute.rb
102
104
  - lib/dry/initializer/builder.rb
103
- - lib/dry/initializer/errors.rb
104
- - lib/dry/initializer/errors/default_value_error.rb
105
- - lib/dry/initializer/errors/order_error.rb
106
- - lib/dry/initializer/errors/plugin_error.rb
107
- - lib/dry/initializer/errors/redefinition_error.rb
108
- - lib/dry/initializer/errors/type_constraint_error.rb
109
- - lib/dry/initializer/mixin.rb
110
- - lib/dry/initializer/plugins.rb
111
- - lib/dry/initializer/plugins/base.rb
112
- - lib/dry/initializer/plugins/default_proc.rb
113
- - lib/dry/initializer/plugins/signature.rb
114
- - lib/dry/initializer/plugins/type_constraint.rb
115
- - lib/dry/initializer/plugins/variable_setter.rb
116
- - lib/dry/initializer/signature.rb
105
+ - lib/dry/initializer/exceptions/default_value_error.rb
106
+ - lib/dry/initializer/exceptions/params_order_error.rb
107
+ - lib/dry/initializer/exceptions/type_constraint_error.rb
108
+ - lib/dry/initializer/option.rb
109
+ - lib/dry/initializer/param.rb
117
110
  - spec/base_spec.rb
118
111
  - spec/container_spec.rb
119
112
  - spec/custom_initializer_spec.rb
120
113
  - spec/default_nil_spec.rb
121
114
  - spec/default_values_spec.rb
115
+ - spec/enhancement_spec.rb
122
116
  - spec/invalid_default_spec.rb
123
117
  - spec/missed_default_spec.rb
124
118
  - spec/optional_spec.rb
125
119
  - spec/options_tolerance_spec.rb
126
- - spec/plugin_registry_spec.rb
120
+ - spec/options_var_spec.rb
127
121
  - spec/reader_spec.rb
128
- - spec/renaming_options_spec.rb
129
122
  - spec/repetitive_definitions_spec.rb
123
+ - spec/several_assignments_spec.rb
130
124
  - spec/spec_helper.rb
131
125
  - spec/subclassing_spec.rb
132
126
  - spec/type_argument_spec.rb
@@ -162,14 +156,15 @@ test_files:
162
156
  - spec/custom_initializer_spec.rb
163
157
  - spec/default_nil_spec.rb
164
158
  - spec/default_values_spec.rb
159
+ - spec/enhancement_spec.rb
165
160
  - spec/invalid_default_spec.rb
166
161
  - spec/missed_default_spec.rb
167
162
  - spec/optional_spec.rb
168
163
  - spec/options_tolerance_spec.rb
169
- - spec/plugin_registry_spec.rb
164
+ - spec/options_var_spec.rb
170
165
  - spec/reader_spec.rb
171
- - spec/renaming_options_spec.rb
172
166
  - spec/repetitive_definitions_spec.rb
167
+ - spec/several_assignments_spec.rb
173
168
  - spec/spec_helper.rb
174
169
  - spec/subclassing_spec.rb
175
170
  - spec/type_argument_spec.rb
@@ -1,6 +0,0 @@
1
- class Dry::Initializer::Errors::DefaultValueError < TypeError
2
- def initialize(name, value)
3
- super "Cannot set #{value.inspect} directly as a default value" \
4
- " of the argument '#{name}'. Wrap it to either proc or lambda."
5
- end
6
- end
@@ -1,7 +0,0 @@
1
- class Dry::Initializer::Errors::OrderError < SyntaxError
2
- def initialize(name)
3
- super "Cannot define the required param '#{name}' after optional ones." \
4
- " Either provide a default value for the '#{name}', or declare it" \
5
- " before params with default values."
6
- end
7
- end
@@ -1,6 +0,0 @@
1
- class Dry::Initializer::Errors::PluginError < TypeError
2
- def initialize(plugin)
3
- super "#{plugin} is not a valid plugin." \
4
- " Use a subclass of Dry::Initialier::Plugins::Base."
5
- end
6
- end
@@ -1,5 +0,0 @@
1
- class Dry::Initializer::Errors::RedefinitionError < SyntaxError
2
- def initialize(name)
3
- super "The argument '#{name}' is already defined."
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class Dry::Initializer::Errors::TypeConstraintError < TypeError
2
- def initialize(name, type)
3
- super "#{type} used as constraint for argument '#{name}' is not a dry-type."
4
- end
5
- end
@@ -1,10 +0,0 @@
1
- module Dry::Initializer
2
- # Collection of gem-specific exceptions
3
- module Errors
4
- require_relative "errors/default_value_error"
5
- require_relative "errors/order_error"
6
- require_relative "errors/plugin_error"
7
- require_relative "errors/redefinition_error"
8
- require_relative "errors/type_constraint_error"
9
- end
10
- end
@@ -1,77 +0,0 @@
1
- module Dry::Initializer
2
- # Class-level DSL for the initializer
3
- module Mixin
4
- # Declares a plain argument
5
- #
6
- # @param [#to_sym] name
7
- #
8
- # @option options [Object] :default The default value
9
- # @option options [#call] :type The type constraings via `dry-types`
10
- # @option options [Boolean] :reader (true) Whether to define attr_reader
11
- #
12
- # @return [self] itself
13
- #
14
- def param(name, type = nil, **options)
15
- options[:type] = type if type
16
- options[:option] = false
17
- @__initializer_builder__ = __initializer_builder__.define(name, **options)
18
- __initializer_builder__.call(__initializer_mixin__)
19
- end
20
-
21
- # Declares a named argument
22
- #
23
- # @param (see #param)
24
- # @option (see #param)
25
- # @return (see #param)
26
- #
27
- def option(name, type = nil, **options)
28
- options[:type] = type if type
29
- options[:option] = true
30
- @__initializer_builder__ = __initializer_builder__.define(name, **options)
31
- __initializer_builder__.call(__initializer_mixin__)
32
- end
33
-
34
- # Adds new plugin to the builder
35
- #
36
- # @param [Dry::Initializer::Plugins::Base] plugin
37
- # @return [self] itself
38
- #
39
- def register_initializer_plugin(plugin)
40
- @__initializer_builder__ = __initializer_builder__.register(plugin)
41
- __initializer_builder__.call(__initializer_mixin__)
42
- end
43
-
44
- private
45
-
46
- def __initializer_mixin__
47
- @__initializer_mixin__ ||= Module.new do
48
- def initialize(*args)
49
- __initialize__(*args)
50
- end
51
- end
52
- end
53
-
54
- def __initializer_builder__
55
- @__initializer_builder__ ||= Builder.new
56
- end
57
-
58
- def inherited(klass)
59
- new_builder = __initializer_builder__.dup
60
- klass.instance_variable_set :@__initializer_builder__, new_builder
61
-
62
- new_mixin = Module.new
63
- new_builder.call(new_mixin)
64
- klass.instance_variable_set :@__initializer_mixin__, new_mixin
65
- klass.include new_mixin
66
-
67
- super
68
- end
69
-
70
- def self.extended(klass)
71
- super
72
- mixin = klass.send(:__initializer_mixin__)
73
- klass.send(:__initializer_builder__).call(mixin)
74
- klass.include mixin
75
- end
76
- end
77
- end
@@ -1,47 +0,0 @@
1
- module Dry::Initializer::Plugins
2
- # Base class for plugins
3
- #
4
- # A plugin should has class method [.call] that takes argument name and
5
- # settings and return a chunk of code for the #initialize method body.
6
- #
7
- class Base
8
- include Dry::Initializer::Errors
9
-
10
- # Builds the proc for the `__after_initializer__` callback
11
- #
12
- # @param [#to_s] name
13
- # @param [Hash<Symbol, Object>] settings
14
- #
15
- # @return [String, Proc, nil]
16
- #
17
- def self.call(name, settings)
18
- new(name, settings).call
19
- end
20
-
21
- # @private
22
- attr_reader :name, :settings
23
-
24
- # Initializes a builder with argument name and settings
25
- # @param (see .call)
26
- def initialize(name, settings)
27
- @name = name
28
- @settings = settings
29
- end
30
-
31
- # Checks equality to another instance by name
32
- # @return [Boolean]
33
- def ==(other)
34
- other.instance_of?(self.class) && (other.name == name)
35
- end
36
-
37
- # Builds a chunk of code
38
- # @return (see .call)
39
- def call; end
40
-
41
- # Returns the name for the attribute
42
- # @return (see .name)
43
- def rename
44
- @rename ||= settings[:option] ? (settings[:as] || name) : name
45
- end
46
- end
47
- end
@@ -1,28 +0,0 @@
1
- module Dry::Initializer::Plugins
2
- # Builds a block to be evaluated by initializer (__after_initialize__)
3
- # to assign a default value to the argument
4
- class DefaultProc < Base
5
- def call
6
- return unless default
7
-
8
- ivar = :"@#{rename}"
9
- default_proc = default
10
-
11
- proc do
12
- if instance_variable_get(ivar) == Dry::Initializer::UNDEFINED
13
- instance_variable_set ivar, instance_eval(&default_proc)
14
- end
15
- end
16
- end
17
-
18
- private
19
-
20
- def default
21
- return unless settings.key? :default
22
-
23
- @default ||= settings[:default].tap do |value|
24
- fail DefaultValueError.new(name, value) unless Proc === value
25
- end
26
- end
27
- end
28
- end
@@ -1,28 +0,0 @@
1
- module Dry::Initializer::Plugins
2
- # Plugin builds a chunk of code for the initializer's signature:
3
- #
4
- # @example
5
- # Signature.call(:user)
6
- # # => "user"
7
- #
8
- # Signature.call(:user, default: -> { nil })
9
- # # => "user = Dry::Initializer::UNDEFINED"
10
- #
11
- # Signature.call(:user, option: true)
12
- # # => nil
13
- #
14
- class Signature < Base
15
- def param?
16
- settings[:option] != true
17
- end
18
-
19
- def required?
20
- !settings.key?(:default) && !settings[:optional]
21
- end
22
-
23
- def call
24
- return unless param?
25
- required? ? name.to_s : "#{name} = Dry::Initializer::UNDEFINED"
26
- end
27
- end
28
- end
@@ -1,21 +0,0 @@
1
- module Dry::Initializer::Plugins
2
- # Plugin builds either chunk of code for the #initializer,
3
- # or a proc for the ##__after_initialize__ callback.
4
- class TypeConstraint < Base
5
- def call
6
- return unless settings.key? :type
7
-
8
- type = settings[:type]
9
- fail TypeConstraintError.new(rename, type) unless type.respond_to? :call
10
-
11
- ivar = :"@#{rename}"
12
- lambda do |*|
13
- value = instance_variable_get(ivar)
14
-
15
- if value != Dry::Initializer::UNDEFINED
16
- instance_variable_set ivar, type.call(value)
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,30 +0,0 @@
1
- module Dry::Initializer::Plugins
2
- # Plugin builds a code for variable setter:
3
- #
4
- # @example
5
- # VariableSetter.call(:user, option: false)
6
- # # => "@user = user"
7
- #
8
- # VariableSetter.call(:user, option: true)
9
- # # => "@user = __options__.fetch(:user)"
10
- #
11
- # VariableSetter.call(:user, option: true, optional: true)
12
- # # => "@user = __options__.fetch(:user, Dry::Initializer::UNDEFINED)"
13
- #
14
- class VariableSetter < Base
15
- def param?
16
- settings[:option] != true
17
- end
18
-
19
- def required?
20
- !settings.key?(:default) && !settings[:optional]
21
- end
22
-
23
- def call
24
- return "@#{name} = #{name}" if param?
25
- key = ":\"#{name}\""
26
- return "@#{rename} = __options__.fetch(#{key})" if required?
27
- "@#{rename} = __options__.fetch(#{key}, Dry::Initializer::UNDEFINED)"
28
- end
29
- end
30
- end
@@ -1,10 +0,0 @@
1
- module Dry::Initializer
2
- # Namespace for code plugins builders
3
- module Plugins
4
- require_relative "plugins/base"
5
- require_relative "plugins/default_proc"
6
- require_relative "plugins/signature"
7
- require_relative "plugins/type_constraint"
8
- require_relative "plugins/variable_setter"
9
- end
10
- end
@@ -1,61 +0,0 @@
1
- module Dry::Initializer
2
- # Immutable container for chunks of code describing argument signatures.
3
- # Responcible for building the resulting signature for the initializer args.
4
- class Signature
5
- include Enumerable
6
- include Errors
7
-
8
- def initialize(*list)
9
- @list = list
10
- end
11
-
12
- def add(*args)
13
- signature = Plugins::Signature.new(*args)
14
-
15
- validate_order_of signature
16
- validate_param_uniqueness_of signature
17
- validate_option_uniqueness_of signature
18
- validate_attribute_uniqueness_of signature
19
-
20
- self.class.new(*@list, signature)
21
- end
22
-
23
- def each
24
- @list.each { |item| yield item }
25
- end
26
-
27
- def call
28
- options = all?(&:param?) ? %w(__options__={}) : %w(**__options__)
29
- (select(&:param?).map(&:call) + options).compact.join(", ")
30
- end
31
-
32
- private
33
-
34
- def validate_param_uniqueness_of(signature)
35
- return unless signature.param?
36
- return unless select(&:param?).map(&:name).include? signature.name
37
-
38
- fail RedefinitionError.new(signature.name)
39
- end
40
-
41
- def validate_option_uniqueness_of(signature)
42
- return if signature.param?
43
- return unless reject(&:param?).map(&:name).include? signature.name
44
-
45
- fail RedefinitionError.new(signature.name)
46
- end
47
-
48
- def validate_attribute_uniqueness_of(signature)
49
- return unless map(&:rename).include? signature.rename
50
-
51
- fail RedefinitionError.new(signature.name)
52
- end
53
-
54
- def validate_order_of(signature)
55
- return unless signature.required? && signature.param?
56
- return unless reject(&:required?).any?(&:param?)
57
-
58
- fail OrderError.new(signature.name)
59
- end
60
- end
61
- end