dry-initializer 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +23 -0
- data/.gitignore +10 -0
- data/.rspec +4 -0
- data/.rubocop.yml +51 -0
- data/.travis.yml +28 -0
- data/CHANGELOG.md +883 -0
- data/Gemfile +29 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -0
- data/Rakefile +8 -0
- data/benchmarks/compare_several_defaults.rb +82 -0
- data/benchmarks/plain_options.rb +63 -0
- data/benchmarks/plain_params.rb +84 -0
- data/benchmarks/with_coercion.rb +71 -0
- data/benchmarks/with_defaults.rb +66 -0
- data/benchmarks/with_defaults_and_coercion.rb +59 -0
- data/dry-initializer.gemspec +20 -0
- data/lib/dry-initializer.rb +1 -0
- data/lib/dry/initializer.rb +61 -0
- data/lib/dry/initializer/builders.rb +7 -0
- data/lib/dry/initializer/builders/attribute.rb +81 -0
- data/lib/dry/initializer/builders/initializer.rb +61 -0
- data/lib/dry/initializer/builders/reader.rb +50 -0
- data/lib/dry/initializer/builders/signature.rb +32 -0
- data/lib/dry/initializer/config.rb +184 -0
- data/lib/dry/initializer/definition.rb +65 -0
- data/lib/dry/initializer/dispatchers.rb +112 -0
- data/lib/dry/initializer/dispatchers/build_nested_type.rb +59 -0
- data/lib/dry/initializer/dispatchers/check_type.rb +43 -0
- data/lib/dry/initializer/dispatchers/prepare_default.rb +40 -0
- data/lib/dry/initializer/dispatchers/prepare_ivar.rb +12 -0
- data/lib/dry/initializer/dispatchers/prepare_optional.rb +13 -0
- data/lib/dry/initializer/dispatchers/prepare_reader.rb +30 -0
- data/lib/dry/initializer/dispatchers/prepare_source.rb +28 -0
- data/lib/dry/initializer/dispatchers/prepare_target.rb +44 -0
- data/lib/dry/initializer/dispatchers/unwrap_type.rb +22 -0
- data/lib/dry/initializer/dispatchers/wrap_type.rb +27 -0
- data/lib/dry/initializer/dsl.rb +43 -0
- data/lib/dry/initializer/mixin.rb +15 -0
- data/lib/dry/initializer/mixin/local.rb +19 -0
- data/lib/dry/initializer/mixin/root.rb +10 -0
- data/lib/dry/initializer/struct.rb +40 -0
- data/lib/dry/initializer/undefined.rb +2 -0
- data/lib/tasks/benchmark.rake +41 -0
- data/lib/tasks/profile.rake +78 -0
- data/spec/attributes_spec.rb +38 -0
- data/spec/coercion_of_nil_spec.rb +25 -0
- data/spec/custom_dispatchers_spec.rb +35 -0
- data/spec/custom_initializer_spec.rb +30 -0
- data/spec/default_values_spec.rb +83 -0
- data/spec/definition_spec.rb +111 -0
- data/spec/invalid_default_spec.rb +13 -0
- data/spec/list_type_spec.rb +32 -0
- data/spec/missed_default_spec.rb +14 -0
- data/spec/nested_type_spec.rb +44 -0
- data/spec/optional_spec.rb +71 -0
- data/spec/options_tolerance_spec.rb +11 -0
- data/spec/public_attributes_utility_spec.rb +22 -0
- data/spec/reader_spec.rb +87 -0
- data/spec/repetitive_definitions_spec.rb +69 -0
- data/spec/several_assignments_spec.rb +41 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/subclassing_spec.rb +49 -0
- data/spec/type_argument_spec.rb +35 -0
- data/spec/type_constraint_spec.rb +78 -0
- data/spec/value_coercion_via_dry_types_spec.rb +29 -0
- metadata +189 -0
data/Gemfile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem"s dependencies in dry-initializer.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :benchmarks do
|
7
|
+
if RUBY_VERSION < "2.4"
|
8
|
+
gem "activesupport", "< 5"
|
9
|
+
else
|
10
|
+
gem "activesupport"
|
11
|
+
end
|
12
|
+
|
13
|
+
gem "active_attr"
|
14
|
+
gem "anima"
|
15
|
+
gem "attr_extras"
|
16
|
+
gem "benchmark-ips", "~> 2.5"
|
17
|
+
gem "concord"
|
18
|
+
gem "fast_attributes"
|
19
|
+
gem "kwattr"
|
20
|
+
gem "ruby-prof", platform: :mri
|
21
|
+
gem "value_struct"
|
22
|
+
gem "values"
|
23
|
+
gem "virtus"
|
24
|
+
end
|
25
|
+
|
26
|
+
group :development, :test do
|
27
|
+
gem "pry", platform: :mri
|
28
|
+
gem "pry-byebug", platform: :mri
|
29
|
+
end
|
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016-2017 Andrew Kozin (nepalez), Vladimir Kochnev (marshall-lee)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# dry-initializer [![Join the chat at https://gitter.im/dry-rb/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dry-rb/chat)
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/dry-initializer.svg)][gem]
|
4
|
+
[![Build Status](https://travis-ci.org/dry-rb/dry-initializer.svg?branch=master)][travis]
|
5
|
+
[![Code Climate](https://codeclimate.com/github/dry-rb/dry-initializer/badges/gpa.svg)][codeclimate]
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/dry-rb/dry-initializer/badges/coverage.svg)][coveralls]
|
7
|
+
[![Inline docs](http://inch-ci.org/github/dry-rb/dry-initializer.svg?branch=master)][inchpages]
|
8
|
+
|
9
|
+
[gem]: https://rubygems.org/gems/dry-initializer
|
10
|
+
[travis]: https://travis-ci.org/dry-rb/dry-initializer
|
11
|
+
[gemnasium]: https://gemnasium.com/dry-rb/dry-initializer
|
12
|
+
[codeclimate]: https://codeclimate.com/github/dry-rb/dry-initializer
|
13
|
+
[coveralls]: https://coveralls.io/r/dry-rb/dry-initializer
|
14
|
+
[inchpages]: http://inch-ci.org/github/dry-rb/dry-initializer
|
15
|
+
[docs]: http://dry-rb.org/gems/dry-initializer/
|
16
|
+
[benchmarks]: https://github.com/dry-rb/dry-initializer/wiki
|
17
|
+
[license]: http://opensource.org/licenses/MIT
|
18
|
+
|
19
|
+
DSL for building class initializer with params and options.
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'dry-initializer'
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
```shell
|
32
|
+
$ bundle
|
33
|
+
```
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
```shell
|
38
|
+
$ gem install dry-initializer
|
39
|
+
```
|
40
|
+
|
41
|
+
## Synopsis
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require 'dry-initializer'
|
45
|
+
require 'dry-types'
|
46
|
+
|
47
|
+
class User
|
48
|
+
extend Dry::Initializer
|
49
|
+
|
50
|
+
# Params of the initializer along with corresponding readers
|
51
|
+
param :name, proc(&:to_s)
|
52
|
+
param :role, default: -> { 'customer' }
|
53
|
+
# Options of the initializer along with corresponding readers
|
54
|
+
option :admin, default: -> { false }
|
55
|
+
option :vip, optional: true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Defines the initializer with params and options
|
59
|
+
user = User.new 'Vladimir', 'admin', admin: true
|
60
|
+
|
61
|
+
# Defines readers for single attributes
|
62
|
+
user.name # => 'Vladimir'
|
63
|
+
user.role # => 'admin'
|
64
|
+
user.admin # => true
|
65
|
+
user.vip # => Dry::Initializer::UNDEFINED
|
66
|
+
```
|
67
|
+
|
68
|
+
See full documentation on the [Dry project official site][docs]
|
69
|
+
|
70
|
+
## Benchmarks
|
71
|
+
|
72
|
+
The `dry-initializer` is pretty fast for rubies 2.3+ [comparing to other libraries][benchmarks].
|
73
|
+
|
74
|
+
## Compatibility
|
75
|
+
|
76
|
+
Tested under rubies [compatible to MRI 2.3+](.travis.yml).
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
* [Fork the project](https://github.com/dry-rb/dry-initializer)
|
81
|
+
* Create your feature branch (`git checkout -b my-new-feature`)
|
82
|
+
* Add tests for it
|
83
|
+
* Commit your changes (`git commit -am '[UPDATE] Add some feature'`)
|
84
|
+
* Push to the branch (`git push origin my-new-feature`)
|
85
|
+
* Create a new Pull Request
|
86
|
+
|
87
|
+
## License
|
88
|
+
|
89
|
+
The gem is available as open source under the terms of the [MIT License][license].
|
90
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
Bundler.require(:benchmarks)
|
2
|
+
|
3
|
+
require "dry-initializer"
|
4
|
+
class WithoutDefaults
|
5
|
+
extend Dry::Initializer
|
6
|
+
|
7
|
+
param :foo
|
8
|
+
param :bar
|
9
|
+
param :baz
|
10
|
+
end
|
11
|
+
|
12
|
+
class WithOneDefault
|
13
|
+
extend Dry::Initializer
|
14
|
+
|
15
|
+
param :foo
|
16
|
+
param :bar
|
17
|
+
param :baz, default: proc { "BAZ" }
|
18
|
+
end
|
19
|
+
|
20
|
+
class WithTwoDefaults
|
21
|
+
extend Dry::Initializer
|
22
|
+
|
23
|
+
param :foo
|
24
|
+
param :bar, default: proc { "BAR" }
|
25
|
+
param :baz, default: proc { "BAZ" }
|
26
|
+
end
|
27
|
+
|
28
|
+
class WithThreeDefaults
|
29
|
+
extend Dry::Initializer
|
30
|
+
|
31
|
+
param :foo, default: proc { "FOO" }
|
32
|
+
param :bar, default: proc { "BAR" }
|
33
|
+
param :baz, default: proc { "BAZ" }
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "Benchmark for various options"
|
37
|
+
|
38
|
+
Benchmark.ips do |x|
|
39
|
+
x.config time: 15, warmup: 10
|
40
|
+
|
41
|
+
x.report("without defaults") do
|
42
|
+
WithoutDefaults.new "FOO", "BAR", "BAZ"
|
43
|
+
end
|
44
|
+
|
45
|
+
x.report("with 0 of 1 default used") do
|
46
|
+
WithOneDefault.new "FOO", "BAR", "BAZ"
|
47
|
+
end
|
48
|
+
|
49
|
+
x.report("with 1 of 1 default used") do
|
50
|
+
WithOneDefault.new "FOO", "BAR"
|
51
|
+
end
|
52
|
+
|
53
|
+
x.report("with 0 of 2 defaults used") do
|
54
|
+
WithTwoDefaults.new "FOO", "BAR", "BAZ"
|
55
|
+
end
|
56
|
+
|
57
|
+
x.report("with 1 of 2 defaults used") do
|
58
|
+
WithTwoDefaults.new "FOO", "BAR"
|
59
|
+
end
|
60
|
+
|
61
|
+
x.report("with 2 of 2 defaults used") do
|
62
|
+
WithTwoDefaults.new "FOO"
|
63
|
+
end
|
64
|
+
|
65
|
+
x.report("with 0 of 3 defaults used") do
|
66
|
+
WithThreeDefaults.new "FOO", "BAR", "BAZ"
|
67
|
+
end
|
68
|
+
|
69
|
+
x.report("with 1 of 3 defaults used") do
|
70
|
+
WithThreeDefaults.new "FOO", "BAR"
|
71
|
+
end
|
72
|
+
|
73
|
+
x.report("with 2 of 3 defaults used") do
|
74
|
+
WithThreeDefaults.new "FOO"
|
75
|
+
end
|
76
|
+
|
77
|
+
x.report("with 3 of 3 defaults used") do
|
78
|
+
WithThreeDefaults.new
|
79
|
+
end
|
80
|
+
|
81
|
+
x.compare!
|
82
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
Bundler.require(:benchmarks)
|
2
|
+
|
3
|
+
require "dry-initializer"
|
4
|
+
class DryTest
|
5
|
+
extend Dry::Initializer[undefined: false]
|
6
|
+
|
7
|
+
option :foo
|
8
|
+
option :bar
|
9
|
+
end
|
10
|
+
|
11
|
+
class DryTestUndefined
|
12
|
+
extend Dry::Initializer
|
13
|
+
|
14
|
+
option :foo
|
15
|
+
option :bar
|
16
|
+
end
|
17
|
+
|
18
|
+
class PlainRubyTest
|
19
|
+
attr_reader :foo, :bar
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
@foo = options[:foo]
|
23
|
+
@bar = options[:bar]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require "anima"
|
28
|
+
class AnimaTest
|
29
|
+
include Anima.new(:foo, :bar)
|
30
|
+
end
|
31
|
+
|
32
|
+
require "kwattr"
|
33
|
+
class KwattrTest
|
34
|
+
kwattr :foo, :bar
|
35
|
+
end
|
36
|
+
|
37
|
+
puts "Benchmark for instantiation with plain options"
|
38
|
+
|
39
|
+
Benchmark.ips do |x|
|
40
|
+
x.config time: 15, warmup: 10
|
41
|
+
|
42
|
+
x.report("plain Ruby") do
|
43
|
+
PlainRubyTest.new foo: "FOO", bar: "BAR"
|
44
|
+
end
|
45
|
+
|
46
|
+
x.report("dry-initializer") do
|
47
|
+
DryTest.new foo: "FOO", bar: "BAR"
|
48
|
+
end
|
49
|
+
|
50
|
+
x.report("dry-initializer (with UNDEFINED)") do
|
51
|
+
DryTestUndefined.new foo: "FOO", bar: "BAR"
|
52
|
+
end
|
53
|
+
|
54
|
+
x.report("anima") do
|
55
|
+
AnimaTest.new foo: "FOO", bar: "BAR"
|
56
|
+
end
|
57
|
+
|
58
|
+
x.report("kwattr") do
|
59
|
+
KwattrTest.new foo: "FOO", bar: "BAR"
|
60
|
+
end
|
61
|
+
|
62
|
+
x.compare!
|
63
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
Bundler.require(:benchmarks)
|
2
|
+
|
3
|
+
require "dry-initializer"
|
4
|
+
class DryTest
|
5
|
+
extend Dry::Initializer[undefined: false]
|
6
|
+
|
7
|
+
param :foo
|
8
|
+
param :bar
|
9
|
+
end
|
10
|
+
|
11
|
+
class DryTestUndefined
|
12
|
+
extend Dry::Initializer
|
13
|
+
|
14
|
+
param :foo
|
15
|
+
param :bar
|
16
|
+
end
|
17
|
+
|
18
|
+
class PlainRubyTest
|
19
|
+
attr_reader :foo, :bar
|
20
|
+
|
21
|
+
def initialize(foo, bar)
|
22
|
+
@foo = foo
|
23
|
+
@bar = bar
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
StructTest = Struct.new(:foo, :bar)
|
28
|
+
|
29
|
+
require "concord"
|
30
|
+
class ConcordTest
|
31
|
+
include Concord.new(:foo, :bar)
|
32
|
+
end
|
33
|
+
|
34
|
+
require "values"
|
35
|
+
ValueTest = Value.new(:foo, :bar)
|
36
|
+
|
37
|
+
require "value_struct"
|
38
|
+
ValueStructTest = ValueStruct.new(:foo, :bar)
|
39
|
+
|
40
|
+
require "attr_extras"
|
41
|
+
class AttrExtrasText
|
42
|
+
attr_initialize :foo, :bar
|
43
|
+
attr_reader :foo, :bar
|
44
|
+
end
|
45
|
+
|
46
|
+
puts "Benchmark for instantiation with plain params"
|
47
|
+
|
48
|
+
Benchmark.ips do |x|
|
49
|
+
x.config time: 15, warmup: 10
|
50
|
+
|
51
|
+
x.report("plain Ruby") do
|
52
|
+
PlainRubyTest.new "FOO", "BAR"
|
53
|
+
end
|
54
|
+
|
55
|
+
x.report("Core Struct") do
|
56
|
+
StructTest.new "FOO", "BAR"
|
57
|
+
end
|
58
|
+
|
59
|
+
x.report("values") do
|
60
|
+
ValueTest.new "FOO", "BAR"
|
61
|
+
end
|
62
|
+
|
63
|
+
x.report("value_struct") do
|
64
|
+
ValueStructTest.new "FOO", "BAR"
|
65
|
+
end
|
66
|
+
|
67
|
+
x.report("dry-initializer") do
|
68
|
+
DryTest.new "FOO", "BAR"
|
69
|
+
end
|
70
|
+
|
71
|
+
x.report("dry-initializer (with UNDEFINED)") do
|
72
|
+
DryTestUndefined.new "FOO", "BAR"
|
73
|
+
end
|
74
|
+
|
75
|
+
x.report("concord") do
|
76
|
+
ConcordTest.new "FOO", "BAR"
|
77
|
+
end
|
78
|
+
|
79
|
+
x.report("attr_extras") do
|
80
|
+
AttrExtrasText.new "FOO", "BAR"
|
81
|
+
end
|
82
|
+
|
83
|
+
x.compare!
|
84
|
+
end
|
@@ -0,0 +1,71 @@
|
|
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)
|
8
|
+
option :bar, proc(&:to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
class DryTestUndefined
|
12
|
+
extend Dry::Initializer
|
13
|
+
|
14
|
+
option :foo, proc(&:to_s)
|
15
|
+
option :bar, proc(&:to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
class PlainRubyTest
|
19
|
+
attr_reader :foo, :bar
|
20
|
+
|
21
|
+
def initialize(options)
|
22
|
+
@foo = options[:foo].to_s
|
23
|
+
@bar = options[:bar].to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require "virtus"
|
28
|
+
class VirtusTest
|
29
|
+
include Virtus.model
|
30
|
+
|
31
|
+
attribute :foo, String
|
32
|
+
attribute :bar, String
|
33
|
+
end
|
34
|
+
|
35
|
+
require "fast_attributes"
|
36
|
+
class FastAttributesTest
|
37
|
+
extend FastAttributes
|
38
|
+
|
39
|
+
define_attributes initialize: true do
|
40
|
+
attribute :foo, String
|
41
|
+
attribute :bar, String
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
puts "Benchmark for instantiation with coercion"
|
46
|
+
|
47
|
+
Benchmark.ips do |x|
|
48
|
+
x.config time: 15, warmup: 10
|
49
|
+
|
50
|
+
x.report("plain Ruby") do
|
51
|
+
PlainRubyTest.new foo: "FOO", bar: "BAR"
|
52
|
+
end
|
53
|
+
|
54
|
+
x.report("dry-initializer") do
|
55
|
+
DryTest.new foo: "FOO", bar: "BAR"
|
56
|
+
end
|
57
|
+
|
58
|
+
x.report("dry-initializer (with UNDEFINED)") do
|
59
|
+
DryTestUndefined.new foo: "FOO", bar: "BAR"
|
60
|
+
end
|
61
|
+
|
62
|
+
x.report("virtus") do
|
63
|
+
VirtusTest.new foo: "FOO", bar: "BAR"
|
64
|
+
end
|
65
|
+
|
66
|
+
x.report("fast_attributes") do
|
67
|
+
FastAttributesTest.new foo: "FOO", bar: "BAR"
|
68
|
+
end
|
69
|
+
|
70
|
+
x.compare!
|
71
|
+
end
|