dry-initializer 3.0.2 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +260 -241
- data/LICENSE +1 -1
- data/README.md +18 -77
- data/dry-initializer.gemspec +34 -19
- data/lib/dry/initializer/builders/attribute.rb +78 -69
- data/lib/dry/initializer/builders/initializer.rb +56 -58
- data/lib/dry/initializer/builders/reader.rb +55 -47
- data/lib/dry/initializer/builders/signature.rb +29 -23
- data/lib/dry/initializer/builders.rb +9 -5
- data/lib/dry/initializer/config.rb +162 -158
- data/lib/dry/initializer/definition.rb +58 -54
- data/lib/dry/initializer/dispatchers/build_nested_type.rb +54 -40
- data/lib/dry/initializer/dispatchers/check_type.rb +45 -39
- data/lib/dry/initializer/dispatchers/prepare_default.rb +32 -25
- data/lib/dry/initializer/dispatchers/prepare_ivar.rb +13 -6
- data/lib/dry/initializer/dispatchers/prepare_optional.rb +14 -7
- data/lib/dry/initializer/dispatchers/prepare_reader.rb +29 -22
- data/lib/dry/initializer/dispatchers/prepare_source.rb +12 -5
- data/lib/dry/initializer/dispatchers/prepare_target.rb +44 -37
- data/lib/dry/initializer/dispatchers/unwrap_type.rb +21 -10
- data/lib/dry/initializer/dispatchers/wrap_type.rb +25 -17
- data/lib/dry/initializer/dispatchers.rb +48 -43
- data/lib/dry/initializer/dsl.rb +42 -34
- data/lib/dry/initializer/mixin/local.rb +19 -13
- data/lib/dry/initializer/mixin/root.rb +12 -7
- data/lib/dry/initializer/mixin.rb +17 -12
- data/lib/dry/initializer/struct.rb +34 -29
- data/lib/dry/initializer/undefined.rb +7 -1
- data/lib/dry/initializer/version.rb +7 -0
- data/lib/dry/initializer.rb +2 -0
- data/lib/dry-initializer.rb +2 -0
- data/lib/tasks/benchmark.rake +2 -0
- data/lib/tasks/profile.rake +4 -0
- metadata +25 -125
- data/.codeclimate.yml +0 -12
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
- data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -34
- data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
- data/.github/workflows/custom_ci.yml +0 -74
- data/.github/workflows/docsite.yml +0 -34
- data/.github/workflows/sync_configs.yml +0 -34
- data/.gitignore +0 -12
- data/.rspec +0 -4
- data/.rubocop.yml +0 -89
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -38
- data/Guardfile +0 -5
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -8
- data/benchmarks/compare_several_defaults.rb +0 -82
- data/benchmarks/plain_options.rb +0 -63
- data/benchmarks/plain_params.rb +0 -84
- data/benchmarks/with_coercion.rb +0 -71
- data/benchmarks/with_defaults.rb +0 -66
- data/benchmarks/with_defaults_and_coercion.rb +0 -59
- data/docsite/source/attributes.html.md +0 -106
- data/docsite/source/container-version.html.md +0 -39
- data/docsite/source/index.html.md +0 -43
- data/docsite/source/inheritance.html.md +0 -43
- data/docsite/source/optionals-and-defaults.html.md +0 -130
- data/docsite/source/options-tolerance.html.md +0 -27
- data/docsite/source/params-and-options.html.md +0 -74
- data/docsite/source/rails-support.html.md +0 -101
- data/docsite/source/readers.html.md +0 -43
- data/docsite/source/skip-undefined.html.md +0 -59
- data/docsite/source/type-constraints.html.md +0 -160
- data/spec/attributes_spec.rb +0 -38
- data/spec/coercion_of_nil_spec.rb +0 -25
- data/spec/custom_dispatchers_spec.rb +0 -35
- data/spec/custom_initializer_spec.rb +0 -30
- data/spec/default_values_spec.rb +0 -83
- data/spec/definition_spec.rb +0 -111
- data/spec/invalid_default_spec.rb +0 -13
- data/spec/list_type_spec.rb +0 -32
- data/spec/missed_default_spec.rb +0 -14
- data/spec/nested_type_spec.rb +0 -48
- data/spec/optional_spec.rb +0 -71
- data/spec/options_tolerance_spec.rb +0 -11
- data/spec/public_attributes_utility_spec.rb +0 -22
- data/spec/reader_spec.rb +0 -87
- data/spec/repetitive_definitions_spec.rb +0 -69
- data/spec/several_assignments_spec.rb +0 -41
- data/spec/spec_helper.rb +0 -29
- data/spec/subclassing_spec.rb +0 -49
- data/spec/type_argument_spec.rb +0 -35
- data/spec/type_constraint_spec.rb +0 -78
- data/spec/value_coercion_via_dry_types_spec.rb +0 -29
@@ -1,59 +0,0 @@
|
|
1
|
-
Bundler.require(:benchmarks)
|
2
|
-
|
3
|
-
require "dry-initializer"
|
4
|
-
class DryTest
|
5
|
-
extend Dry::Initializer[undefined: false]
|
6
|
-
|
7
|
-
option :foo, proc(&:to_s), default: -> { "FOO" }
|
8
|
-
option :bar, proc(&:to_s), default: -> { "BAR" }
|
9
|
-
end
|
10
|
-
|
11
|
-
class DryTestUndefined
|
12
|
-
extend Dry::Initializer
|
13
|
-
|
14
|
-
option :foo, proc(&:to_s), default: -> { "FOO" }
|
15
|
-
option :bar, proc(&:to_s), default: -> { "BAR" }
|
16
|
-
end
|
17
|
-
|
18
|
-
class PlainRubyTest
|
19
|
-
attr_reader :foo, :bar
|
20
|
-
|
21
|
-
def initialize(foo: "FOO", bar: "BAR")
|
22
|
-
@foo = foo
|
23
|
-
@bar = bar
|
24
|
-
raise TypeError unless String === @foo
|
25
|
-
raise TypeError unless String === @bar
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
require "virtus"
|
30
|
-
class VirtusTest
|
31
|
-
include Virtus.model
|
32
|
-
|
33
|
-
attribute :foo, String, default: "FOO"
|
34
|
-
attribute :bar, String, default: "BAR"
|
35
|
-
end
|
36
|
-
|
37
|
-
puts "Benchmark for instantiation with type constraints and default values"
|
38
|
-
|
39
|
-
Benchmark.ips do |x|
|
40
|
-
x.config time: 15, warmup: 10
|
41
|
-
|
42
|
-
x.report("plain Ruby") do
|
43
|
-
PlainRubyTest.new
|
44
|
-
end
|
45
|
-
|
46
|
-
x.report("dry-initializer") do
|
47
|
-
DryTest.new
|
48
|
-
end
|
49
|
-
|
50
|
-
x.report("dry-initializer (with UNDEFINED)") do
|
51
|
-
DryTest.new
|
52
|
-
end
|
53
|
-
|
54
|
-
x.report("virtus") do
|
55
|
-
VirtusTest.new
|
56
|
-
end
|
57
|
-
|
58
|
-
x.compare!
|
59
|
-
end
|
@@ -1,106 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Attributes
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
Sometimes you need to access all attributes assigned via params and options of the object constructor.
|
8
|
-
|
9
|
-
We support 2 methods: `attributes` and `public_attributes` for this goal. Both methods are wrapped into container accessible via `.dry_types` container:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
require 'dry-initializer'
|
13
|
-
|
14
|
-
class User
|
15
|
-
extend Dry::Initializer
|
16
|
-
|
17
|
-
param :name
|
18
|
-
option :email, optional: true
|
19
|
-
option :telefon, optional: true, as: :phone
|
20
|
-
end
|
21
|
-
|
22
|
-
user = User.new "Andy", telefon: "71002003040"
|
23
|
-
|
24
|
-
User.dry_initializer.attributes(user)
|
25
|
-
# => { name: "Andy", phone: "71002003040" }
|
26
|
-
```
|
27
|
-
|
28
|
-
What the method does is extracts *variables assigned* to the object (and skips unassigned ones like the `email` above). It doesn't matter whether you send it via `params` or `option`; we look at the result of the instantiation, not at the interface.
|
29
|
-
|
30
|
-
Method `public_attributes` works different. Let's look at the following example to see the difference:
|
31
|
-
|
32
|
-
```ruby
|
33
|
-
require 'dry-initializer'
|
34
|
-
|
35
|
-
class User
|
36
|
-
extend Dry::Initializer
|
37
|
-
|
38
|
-
param :name
|
39
|
-
option :telefon, optional: true, as: :phone
|
40
|
-
option :email, optional: true
|
41
|
-
option :token, optional: true, reader: :private
|
42
|
-
option :password, optional: true, reader: false
|
43
|
-
end
|
44
|
-
|
45
|
-
user = User.new "Andy", telefon: "71002003040", token: "foo", password: "bar"
|
46
|
-
|
47
|
-
User.dry_initializer.attributes(user)
|
48
|
-
# => { name: "Andy", phone: "71002003040", token: "foo", password: "bar" }
|
49
|
-
|
50
|
-
User.dry_initializer.public_attributes(user)
|
51
|
-
# => { name: "Andy", phone: "71002003040", email: nil }
|
52
|
-
```
|
53
|
-
|
54
|
-
Notice that `public_attribute` reads *public reader methods*, not variables. That's why it skips both the private `token`, and the `password` whose reader hasn't been defined.
|
55
|
-
|
56
|
-
Another difference concerns unassigned values. Because the reader `user.email` returns `nil` (its `@email` variable contains `Dry::Initializer::UNDEFINED` constant), the `public_attributes` adds this value to the hash using the method.
|
57
|
-
|
58
|
-
The third thing to mention is that you can override the reader, and it is the overriden method which will be used by `public_attributes`:
|
59
|
-
|
60
|
-
```ruby
|
61
|
-
require 'dry-initializer'
|
62
|
-
|
63
|
-
class User
|
64
|
-
extend Dry::Initializer
|
65
|
-
|
66
|
-
param :name
|
67
|
-
option :password, optional: true
|
68
|
-
|
69
|
-
def password
|
70
|
-
super.hash.to_s
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
user = User.new "Joe", password: "foo"
|
75
|
-
|
76
|
-
User.dry_initializer.attributes(user)
|
77
|
-
# => { user: "Joe", password: "foo" }
|
78
|
-
|
79
|
-
User.dry_initializer.public_attributes(user)
|
80
|
-
# => { user: "Joe", password: "-1844874613000160009" }
|
81
|
-
```
|
82
|
-
|
83
|
-
This feature works for the "extend Dry::Initializer" syntax. But what about "include Dry::Initializer.define ..."? Now we don't pollute class namespace with new methods, that's why `.dry_initializer` is absent.
|
84
|
-
|
85
|
-
To access config you can use a hack. Under the hood we define private instance method `#__dry_initializer_config__` which refers to the same container. So you can write:
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
require 'dry-initializer'
|
89
|
-
|
90
|
-
class User
|
91
|
-
extend Dry::Initializer
|
92
|
-
param :name
|
93
|
-
end
|
94
|
-
|
95
|
-
user = User.new "Joe"
|
96
|
-
|
97
|
-
user.send(:__dry_initializer_config__).attributes(user)
|
98
|
-
# => { user: "Joe" }
|
99
|
-
|
100
|
-
user.send(:__dry_initializer_config__).public_attributes(user)
|
101
|
-
# => { user: "Joe" }
|
102
|
-
```
|
103
|
-
|
104
|
-
This is a hack because the `__dry_initializer_config__` is not a part of the gem's public interface; there's a possibility it can be changed or removed in the later releases.
|
105
|
-
|
106
|
-
We'll try to be careful with it, and mark it as deprecated method in case of such a removal.
|
@@ -1,39 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Container Version
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
Instead of extending a class with the `Dry::Initializer`, you can include a container with the `initializer` method only. This method should be preferred when you don't need subclassing.
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
require 'dry-initializer'
|
11
|
-
|
12
|
-
class User
|
13
|
-
# notice `-> do .. end` syntax
|
14
|
-
include Dry::Initializer.define -> do
|
15
|
-
param :name, proc(&:to_s)
|
16
|
-
param :role, default: proc { 'customer' }
|
17
|
-
option :admin, default: proc { false }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
```
|
21
|
-
|
22
|
-
If you still need the DSL (`param` and `option`) to be inherited, use the direct extension:
|
23
|
-
|
24
|
-
```ruby
|
25
|
-
require 'dry-initializer'
|
26
|
-
|
27
|
-
class BaseService
|
28
|
-
extend Dry::Initializer
|
29
|
-
alias_method :dependency, :param
|
30
|
-
end
|
31
|
-
|
32
|
-
class ShowUser < BaseService
|
33
|
-
dependency :user
|
34
|
-
|
35
|
-
def call
|
36
|
-
puts user&.name
|
37
|
-
end
|
38
|
-
end
|
39
|
-
```
|
@@ -1,43 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Introduction & Usage
|
3
|
-
description: DSL for defining initializer params and options
|
4
|
-
layout: gem-single
|
5
|
-
order: 8
|
6
|
-
type: gem
|
7
|
-
name: dry-initializer
|
8
|
-
sections:
|
9
|
-
- container-version
|
10
|
-
- params-and-options
|
11
|
-
- options-tolerance
|
12
|
-
- optionals-and-defaults
|
13
|
-
- type-constraints
|
14
|
-
- readers
|
15
|
-
- inheritance
|
16
|
-
- skip-undefined
|
17
|
-
- attributes
|
18
|
-
- rails-support
|
19
|
-
---
|
20
|
-
|
21
|
-
`dry-initializer` is a simple mixin of class methods `params` and `options` for instances.
|
22
|
-
|
23
|
-
## Synopsis
|
24
|
-
|
25
|
-
```ruby
|
26
|
-
require 'dry-initializer'
|
27
|
-
|
28
|
-
class User
|
29
|
-
extend Dry::Initializer
|
30
|
-
|
31
|
-
param :name, proc(&:to_s)
|
32
|
-
param :role, default: proc { 'customer' }
|
33
|
-
option :admin, default: proc { false }
|
34
|
-
option :phone, optional: true
|
35
|
-
end
|
36
|
-
|
37
|
-
user = User.new 'Vladimir', 'admin', admin: true
|
38
|
-
|
39
|
-
user.name # => 'Vladimir'
|
40
|
-
user.role # => 'admin'
|
41
|
-
user.admin # => true
|
42
|
-
user.phone # => nil
|
43
|
-
```
|
@@ -1,43 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Inheritance
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
Subclassing preserves all definitions being made inside a superclass.
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
require 'dry-initializer'
|
11
|
-
|
12
|
-
class User
|
13
|
-
extend Dry::Initializer
|
14
|
-
|
15
|
-
param :name
|
16
|
-
end
|
17
|
-
|
18
|
-
class Employee < User
|
19
|
-
param :position
|
20
|
-
end
|
21
|
-
|
22
|
-
employee = Employee.new('John', 'supercargo')
|
23
|
-
employee.name # => 'John'
|
24
|
-
employee.position # => 'supercargo'
|
25
|
-
|
26
|
-
employee = Employee.new # => fails because type
|
27
|
-
```
|
28
|
-
|
29
|
-
You can override params and options.
|
30
|
-
Such overriding leaves initial order of params (positional arguments) unchanged:
|
31
|
-
|
32
|
-
```ruby
|
33
|
-
class Employee < User
|
34
|
-
param :position, optional: true
|
35
|
-
param :name, default: proc { 'Unknown' }
|
36
|
-
end
|
37
|
-
|
38
|
-
user = User.new # => Boom! because User#name is required
|
39
|
-
employee = Employee.new # passes because who cares on employee's name
|
40
|
-
|
41
|
-
employee.name
|
42
|
-
# => 'Unknown' because it is the name that positioned first like in User
|
43
|
-
```
|
@@ -1,130 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Optional Attributes and Default Values
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
By default both params and options are mandatory. Use `:default` key to make them optional:
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
require 'dry-initializer'
|
11
|
-
|
12
|
-
class User
|
13
|
-
extend Dry::Initializer
|
14
|
-
|
15
|
-
param :name, default: proc { 'Unknown user' }
|
16
|
-
option :email, default: proc { 'unknown@example.com' }
|
17
|
-
option :phone, optional: true
|
18
|
-
end
|
19
|
-
|
20
|
-
user = User.new
|
21
|
-
user.name # => 'Unknown user'
|
22
|
-
user.email # => 'unknown@example.com'
|
23
|
-
user.phone # => Dry::Initializer::UNDEFINED
|
24
|
-
|
25
|
-
user = User.new 'Vladimir', email: 'vladimir@example.com', phone: '71234567788'
|
26
|
-
user.name # => 'Vladimir'
|
27
|
-
user.email # => 'vladimir@example.com'
|
28
|
-
user.phone # => '71234567788'
|
29
|
-
```
|
30
|
-
|
31
|
-
You cannot define required **parameter** after optional one. The following example raises `SyntaxError` exception:
|
32
|
-
|
33
|
-
```ruby
|
34
|
-
require 'dry-initializer'
|
35
|
-
|
36
|
-
class User
|
37
|
-
extend Dry::Initializer
|
38
|
-
|
39
|
-
param :name, default: proc { 'Unknown name' }
|
40
|
-
param :email # => #<SyntaxError ...>
|
41
|
-
end
|
42
|
-
```
|
43
|
-
|
44
|
-
You should assign `nil` value explicitly. Otherwise an instance variable it will be left undefined. In both cases attribute reader method will return `nil`.
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
require 'dry-initializer'
|
48
|
-
|
49
|
-
class User
|
50
|
-
extend Dry::Initializer
|
51
|
-
|
52
|
-
param :name
|
53
|
-
option :email, optional: true
|
54
|
-
end
|
55
|
-
|
56
|
-
user = User.new 'Andrew'
|
57
|
-
user.email # => nil
|
58
|
-
user.instance_variable_get :@email
|
59
|
-
# => Dry::Initializer::UNDEFINED
|
60
|
-
|
61
|
-
user = User.new 'Andrew', email: nil
|
62
|
-
user.email # => nil
|
63
|
-
user.instance_variable_get :@email
|
64
|
-
# => nil
|
65
|
-
```
|
66
|
-
|
67
|
-
You can also set `nil` as a default value:
|
68
|
-
|
69
|
-
```ruby
|
70
|
-
require 'dry-initializer'
|
71
|
-
|
72
|
-
class User
|
73
|
-
extend Dry::Initializer
|
74
|
-
|
75
|
-
param :name
|
76
|
-
option :email, default: proc { nil }
|
77
|
-
end
|
78
|
-
|
79
|
-
user = User.new 'Andrew'
|
80
|
-
user.email # => nil
|
81
|
-
user.instance_variable_get :@email
|
82
|
-
# => nil
|
83
|
-
```
|
84
|
-
|
85
|
-
You **must** wrap default values into procs.
|
86
|
-
|
87
|
-
If you need to **assign** proc as a default value, wrap it to another one:
|
88
|
-
|
89
|
-
```ruby
|
90
|
-
require 'dry-initializer'
|
91
|
-
|
92
|
-
class User
|
93
|
-
extend Dry::Initializer
|
94
|
-
|
95
|
-
param :name_proc, default: proc { proc { 'Unknown user' } }
|
96
|
-
end
|
97
|
-
|
98
|
-
user = User.new
|
99
|
-
user.name_proc.call # => 'Unknown user'
|
100
|
-
```
|
101
|
-
|
102
|
-
Proc will be executed in a scope of new instance. You can refer to other arguments:
|
103
|
-
|
104
|
-
```ruby
|
105
|
-
require 'dry-initializer'
|
106
|
-
|
107
|
-
class User
|
108
|
-
extend Dry::Initializer
|
109
|
-
|
110
|
-
param :name
|
111
|
-
param :email, default: proc { "#{name.downcase}@example.com" }
|
112
|
-
end
|
113
|
-
|
114
|
-
user = User.new 'Andrew'
|
115
|
-
user.email # => 'andrew@example.com'
|
116
|
-
```
|
117
|
-
|
118
|
-
**Warning**: when using lambdas instead of procs, don't forget an argument, required by [instance_eval][instance_eval] (you can skip in in a proc).
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
require 'dry-initializer'
|
122
|
-
|
123
|
-
class User
|
124
|
-
extend Dry::Initializer
|
125
|
-
|
126
|
-
param :name, default: -> (obj) { 'Dude' }
|
127
|
-
end
|
128
|
-
```
|
129
|
-
|
130
|
-
[instance_eval]: http://ruby-doc.org/core-2.2.0/BasicObject.html#method-i-instance_eval
|
@@ -1,27 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Tolerance to Unknown Options
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
By default the initializer is strict for params (positional arguments), expecting them to be defined explicitly.
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
require 'dry-initializer'
|
11
|
-
|
12
|
-
class User
|
13
|
-
extend Dry::Initializer
|
14
|
-
end
|
15
|
-
|
16
|
-
user = User.new 'Joe' # raises ArgumentError
|
17
|
-
```
|
18
|
-
|
19
|
-
At the same time it is tolerant to unknown options. All unknown options are accepted, but ignored:
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
# It accepts undefined options...
|
23
|
-
user = User.new name: 'Joe'
|
24
|
-
|
25
|
-
# ...but ignores them
|
26
|
-
user.respond_to? :name # => false
|
27
|
-
```
|
@@ -1,74 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Params and Options
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
Use `param` to define plain argument:
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
require 'dry-initializer'
|
11
|
-
|
12
|
-
class User
|
13
|
-
extend Dry::Initializer
|
14
|
-
|
15
|
-
param :name
|
16
|
-
param :email
|
17
|
-
end
|
18
|
-
|
19
|
-
user = User.new 'Andrew', 'andrew@email.com'
|
20
|
-
user.name # => 'Andrew'
|
21
|
-
user.email # => 'andrew@email.com'
|
22
|
-
```
|
23
|
-
|
24
|
-
Use `option` to define named (hash) argument:
|
25
|
-
|
26
|
-
```ruby
|
27
|
-
require 'dry-initializer'
|
28
|
-
|
29
|
-
class User
|
30
|
-
extend Dry::Initializer
|
31
|
-
|
32
|
-
option :name
|
33
|
-
option :email
|
34
|
-
end
|
35
|
-
|
36
|
-
user = User.new email: 'andrew@email.com', name: 'Andrew'
|
37
|
-
user.name # => 'Andrew'
|
38
|
-
user.email # => 'andrew@email.com'
|
39
|
-
```
|
40
|
-
|
41
|
-
Options can be renamed using `:as` key:
|
42
|
-
|
43
|
-
```ruby
|
44
|
-
require 'dry-initializer'
|
45
|
-
|
46
|
-
class User
|
47
|
-
extend Dry::Initializer
|
48
|
-
|
49
|
-
option :name, as: :username
|
50
|
-
end
|
51
|
-
|
52
|
-
user = User.new name: "Joe"
|
53
|
-
user.username # => "Joe"
|
54
|
-
user.instance_variable_get :@username # => "Joe"
|
55
|
-
user.instance_variable_get :@name # => nil
|
56
|
-
user.respond_to? :name # => false
|
57
|
-
```
|
58
|
-
|
59
|
-
You can also define several ways of initializing the same argument via different options:
|
60
|
-
|
61
|
-
```ruby
|
62
|
-
require 'dry-initializer'
|
63
|
-
|
64
|
-
class User
|
65
|
-
extend Dry::Initializer
|
66
|
-
|
67
|
-
option :phone
|
68
|
-
option :telephone, as: :phone
|
69
|
-
option :name, optional: true
|
70
|
-
end
|
71
|
-
|
72
|
-
User.new(phone: '1234567890').phone # => '1234567890'
|
73
|
-
User.new(telephone: '1234567890').phone # => '1234567890'
|
74
|
-
```
|
@@ -1,101 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Rails Support
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
Rails plugin is implemented in a separate [dry-initializer-rails](https://github.com/nepalez/dry-initializer-rails) gem.
|
8
|
-
|
9
|
-
It provides coercion of assigned values to corresponding ActiveRecord instances.
|
10
|
-
|
11
|
-
### Base Example
|
12
|
-
|
13
|
-
Add the `:model` setting to `param` or `option`:
|
14
|
-
|
15
|
-
```ruby
|
16
|
-
require 'dry-initializer-rails'
|
17
|
-
|
18
|
-
class CreateOrder
|
19
|
-
extend Dry::Initializer
|
20
|
-
|
21
|
-
# Params and options
|
22
|
-
param :customer, model: 'Customer' # use either a name
|
23
|
-
option :product, model: Product # or a class
|
24
|
-
|
25
|
-
def call
|
26
|
-
Order.create customer: customer, product: product
|
27
|
-
end
|
28
|
-
end
|
29
|
-
```
|
30
|
-
|
31
|
-
Now you can assign values as pre-initialized model instances:
|
32
|
-
|
33
|
-
```ruby
|
34
|
-
customer = Customer.find(1)
|
35
|
-
product = Product.find(2)
|
36
|
-
|
37
|
-
order = CreateOrder.new(customer, product: product).call
|
38
|
-
order.customer # => <Customer @id=1 ...>
|
39
|
-
order.product # => <Product @id=2 ...>
|
40
|
-
```
|
41
|
-
|
42
|
-
...or their ids:
|
43
|
-
|
44
|
-
```ruby
|
45
|
-
order = CreateOrder.new(1, product: 2).call
|
46
|
-
order.customer # => <Customer @id=1 ...>
|
47
|
-
order.product # => <Product @id=2 ...>
|
48
|
-
```
|
49
|
-
|
50
|
-
The instance is envoked using method `find_by(id: ...)`.
|
51
|
-
With wrong ids `nil` values are assigned to corresponding params and options:
|
52
|
-
|
53
|
-
```ruby
|
54
|
-
order = CreateOrder.new(0, product: 0).call
|
55
|
-
order.customer # => nil
|
56
|
-
order.product # => nil
|
57
|
-
```
|
58
|
-
|
59
|
-
### Custom Keys
|
60
|
-
|
61
|
-
You can specify custom `key` for searching model instance:
|
62
|
-
|
63
|
-
```ruby
|
64
|
-
require 'dry-initializer-rails'
|
65
|
-
|
66
|
-
class CreateOrder
|
67
|
-
extend Dry::Initializer
|
68
|
-
|
69
|
-
param :customer, model: 'User', find_by: 'name'
|
70
|
-
option :product, model: Item, find_by: :name
|
71
|
-
end
|
72
|
-
```
|
73
|
-
|
74
|
-
This time you can send names (not ids) to the initializer:
|
75
|
-
|
76
|
-
```ruby
|
77
|
-
order = CreateOrder.new('Andrew', product: 'the_thing_no_123').call
|
78
|
-
|
79
|
-
order.customer # => <User @name='Andrew' ...>
|
80
|
-
order.product # => <Item @name='the_thing_no_123' ...>
|
81
|
-
```
|
82
|
-
|
83
|
-
### Container Syntax
|
84
|
-
|
85
|
-
If you prefer [container syntax](docs::container-version), extend plugin inside the block:
|
86
|
-
|
87
|
-
```ruby
|
88
|
-
require 'dry-initializer-rails'
|
89
|
-
|
90
|
-
class CreateOrder
|
91
|
-
include Dry::Initializer.define -> do
|
92
|
-
# ... params/options declarations
|
93
|
-
end
|
94
|
-
end
|
95
|
-
```
|
96
|
-
|
97
|
-
### Types vs Models
|
98
|
-
|
99
|
-
[Type constraints](docs::type-constraints) are checked before the coercion.
|
100
|
-
|
101
|
-
When mixing `:type` and `:model` settings for the same param/option, you should use [sum types](/gems/dry-types/1.2/sum) that accept both model instances and their attributes.
|
@@ -1,43 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Readers
|
3
|
-
layout: gem-single
|
4
|
-
name: dry-initializer
|
5
|
-
---
|
6
|
-
|
7
|
-
By default public attribute reader is defined for every param and option.
|
8
|
-
|
9
|
-
You can define private or protected reader instead:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
require 'dry-initializer'
|
13
|
-
|
14
|
-
class User
|
15
|
-
extend Dry::Initializer
|
16
|
-
|
17
|
-
param :name, reader: :private # the same as adding `private :name`
|
18
|
-
param :email, reader: :protected # the same as adding `protected :email`
|
19
|
-
end
|
20
|
-
```
|
21
|
-
|
22
|
-
To skip any reader, use `reader: false`:
|
23
|
-
|
24
|
-
```ruby
|
25
|
-
require 'dry-initializer'
|
26
|
-
|
27
|
-
class User
|
28
|
-
extend Dry::Initializer
|
29
|
-
|
30
|
-
param :name
|
31
|
-
param :email, reader: false
|
32
|
-
end
|
33
|
-
|
34
|
-
user = User.new 'Luke', 'luke@example.com'
|
35
|
-
user.name # => 'Luke'
|
36
|
-
|
37
|
-
user.email # => #<NoMethodError ...>
|
38
|
-
user.instance_variable_get :@email # => 'luke@example.com'
|
39
|
-
```
|
40
|
-
|
41
|
-
Notice that any other value except for `false`, `:protected` and `:private` provides a public reader.
|
42
|
-
|
43
|
-
No writers are defined. Define them using pure ruby `attr_writer` when necessary.
|