dry-initializer 0.11.0 → 1.1.0

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