dry-initializer 0.1.1 → 0.2.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -9
  3. data/CHANGELOG.md +72 -3
  4. data/LICENSE.txt +1 -1
  5. data/README.md +7 -279
  6. data/benchmarks/with_types.rb +2 -0
  7. data/benchmarks/with_types_and_defaults.rb +2 -0
  8. data/dry-initializer.gemspec +1 -1
  9. data/lib/dry/initializer.rb +5 -4
  10. data/lib/dry/initializer/builder.rb +66 -13
  11. data/lib/dry/initializer/errors.rb +5 -7
  12. data/lib/dry/initializer/errors/default_value_error.rb +6 -0
  13. data/lib/dry/initializer/errors/order_error.rb +7 -0
  14. data/lib/dry/initializer/errors/plugin_error.rb +6 -0
  15. data/lib/dry/initializer/errors/{existing_argument_error.rb → redefinition_error.rb} +1 -1
  16. data/lib/dry/initializer/errors/type_constraint_error.rb +6 -0
  17. data/lib/dry/initializer/errors/type_error.rb +4 -3
  18. data/lib/dry/initializer/mixin.rb +7 -7
  19. data/lib/dry/initializer/plugins.rb +10 -0
  20. data/lib/dry/initializer/plugins/base.rb +42 -0
  21. data/lib/dry/initializer/plugins/default_proc.rb +28 -0
  22. data/lib/dry/initializer/plugins/signature.rb +35 -0
  23. data/lib/dry/initializer/plugins/type_constraint.rb +58 -0
  24. data/lib/dry/initializer/plugins/variable_setter.rb +12 -0
  25. data/lib/dry/initializer/signature.rb +47 -0
  26. data/spec/dry/container_spec.rb +3 -3
  27. data/spec/dry/dry_type_constraint_spec.rb +30 -0
  28. data/spec/dry/invalid_default_spec.rb +1 -1
  29. data/spec/dry/{proc_type_spec.rb → object_type_constraint_spec.rb} +4 -4
  30. data/spec/dry/{poro_type_spec.rb → plain_type_constraint_spec.rb} +1 -1
  31. data/spec/dry/value_coercion_via_dry_types_spec.rb +21 -0
  32. metadata +29 -25
  33. data/lib/dry/initializer/argument.rb +0 -96
  34. data/lib/dry/initializer/arguments.rb +0 -85
  35. data/lib/dry/initializer/errors/invalid_default_value_error.rb +0 -6
  36. data/lib/dry/initializer/errors/invalid_type_error.rb +0 -6
  37. data/lib/dry/initializer/errors/key_error.rb +0 -5
  38. data/lib/dry/initializer/errors/missed_default_value_error.rb +0 -5
  39. data/spec/dry/dry_type_spec.rb +0 -25
  40. data/spec/dry/invalid_type_spec.rb +0 -13
@@ -0,0 +1,47 @@
1
+ module Dry::Initializer
2
+ # Mutable 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
9
+ @list ||= []
10
+ end
11
+
12
+ def add(*args)
13
+ signature = Plugins::Signature.new(*args)
14
+
15
+ validates_uniqueness_of signature
16
+ validates_order_of signature
17
+
18
+ @list << signature
19
+ self
20
+ end
21
+
22
+ def call
23
+ map(&:call).join(", ")
24
+ end
25
+
26
+ private
27
+
28
+ def each
29
+ (@list.select(&:param?) + @list.reject(&:param?)).each do |item|
30
+ yield item
31
+ end
32
+ end
33
+
34
+ def validates_uniqueness_of(signature)
35
+ return unless include? signature
36
+
37
+ fail RedefinitionError.new(signature.name)
38
+ end
39
+
40
+ def validates_order_of(signature)
41
+ return unless signature.param? && !signature.default?
42
+ return unless any? { |item| item.param? && item.default? }
43
+
44
+ fail OrderError.new(signature.name)
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
- describe "base example" do
2
- context 'using block syntax' do
1
+ describe "container" do
2
+ context "with block syntax" do
3
3
  before do
4
4
  class Test::Foo
