dry-initializer 0.0.1
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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +15 -0
- data/.gitignore +9 -0
- data/.rspec +3 -0
- data/.rubocop.yml +91 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +25 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +444 -0
- data/Rakefile +47 -0
- data/benchmarks/options.rb +54 -0
- data/benchmarks/params.rb +73 -0
- data/benchmarks/params_vs_options.rb +35 -0
- data/benchmarks/several_defaults.rb +82 -0
- data/benchmarks/with_defaults.rb +55 -0
- data/benchmarks/with_types.rb +62 -0
- data/benchmarks/with_types_and_defaults.rb +48 -0
- data/benchmarks/without_options.rb +52 -0
- data/dry-initializer.gemspec +19 -0
- data/lib/dry-initializer.rb +1 -0
- data/lib/dry/initializer.rb +53 -0
- data/lib/dry/initializer/argument.rb +96 -0
- data/lib/dry/initializer/arguments.rb +85 -0
- data/lib/dry/initializer/builder.rb +33 -0
- data/lib/dry/initializer/errors.rb +13 -0
- data/lib/dry/initializer/errors/existing_argument_error.rb +5 -0
- data/lib/dry/initializer/errors/invalid_default_value_error.rb +6 -0
- data/lib/dry/initializer/errors/invalid_type_error.rb +6 -0
- data/lib/dry/initializer/errors/key_error.rb +5 -0
- data/lib/dry/initializer/errors/missed_default_value_error.rb +5 -0
- data/lib/dry/initializer/errors/type_error.rb +5 -0
- data/spec/dry/base_spec.rb +21 -0
- data/spec/dry/default_nil_spec.rb +17 -0
- data/spec/dry/default_values_spec.rb +39 -0
- data/spec/dry/dry_type_spec.rb +25 -0
- data/spec/dry/invalid_default_spec.rb +13 -0
- data/spec/dry/invalid_type_spec.rb +13 -0
- data/spec/dry/missed_default_spec.rb +14 -0
- data/spec/dry/poro_type_spec.rb +33 -0
- data/spec/dry/proc_type_spec.rb +25 -0
- data/spec/dry/reader_spec.rb +22 -0
- data/spec/dry/repetitive_definitions_spec.rb +49 -0
- data/spec/dry/subclassing_spec.rb +24 -0
- data/spec/spec_helper.rb +15 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9c8a4ecc08b8c494713d17b0af1191257c6eae96
|
4
|
+
data.tar.gz: 5019f46f22eb9c37904b42f67620d2f5d2ee747f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 278434f8949064eb547f6c481e94bff71080eda6c6ff95586cc647259ba842301dc850022c6fd88af80ac37985394829a9c93788917b7755ef6011a0c595c1bb
|
7
|
+
data.tar.gz: 6afa297f5e3a180d79366fb14750b787a7dc9b920118da9a0f806f37f1c3dcec1d0d6e14767b23dae284ff962099ea5aba0bd486607352a8825f1298f59eb204
|
data/.codeclimate.yml
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
---
|
2
|
+
AllCops:
|
3
|
+
DisplayCopNames: true
|
4
|
+
DisplayStyleGuide: true
|
5
|
+
StyleGuideCopsOnly: true
|
6
|
+
TargetRubyVersion: 2.2
|
7
|
+
|
8
|
+
Lint/HandleExceptions:
|
9
|
+
Exclude:
|
10
|
+
- '**/*_spec.rb'
|
11
|
+
|
12
|
+
Lint/RescueException:
|
13
|
+
Exclude:
|
14
|
+
- '**/*_spec.rb'
|
15
|
+
|
16
|
+
Metrics/LineLength:
|
17
|
+
Max: 80
|
18
|
+
Exclude:
|
19
|
+
- 'spec/**/*.rb'
|
20
|
+
|
21
|
+
Style/AccessorMethodName:
|
22
|
+
Exclude:
|
23
|
+
- '**/*_spec.rb'
|
24
|
+
|
25
|
+
Style/Alias:
|
26
|
+
EnforcedStyle: prefer_alias_method
|
27
|
+
|
28
|
+
Style/AsciiComments:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/CaseEquality:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Style/ClassAndModuleChildren:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Style/Documentation:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Style/DoubleNegation:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/EmptyLinesAroundClassBody:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Style/EmptyLinesAroundModuleBody:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Style/EmptyLineBetweenDefs:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
Style/FileName:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Style/ModuleFunction:
|
56
|
+
Enabled: false
|
57
|
+
|
58
|
+
Style/RaiseArgs:
|
59
|
+
EnforcedStyle: compact
|
60
|
+
|
61
|
+
Style/Semicolon:
|
62
|
+
Exclude:
|
63
|
+
- '**/*_spec.rb'
|
64
|
+
|
65
|
+
Style/SignalException:
|
66
|
+
EnforcedStyle: semantic
|
67
|
+
|
68
|
+
Style/SingleLineBlockParams:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
Style/SingleLineMethods:
|
72
|
+
Exclude:
|
73
|
+
- '**/*_spec.rb'
|
74
|
+
|
75
|
+
Style/SpaceBeforeFirstArg:
|
76
|
+
Enabled: false
|
77
|
+
|
78
|
+
Style/SpecialGlobalVars:
|
79
|
+
Exclude:
|
80
|
+
- '**/Gemfile'
|
81
|
+
- '**/*.gemspec'
|
82
|
+
|
83
|
+
Style/StringLiterals:
|
84
|
+
EnforcedStyle: double_quotes
|
85
|
+
|
86
|
+
Style/StringLiteralsInInterpolation:
|
87
|
+
EnforcedStyle: double_quotes
|
88
|
+
|
89
|
+
Style/TrivialAccessors:
|
90
|
+
Exclude:
|
91
|
+
- '**/*_spec.rb'
|
data/.travis.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
language: ruby
|
3
|
+
before_install: gem install bundler -v 1.11.2
|
4
|
+
cache: bundler
|
5
|
+
script: bundle exec rspec
|
6
|
+
rvm:
|
7
|
+
- '2.2'
|
8
|
+
- '2.3.0'
|
9
|
+
- rbx-2
|
10
|
+
- ruby-head
|
11
|
+
# - jruby-9
|
12
|
+
# - jruby-head
|
13
|
+
matrix:
|
14
|
+
allow_failures:
|
15
|
+
- rvm: ruby-head
|
16
|
+
# - rvm: jruby-head
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem"s dependencies in dry-initializer.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem "dry-types", git: "https://github.com/dryrb/dry-types", branch: "master"
|
7
|
+
|
8
|
+
group :benchmarks do
|
9
|
+
gem "benchmark-ips", "~> 2.5"
|
10
|
+
|
11
|
+
gem "active_attr"
|
12
|
+
gem "anima"
|
13
|
+
gem "attr_extras"
|
14
|
+
gem "concord"
|
15
|
+
gem "fast_attributes"
|
16
|
+
gem "kwattr"
|
17
|
+
gem "value_struct"
|
18
|
+
gem "values"
|
19
|
+
gem "virtus"
|
20
|
+
end
|
21
|
+
|
22
|
+
group :development, :test do
|
23
|
+
gem "pry", platform: :mri
|
24
|
+
gem "pry-byebug", platform: :mri
|
25
|
+
end
|
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Andrew Kozin (aka nepalez)
|
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,444 @@
|
|
1
|
+
# dry-initializer [](https://gitter.im/dry-rb/chat)
|
2
|
+
|
3
|
+
[][gem]
|
4
|
+
[][travis]
|
5
|
+
[][gemnasium]
|
6
|
+
[][codeclimate]
|
7
|
+
[][coveralls]
|
8
|
+
[][inchpages]
|
9
|
+
|
10
|
+
[gem]: https://rubygems.org/gems/dry-initializer
|
11
|
+
[travis]: https://travis-ci.org/dry-rb/dry-initializer
|
12
|
+
[gemnasium]: https://gemnasium.com/dry-rb/dry-initializer
|
13
|
+
[codeclimate]: https://codeclimate.com/github/dry-rb/dry-initializer
|
14
|
+
[coveralls]: https://coveralls.io/r/dry-rb/dry-initializer
|
15
|
+
[inchpages]: http://inch-ci.org/github/dry-rb/dry-initializer
|
16
|
+
|
17
|
+
DSL for building class initializer with params and options.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'dry-initializer'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
```shell
|
30
|
+
$ bundle
|
31
|
+
```
|
32
|
+
|
33
|
+
Or install it yourself as:
|
34
|
+
|
35
|
+
```shell
|
36
|
+
$ gem install dry-initializer
|
37
|
+
```
|
38
|
+
|
39
|
+
## Synopsis
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'dry-initializer'
|
43
|
+
|
44
|
+
class User
|
45
|
+
extend Dry::Initializer
|
46
|
+
|
47
|
+
# Params of the initializer along with corresponding readers
|
48
|
+
param :name, type: String
|
49
|
+
param :role, default: proc { 'customer' }
|
50
|
+
# Options of the initializer along with corresponding readers
|
51
|
+
option :admin, default: proc { false }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Defines the initializer with params and options
|
55
|
+
user = User.new 'Vladimir', 'admin', admin: true
|
56
|
+
|
57
|
+
# Defines readers for single attributes
|
58
|
+
user.name # => 'Vladimir'
|
59
|
+
user.role # => 'admin'
|
60
|
+
user.admin # => true
|
61
|
+
```
|
62
|
+
|
63
|
+
This is pretty the same as:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class User
|
67
|
+
attr_reader :name, :type, :admin
|
68
|
+
|
69
|
+
def initializer(name, type = 'customer', admin: false)
|
70
|
+
@name = name
|
71
|
+
@type = type
|
72
|
+
@admin = admin
|
73
|
+
|
74
|
+
fail TypeError unless String === @name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
### Params and Options
|
80
|
+
|
81
|
+
Use `param` to define plain argument:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class User
|
85
|
+
extend Dry::Initializer
|
86
|
+
|
87
|
+
param :name
|
88
|
+
param :email
|
89
|
+
end
|
90
|
+
|
91
|
+
user = User.new 'Andrew', 'andrew@email.com'
|
92
|
+
user.name # => 'Andrew'
|
93
|
+
user.email # => 'andrew@email.com'
|
94
|
+
```
|
95
|
+
|
96
|
+
Use `option` to define named (hash) argument:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class User
|
100
|
+
extend Dry::Initializer
|
101
|
+
|
102
|
+
option :name
|
103
|
+
option :email
|
104
|
+
end
|
105
|
+
|
106
|
+
user = User.new email: 'andrew@email.com', name: 'Andrew'
|
107
|
+
user.name # => 'Andrew'
|
108
|
+
user.email # => 'andrew@email.com'
|
109
|
+
```
|
110
|
+
|
111
|
+
All names should be unique:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
class User
|
115
|
+
extend Dry::Initializer
|
116
|
+
|
117
|
+
param :name
|
118
|
+
option :name # => raises #<SyntaxError ...>
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
### Default Values
|
123
|
+
|
124
|
+
By default both params and options are mandatory. Use `:default` key to make them optional:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
class User
|
128
|
+
extend Dry::Initializer
|
129
|
+
|
130
|
+
param :name, default: proc { 'Unknown user' }
|
131
|
+
option :email, default: proc { 'unknown@example.com' }
|
132
|
+
end
|
133
|
+
|
134
|
+
user = User.new
|
135
|
+
user.name # => 'Unknown user'
|
136
|
+
user.email # => 'unknown@example.com'
|
137
|
+
|
138
|
+
user = User.new 'Vladimir', email: 'vladimir@example.com'
|
139
|
+
user.name # => 'Vladimir'
|
140
|
+
user.email # => 'vladimir@example.com'
|
141
|
+
```
|
142
|
+
|
143
|
+
Set `nil` as a default value explicitly:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
class User
|
147
|
+
extend Dry::Initializer
|
148
|
+
|
149
|
+
param :name
|
150
|
+
option :email, default: proc { nil }
|
151
|
+
end
|
152
|
+
|
153
|
+
user = User.new 'Andrew'
|
154
|
+
user.email # => nil
|
155
|
+
|
156
|
+
user = User.new
|
157
|
+
# => #<ArgumentError ...>
|
158
|
+
```
|
159
|
+
|
160
|
+
You **must** wrap default values into procs.
|
161
|
+
|
162
|
+
If you need to **assign** proc as a default value, wrap it to another one:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
class User
|
166
|
+
extend Dry::Initializer
|
167
|
+
|
168
|
+
param :name_proc, default: proc { proc { 'Unknown user' } }
|
169
|
+
end
|
170
|
+
|
171
|
+
user = User.new
|
172
|
+
user.name_proc.call # => 'Unknown user'
|
173
|
+
```
|
174
|
+
|
175
|
+
Proc will be executed in a scope of new instance. You can refer to other arguments:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
class User
|
179
|
+
extend Dry::Initializer
|
180
|
+
|
181
|
+
param :name
|
182
|
+
param :email, default: proc { "#{name.downcase}@example.com" }
|
183
|
+
end
|
184
|
+
|
185
|
+
user = User.new 'Andrew'
|
186
|
+
user.email # => 'andrew@example.com'
|
187
|
+
```
|
188
|
+
|
189
|
+
**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).
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
class User
|
193
|
+
extend Dry::Initializer
|
194
|
+
|
195
|
+
param :name, default: -> (obj) { 'Dude' }
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
[instance_eval]: http://ruby-doc.org/core-2.2.0/BasicObject.html#method-i-instance_eval
|
200
|
+
|
201
|
+
### Order of Declarations
|
202
|
+
|
203
|
+
You cannot define required parameter after optional ones. The following example raises `SyntaxError` exception:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
class User
|
207
|
+
extend Dry::Initializer
|
208
|
+
|
209
|
+
param :name, default: proc { 'Unknown name' }
|
210
|
+
param :email # => #<SyntaxError ...>
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
### Type Constraints
|
215
|
+
|
216
|
+
To set type constraint use `:type` key:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
class User
|
220
|
+
extend Dry::Initializer
|
221
|
+
|
222
|
+
param :name, type: String
|
223
|
+
end
|
224
|
+
|
225
|
+
user = User.new 'Andrew'
|
226
|
+
user.name # => 'Andrew'
|
227
|
+
|
228
|
+
user = User.new :andrew
|
229
|
+
# => #<TypeError ...>
|
230
|
+
```
|
231
|
+
|
232
|
+
You can use plain Ruby classes and modules as type constraint (see above), or use [dry-types][dry-types]:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
class User
|
236
|
+
extend Dry::Initializer
|
237
|
+
|
238
|
+
param :name, type: Dry::Types::Coercion::String
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
Or you can define custom constraint as a proc:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
class User
|
246
|
+
extend Dry::Initializer
|
247
|
+
|
248
|
+
param :name, type: proc { |v| raise TypeError if String === v }
|
249
|
+
end
|
250
|
+
|
251
|
+
user = User.new name: 'Andrew'
|
252
|
+
# => #<TypeError ...>
|
253
|
+
```
|
254
|
+
|
255
|
+
[dry-types]: https://github.com/dryrb/dry-types
|
256
|
+
|
257
|
+
### Reader
|
258
|
+
|
259
|
+
By default `attr_reader` is defined for every param and option.
|
260
|
+
|
261
|
+
To skip the reader, use `reader: false`:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
class User
|
265
|
+
extend Dry::Initializer
|
266
|
+
|
267
|
+
param :name
|
268
|
+
param :email, reader: false
|
269
|
+
end
|
270
|
+
|
271
|
+
user = User.new 'Luke', 'luke@example.com'
|
272
|
+
user.name # => 'Luke'
|
273
|
+
|
274
|
+
user.email # => #<NoMethodError ...>
|
275
|
+
user.instance_variable_get :@email # => 'luke@example.com'
|
276
|
+
```
|
277
|
+
|
278
|
+
No writers are defined. Define them using pure ruby `attr_writer` when necessary.
|
279
|
+
|
280
|
+
### Subclassing
|
281
|
+
|
282
|
+
Subclassing preserves all definitions being made inside a superclass:
|
283
|
+
|
284
|
+
```ruby
|
285
|
+
class User
|
286
|
+
extend Dry::Initializer
|
287
|
+
|
288
|
+
param :name
|
289
|
+
end
|
290
|
+
|
291
|
+
class Employee < User
|
292
|
+
param :position
|
293
|
+
end
|
294
|
+
|
295
|
+
employee = Employee.new('John', 'supercargo')
|
296
|
+
employee.name # => 'John'
|
297
|
+
employee.position # => 'supercargo'
|
298
|
+
```
|
299
|
+
|
300
|
+
## Benchmarks
|
301
|
+
|
302
|
+
### Various usages of Dry::Initializer
|
303
|
+
|
304
|
+
[At first][benchmark-options] we compared initializers for case of no-opts with those with default values and time constraints (for every single argument):
|
305
|
+
|
306
|
+
```
|
307
|
+
no opts: 1186020.0 i/s
|
308
|
+
with 2 types: 744825.4 i/s - 1.59x slower
|
309
|
+
with 2 defaults: 644170.0 i/s - 1.84x slower
|
310
|
+
with defaults and types: 534200.0 i/s - 2.22x slower
|
311
|
+
```
|
312
|
+
|
313
|
+
Defaults are slow. The more defaults you add the slower the instantiation. Let's [add details][benchmark_several_defaults]:
|
314
|
+
|
315
|
+
```
|
316
|
+
without defaults: 3412165.6 i/s
|
317
|
+
with 0 of 1 default used: 1816946.6 i/s - 1.88x slower
|
318
|
+
with 0 of 2 defaults used: 1620908.5 i/s - 2.11x slower
|
319
|
+
with 0 of 3 defaults used: 1493410.6 i/s - 2.28x slower
|
320
|
+
with 1 of 1 default used: 797438.8 i/s - 4.28x slower
|
321
|
+
with 1 of 2 defaults used: 754533.4 i/s - 4.52x slower
|
322
|
+
with 1 of 3 defaults used: 716828.9 i/s - 4.76x slower
|
323
|
+
with 2 of 2 defaults used: 622569.8 i/s - 5.48x slower
|
324
|
+
with 2 of 3 defaults used: 604062.1 i/s - 5.65x slower
|
325
|
+
with 3 of 3 defaults used: 533233.4 i/s - 6.40x slower
|
326
|
+
```
|
327
|
+
|
328
|
+
A single declaration of default values costs about 90% additional time. Its usage costs full 300%, and every next default adds 80% more.
|
329
|
+
|
330
|
+
Avoid defaults when possible!
|
331
|
+
|
332
|
+
### Comparison to Other Gems
|
333
|
+
|
334
|
+
We also compared initializers provided by gems from the [post 'Con-Struct Attibutes' by Jan Lelis][con-struct]:
|
335
|
+
|
336
|
+
* [active_attr][active_attr]
|
337
|
+
* [anima][anima]
|
338
|
+
* [attr_extras][attr_extras]
|
339
|
+
* [concord][concord]
|
340
|
+
* [fast_attr][fast_attr]
|
341
|
+
* [kwattr][kwattr]
|
342
|
+
* [value_struct][value_struct]
|
343
|
+
* [values][values]
|
344
|
+
* [virtus][virtus]
|
345
|
+
|
346
|
+
[con-struct]: http://idiosyncratic-ruby.com/18-con-struct-attributes.html
|
347
|
+
[active_attr]: https://github.com/cgriego/active_attr
|
348
|
+
[anima]: https://github.com/mbj/anima
|
349
|
+
[attr_extras]: https://github.com/barsoom/attr_extras
|
350
|
+
[concord]: https://github.com/mbj/concord
|
351
|
+
[fast_attr]: https://github.com/applift/fast_attributes
|
352
|
+
[kwattr]: https://github.com/etiennebarrie/kwattr
|
353
|
+
[value_struct]: https://github.com/janlelis/value_struct
|
354
|
+
[values]: https://github.com/tcrayford/values
|
355
|
+
[virtus]: https://github.com/solnic/virtus
|
356
|
+
|
357
|
+
Because the gems has their restrictions, in benchmarks we tested only comparable examples.
|
358
|
+
A corresponding code in plain Ruby was taken for comparison.
|
359
|
+
|
360
|
+
### Without Options
|
361
|
+
|
362
|
+
Results for [the examples][benchmark_without_options]
|
363
|
+
|
364
|
+
Benchmark for instantiation of plain arguments (params):
|
365
|
+
|
366
|
+
```
|
367
|
+
Core Struct: 4520294.5 i/s
|
368
|
+
value_struct: 4479181.2 i/s - same-ish: difference falls within error
|
369
|
+
plain Ruby: 4161762.2 i/s - 1.09x slower
|
370
|
+
dry-initializer: 3981426.3 i/s - 1.14x slower
|
371
|
+
concord: 1372696.9 i/s - 3.29x slower
|
372
|
+
values: 637396.9 i/s - 7.09x slower
|
373
|
+
attr_extras: 556342.9 i/s - 8.13x slower
|
374
|
+
```
|
375
|
+
|
376
|
+
Benchmark for instantiation of named arguments (options)
|
377
|
+
|
378
|
+
```
|
379
|
+
dry-initializer: 1020257.3 i/s
|
380
|
+
plain Ruby: 1009705.8 i/s - same-ish: difference falls within error
|
381
|
+
kwattr: 394574.0 i/s - 2.59x slower
|
382
|
+
anima: 377387.8 i/s - 2.70x slower
|
383
|
+
```
|
384
|
+
|
385
|
+
### With Default Values
|
386
|
+
|
387
|
+
Results for [the examples][benchmark_with_defaults]
|
388
|
+
|
389
|
+
```
|
390
|
+
plain Ruby: 3534979.5 i/s
|
391
|
+
dry-initializer: 657308.4 i/s - 5.38x slower
|
392
|
+
kwattr: 581691.0 i/s - 6.08x slower
|
393
|
+
active_attr: 309211.0 i/s - 11.43x slower
|
394
|
+
```
|
395
|
+
|
396
|
+
### With Type Constraints
|
397
|
+
|
398
|
+
Results for [the examples][benchmark_with_types]
|
399
|
+
|
400
|
+
```
|
401
|
+
plain Ruby: 951574.7 i/s
|
402
|
+
dry-initializer: 701676.7 i/s - 1.36x slower
|
403
|
+
fast_attributes: 562646.4 i/s - 1.69x slower
|
404
|
+
virtus: 143113.3 i/s - 6.65x slower
|
405
|
+
```
|
406
|
+
|
407
|
+
### With Default Values and Type Constraints
|
408
|
+
|
409
|
+
Results for [the examples][benchmark_with_types_and_defaults]
|
410
|
+
|
411
|
+
```
|
412
|
+
plain Ruby: 2887933.4 i/s
|
413
|
+
dry-initializer: 532508.0 i/s - 5.42x slower
|
414
|
+
virtus: 183347.1 i/s - 15.75x slower
|
415
|
+
```
|
416
|
+
|
417
|
+
To recap, `dry-initializer` is a fastest DSL for rubies 2.2+ except for cases when core `Struct` is sufficient.
|
418
|
+
|
419
|
+
[benchmark-options]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/options.rb
|
420
|
+
[benchmark_several_defaults]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/several_defaults.rb
|
421
|
+
[benchmark_without_options]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/without_options.rb
|
422
|
+
[benchmark_with_defaults]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/with_defaults.rb
|
423
|
+
[benchmark_with_types]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/with_types.rb
|
424
|
+
[benchmark_with_types_and_defaults]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/with_types_and_defaults.rb
|
425
|
+
[benchmark_params]: https://github.com/dryrb/dry-initializer/blob/master/benchmarks/params.rb
|
426
|
+
|
427
|
+
## Compatibility
|
428
|
+
|
429
|
+
Tested under rubies [compatible to MRI 2.2+](.travis.yml).
|
430
|
+
|
431
|
+
## Contributing
|
432
|
+
|
433
|
+
* Read the [STYLEGUIDE](config/metrics/STYLEGUIDE)
|
434
|
+
* [Fork the project](https://github.com/nepalez/query_builder)
|
435
|
+
* Create your feature branch (`git checkout -b my-new-feature`)
|
436
|
+
* Add tests for it
|
437
|
+
* Commit your changes (`git commit -am '[UPDATE] Add some feature'`)
|
438
|
+
* Push to the branch (`git push origin my-new-feature`)
|
439
|
+
* Create a new Pull Request
|
440
|
+
|
441
|
+
## License
|
442
|
+
|
443
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
444
|
+
|