5
5
  include Dry::Initializer.define {
@@ -21,7 +21,7 @@ describe "base example" do
21
21
  end
22
22
  end
23
23
 
24
- context 'using lambda syntax' do
24
+ context "with lambda syntax" do
25
25
  before do
26
26
  class Test::Foo
27
27
  include Dry::Initializer.define -> do
@@ -0,0 +1,30 @@
1
+ require "dry-types"
2
+
3
+ describe "Dry type constraint" do
4
+ before do
5
+ module Test::Types
6
+ include Dry::Types.module
7
+ end
8
+
9
+ class Test::Foo
10
+ extend Dry::Initializer::Mixin
11
+ param :foo, type: Test::Types::Strict::String
12
+ end
13
+ end
14
+
15
+ context "in case of mismatch" do
16
+ subject { Test::Foo.new 1 }
17
+
18
+ it "raises TypeError" do
19
+ expect { subject }.to raise_error TypeError, /1/
20
+ end
21
+ end
22
+
23
+ context "in case of match" do
24
+ subject { Test::Foo.new "foo" }
25
+
26
+ it "completes the initialization" do
27
+ expect { subject }.not_to raise_error
28
+ end
29
+ end
30
+ end
@@ -8,6 +8,6 @@ describe "invalid default value assignment" do
8
8
  end
9
9
 
10
10
  it "raises TypeError" do
11
- expect { subject }.to raise_error SyntaxError, /1/
11
+ expect { subject }.to raise_error TypeError, /1/
12
12
  end
13
13
  end
@@ -1,14 +1,14 @@
1
- describe "proc type" do
1
+ describe "object type constraint" do
2
2
  before do
3
3
  class Test::Foo
4
4
  extend Dry::Initializer::Mixin
5
5
 
6
- param :foo, type: proc { |val| fail(TypeError) unless String === val }
6
+ param :foo, type: /bar/
7
7
  end
8
8
  end
9
9
 
10
10
  context "in case of mismatch" do
11
- subject { Test::Foo.new :foo }
11
+ subject { Test::Foo.new 'baz' }
12
12
 
13
13
  it "raises TypeError" do
14
14
  expect { subject }.to raise_error TypeError
@@ -16,7 +16,7 @@ describe "proc type" do
16
16
  end
17
17
 
18
18
  context "in case of match" do
19
- subject { Test::Foo.new "foo" }
19
+ subject { Test::Foo.new 'barbar' }
20
20
 
21
21
  it "completes the initialization" do
22
22
  expect { subject }.not_to raise_error
@@ -1,4 +1,4 @@
1
- describe "PORO type" do
1
+ describe "plain type constraint" do
2
2
  before do
3
3
  class Test::Foo
4
4
  extend Dry::Initializer::Mixin
@@ -0,0 +1,21 @@
1
+ require "dry-types"
2
+
3
+ describe "value coercion via dry-types" do
4
+ before do
5
+ module Test::Types
6
+ include Dry::Types.module
7
+ end
8
+
9
+ class Test::Foo
10
+ extend Dry::Initializer::Mixin
11
+
12
+ param :foo, type: Test::Types::Coercible::String
13
+ end
14
+ end
15
+
16
+ subject { Test::Foo.new :foo }
17
+
18
+ it "coerces values" do
19
+ expect(subject.foo).to eql "foo"
20
+ end
21
+ 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.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Kochnev (marshall-lee)
@@ -9,50 +9,50 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-28 00:00:00.000000000 Z
12
+ date: 2016-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
16
  requirements:
18
17
  - - "~>"
19
18
  - !ruby/object:Gem::Version
20
19
  version: '3.0'
21
20
  type: :development
22
- prerelease: false
23
21
  version_requirements: !ruby/object:Gem::Requirement
24
22
  requirements:
25
23
  - - "~>"
26
24
  - !ruby/object:Gem::Version
27
25
  version: '3.0'
26
+ name: rspec
27
+ prerelease: false
28
28
  - !ruby/object:Gem::Dependency
29
- name: rake
30
29
  requirement: !ruby/object:Gem::Requirement
31
30
  requirements:
32
31
  - - "~>"
33
32
  - !ruby/object:Gem::Version
34
33
  version: '10.0'
35
34
  type: :development
36
- prerelease: false
37
35
  version_requirements: !ruby/object:Gem::Requirement
38
36
  requirements:
39
37
  - - "~>"
40
38
  - !ruby/object:Gem::Version
41
39
  version: '10.0'
40
+ name: rake
41
+ prerelease: false
42
42
  - !ruby/object:Gem::Dependency
43
- name: dry-types
44
43
  requirement: !ruby/object:Gem::Requirement
45
44
  requirements:
46
45
  - - "~>"
47
46
  - !ruby/object:Gem::Version
48
47
  version: 0.5.1
49
48
  type: :development
50
- prerelease: false
51
49
  version_requirements: !ruby/object:Gem::Requirement
52
50
  requirements:
53
51
  - - "~>"
54
52
  - !ruby/object:Gem::Version
55
53
  version: 0.5.1
54
+ name: dry-types
55
+ prerelease: false
56
56
  description:
57
57
  email:
58
58
  - hashtable@yandex.ru
@@ -85,30 +85,35 @@ files:
85
85
  - dry-initializer.gemspec
86
86
  - lib/dry-initializer.rb
87
87
  - lib/dry/initializer.rb
88
- - lib/dry/initializer/argument.rb
89
- - lib/dry/initializer/arguments.rb
90
88
  - lib/dry/initializer/builder.rb
91
89
  - lib/dry/initializer/errors.rb
92
- - lib/dry/initializer/errors/existing_argument_error.rb
93
- - lib/dry/initializer/errors/invalid_default_value_error.rb
94
- - lib/dry/initializer/errors/invalid_type_error.rb
95
- - lib/dry/initializer/errors/key_error.rb
96
- - lib/dry/initializer/errors/missed_default_value_error.rb
90
+ - lib/dry/initializer/errors/default_value_error.rb
91
+ - lib/dry/initializer/errors/order_error.rb
92
+ - lib/dry/initializer/errors/plugin_error.rb
93
+ - lib/dry/initializer/errors/redefinition_error.rb
94
+ - lib/dry/initializer/errors/type_constraint_error.rb
97
95
  - lib/dry/initializer/errors/type_error.rb
98
96
  - lib/dry/initializer/mixin.rb
97
+ - lib/dry/initializer/plugins.rb
98
+ - lib/dry/initializer/plugins/base.rb
99
+ - lib/dry/initializer/plugins/default_proc.rb
100
+ - lib/dry/initializer/plugins/signature.rb
101
+ - lib/dry/initializer/plugins/type_constraint.rb
102
+ - lib/dry/initializer/plugins/variable_setter.rb
103
+ - lib/dry/initializer/signature.rb
99
104
  - spec/dry/base_spec.rb
100
105
  - spec/dry/container_spec.rb
101
106
  - spec/dry/default_nil_spec.rb
102
107
  - spec/dry/default_values_spec.rb
103
- - spec/dry/dry_type_spec.rb
108
+ - spec/dry/dry_type_constraint_spec.rb
104
109
  - spec/dry/invalid_default_spec.rb
105
- - spec/dry/invalid_type_spec.rb
106
110
  - spec/dry/missed_default_spec.rb
107
- - spec/dry/poro_type_spec.rb
108
- - spec/dry/proc_type_spec.rb
111
+ - spec/dry/object_type_constraint_spec.rb
112
+ - spec/dry/plain_type_constraint_spec.rb
109
113
  - spec/dry/reader_spec.rb
110
114
  - spec/dry/repetitive_definitions_spec.rb
111
115
  - spec/dry/subclassing_spec.rb
116
+ - spec/dry/value_coercion_via_dry_types_spec.rb
112
117
  - spec/spec_helper.rb
113
118
  homepage: https://github.com/dryrb/dry-initializer
114
119
  licenses:
@@ -130,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
135
  version: '0'
131
136
  requirements: []
132
137
  rubyforge_project:
133
- rubygems_version: 2.5.1
138
+ rubygems_version: 2.6.4
134
139
  signing_key:
135
140
  specification_version: 4
136
141
  summary: DSL for declaring params and options of the initializer
@@ -139,14 +144,13 @@ test_files:
139
144
  - spec/dry/container_spec.rb
140
145
  - spec/dry/default_nil_spec.rb
141
146
  - spec/dry/default_values_spec.rb
142
- - spec/dry/dry_type_spec.rb
147
+ - spec/dry/dry_type_constraint_spec.rb
143
148
  - spec/dry/invalid_default_spec.rb
144
- - spec/dry/invalid_type_spec.rb
145
149
  - spec/dry/missed_default_spec.rb
146
- - spec/dry/poro_type_spec.rb
147
- - spec/dry/proc_type_spec.rb
150
+ - spec/dry/object_type_constraint_spec.rb
151
+ - spec/dry/plain_type_constraint_spec.rb
148
152
  - spec/dry/reader_spec.rb
149
153
  - spec/dry/repetitive_definitions_spec.rb
150
154
  - spec/dry/subclassing_spec.rb
155
+ - spec/dry/value_coercion_via_dry_types_spec.rb
151
156
  - spec/spec_helper.rb
152
- has_rdoc:
@@ -1,96 +0,0 @@
1
- module Dry::Initializer
2
- # A simple structure describes an argument (either param, or option)
3
- #
4
- # @api private
5
- #
6
- class Argument
7
- include Errors
8
-
9
- UNDEFINED = Object.new.freeze
10
-
11
- # @!attribute [r] option
12
- # @return [Boolean]
13
- # Whether this is an option, or param of the initializer
14
- attr_reader :option
15
-
16
- # @!attribute [r] name
17
- # @return [Symbol] the name of the argument
18
- attr_reader :name
19
-
20
- # @!attribute [r] default
21
- # @return [Boolean] whether the argument has a default value
22
- attr_reader :default
23
-
24
- # @!attribute [r] default_value
25
- # @return [Object] the default value of the argument
26
- attr_reader :default_value
27
-
28
- # @!attribute [r] type
29
- # @return [Class, nil] a type constraint
30
- attr_reader :type
31
-
32
- # @!attribute [r] reader
33
- # @return [Boolean] whether an attribute reader is defined for the argument
34
- attr_reader :reader
35
-
36
- def initialize(name, option:, reader: true, **options)
37
- @name = name.to_sym
38
- @option = option
39
- @reader = reader
40
- assign_default_value(options)
41
- assign_type(options)
42
- end
43
-
44
- def ==(other)
45
- other.name == name
46
- end
47
-
48
- def signature
49
- case [option, default]
50
- when [false, false] then name
51
- when [false, true] then "#{name} = Dry::Initializer::Argument::UNDEFINED"
52
- when [true, false] then "#{name}:"
53
- else
54
- "#{name}: Dry::Initializer::Argument::UNDEFINED"
55
- end
56
- end
57
-
58
- def assignment
59
- "@#{name} = #{name}"
60
- end
61
-
62
- def default_assignment
63
- "@#{name} = instance_eval(&__arguments__[:#{name}].default_value)" \
64
- " if #{name} == Dry::Initializer::Argument::UNDEFINED"
65
- end
66
-
67
- def type_constraint
68
- "__arguments__[:#{name}].type.call(@#{name})"
69
- end
70
-
71
- private
72
-
73
- def assign_default_value(options)
74
- @default = options.key? :default
75
- return unless @default
76
-
77
- @default_value = options[:default]
78
- return if Proc === @default_value
79
-
80
- fail InvalidDefaultValueError.new(@default_value)
81
- end
82
-
83
- def assign_type(options)
84
- return unless options.key? :type
85
-
86
- type = options[:type]
87
- type = plain_type_to_proc(type) if Module === type
88
- fail InvalidTypeError.new(type) unless type.respond_to? :call
89
- @type = type
90
- end
91
-
92
- def plain_type_to_proc(type)
93
- proc { |value| fail TypeError.new(type, value) unless type === value }
94
- end
95
- end
96
- end
@@ -1,85 +0,0 @@
1
- module Dry::Initializer
2
- # Collection of definitions for arguments
3
- #
4
- # @api private
5
- #
6
- class Arguments
7
- include Errors
8
- include Enumerable
9
-
10
- def initialize(**arguments)
11
- @arguments = arguments
12
- end
13
-
14
- def add(name, options)
15
- validate_uniqueness(name)
16
- validate_presence_of_default(name, options)
17
-
18
- new_argument = Argument.new(name, options)
19
- self.class.new @arguments.merge(name.to_sym => new_argument)
20
- end
21
-
22
- def declaration
23
- <<-RUBY
24
- attr_reader #{select(&:reader).map { |arg| ":#{arg.name}" }.join(", ")}
25
- define_method :initialize do |#{signature}|
26
- #{assign_arguments}
27
- #{take_declarations}
28
- #{assign_defaults}
29
- #{check_constraints}
30
- end
31
- RUBY
32
- end
33
-
34
- def [](name)
35
- @arguments[name]
36
- end
37
-
38
- private
39
-
40
- def each
41
- @arguments.each { |_, argument| yield(argument) }
42
- end
43
-
44
- def params
45
- reject(&:option)
46
- end
47
-
48
- def options
49
- select(&:option)
50
- end
51
-
52
- def validate_uniqueness(name)
53
- fail ExistingArgumentError.new(name) if self[name.to_sym]
54
- end
55
-
56
- def validate_presence_of_default(name, options)
57
- return if options.key? :default
58
- return if options[:option]
59
- return unless params.any?(&:default)
60
-
61
- fail MissedDefaultValueError.new(name)
62
- end
63
-
64
- def signature
65
- (params + options).map(&:signature).join(", ")
66
- end
67
-
68
- def assign_arguments
69
- map(&:assignment).join("\n")
70
- end
71
-
72
- def take_declarations
73
- return unless any?(&:default) || any?(&:type)
74
- "__arguments__ = self.class.send(:arguments_builder).arguments"
75
- end
76
-
77
- def assign_defaults
78
- select(&:default).map(&:default_assignment).join("\n")
79
- end
80
-
81
- def check_constraints
82
- select(&:type).map(&:type_constraint).join("\n")
83
- end
84
- end
85
- end