dry-initializer 3.0.4 → 3.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/LICENSE +1 -1
- data/README.md +4 -3
- data/dry-initializer.gemspec +15 -13
- data/lib/dry/initializer/builders/attribute.rb +92 -82
- data/lib/dry/initializer/builders/initializer.rb +56 -54
- data/lib/dry/initializer/builders/reader.rb +55 -49
- data/lib/dry/initializer/builders/signature.rb +29 -23
- data/lib/dry/initializer/builders.rb +9 -5
- data/lib/dry/initializer/config.rb +160 -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 +24 -17
- data/lib/dry/initializer/dispatchers.rb +48 -43
- data/lib/dry/initializer/dsl.rb +42 -34
- data/lib/dry/initializer/errors.rb +22 -0
- 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 +3 -1
- data/lib/dry/initializer.rb +12 -9
- data/lib/dry-initializer.rb +3 -1
- data/lib/tasks/benchmark.rake +15 -13
- data/lib/tasks/profile.rake +20 -16
- metadata +5 -4
data/lib/dry/initializer/dsl.rb
CHANGED
@@ -1,43 +1,51 @@
|
|
1
|
-
|
2
|
-
# Module-level DSL
|
3
|
-
module DSL
|
4
|
-
# Setting for null (undefined value)
|
5
|
-
# @return [nil, Dry::Initializer::UNDEFINED]
|
6
|
-
attr_reader :null
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
3
|
+
module Dry
|
4
|
+
module Initializer
|
5
|
+
# Module-level DSL
|
6
|
+
module DSL
|
7
|
+
# Setting for null (undefined value)
|
8
|
+
# @return [nil, Dry::Initializer::UNDEFINED]
|
9
|
+
attr_reader :null
|
10
|
+
|
11
|
+
# Returns a version of the module with custom settings
|
12
|
+
# @option settings [Boolean] :undefined
|
13
|
+
# If unassigned params and options should be treated different from nil
|
14
|
+
# @return [Dry::Initializer]
|
15
|
+
def [](undefined: true, **)
|
16
|
+
null = undefined == false ? nil : UNDEFINED
|
17
|
+
Module.new.tap do |mod|
|
18
|
+
mod.extend DSL
|
19
|
+
mod.include self
|
20
|
+
mod.send(:instance_variable_set, :@null, null)
|
21
|
+
end
|
18
22
|
end
|
19
|
-
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
# Returns mixin module to be included to target class by hand
|
25
|
+
# @return [Module]
|
26
|
+
# @yield proc defining params and options
|
27
|
+
def define(procedure = nil, &block)
|
28
|
+
config = Config.new(null: null)
|
29
|
+
config.instance_exec(&(procedure || block))
|
30
|
+
config.mixin.include Mixin::Root
|
31
|
+
config.mixin
|
32
|
+
end
|
30
33
|
|
31
|
-
|
34
|
+
private
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
def extended(klass)
|
37
|
+
config = Config.new(klass, null: null)
|
38
|
+
klass.send :instance_variable_set, :@dry_initializer, config
|
39
|
+
klass.include Mixin::Root
|
40
|
+
end
|
38
41
|
|
39
|
-
|
40
|
-
|
42
|
+
class << self
|
43
|
+
private
|
44
|
+
|
45
|
+
def extended(mod)
|
46
|
+
mod.instance_variable_set :@null, UNDEFINED
|
47
|
+
end
|
48
|
+
end
|
41
49
|
end
|
42
50
|
end
|
43
51
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Initializer
|
5
|
+
class CoercionError < ::StandardError
|
6
|
+
def initialize(constraint_error, field)
|
7
|
+
@constraint_error = constraint_error
|
8
|
+
@field = field
|
9
|
+
super(message)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Ensure that the field name is in the error message
|
13
|
+
def message
|
14
|
+
if @constraint_error.message =~ /#{@field}/
|
15
|
+
@constraint_error.message
|
16
|
+
else
|
17
|
+
"#{@constraint_error.message} for field :#{@field}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,19 +1,25 @@
|
|
1
|
-
|
2
|
-
# @private
|
3
|
-
module Local
|
4
|
-
attr_reader :klass
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module Dry
|
4
|
+
module Initializer
|
5
|
+
module Mixin
|
6
|
+
# @private
|
7
|
+
module Local
|
8
|
+
attr_reader :klass
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"Dry::Initializer::Mixin::Local[#{klass}]"
|
12
|
+
end
|
13
|
+
alias_method :to_s, :inspect
|
14
|
+
alias_method :to_str, :inspect
|
11
15
|
|
12
|
-
|
16
|
+
private
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
18
|
+
def included(klass)
|
19
|
+
@klass = klass
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
@@ -1,11 +1,16 @@
|
|
1
|
-
|
2
|
-
# @private
|
3
|
-
module Root
|
4
|
-
private
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
3
|
+
module Dry
|
4
|
+
module Initializer
|
5
|
+
module Mixin
|
6
|
+
# @private
|
7
|
+
module Root
|
8
|
+
private
|
9
|
+
|
10
|
+
def initialize(...)
|
11
|
+
__dry_initializer_initialize__(...)
|
12
|
+
end
|
13
|
+
end
|
8
14
|
end
|
9
|
-
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
10
15
|
end
|
11
16
|
end
|
@@ -1,15 +1,20 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Initializer
|
5
|
+
# @private
|
6
|
+
module Mixin
|
7
|
+
extend DSL # @deprecated
|
8
|
+
include Dry::Initializer # @deprecated
|
9
|
+
# @deprecated
|
10
|
+
def self.extended(klass)
|
11
|
+
warn "[DEPRECATED] Use Dry::Initializer instead of its alias" \
|
12
|
+
" Dry::Initializer::Mixin. The later will be removed in v2.1.0"
|
13
|
+
super
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
require_relative "mixin/root"
|
17
|
+
require_relative "mixin/local"
|
18
|
+
end
|
14
19
|
end
|
15
20
|
end
|
@@ -1,39 +1,44 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# The nested structure that takes nested hashes with indifferent access
|
3
4
|
#
|
4
|
-
|
5
|
-
|
5
|
+
module Dry
|
6
|
+
module Initializer
|
7
|
+
class Struct
|
8
|
+
extend ::Dry::Initializer
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
class << self
|
11
|
+
undef_method :param
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def new(options)
|
14
|
+
super(**Hash(options).each_with_object({}) { |(k, v), h| h[k.to_sym] = v })
|
15
|
+
end
|
16
|
+
alias_method :call, :new
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
#
|
20
|
+
# Represents event data as a nested hash with deeply stringified keys
|
21
|
+
# @return [Hash<String, ...>]
|
22
|
+
#
|
23
|
+
def to_h
|
24
|
+
self
|
25
|
+
.class
|
26
|
+
.dry_initializer
|
27
|
+
.attributes(self)
|
28
|
+
.each_with_object({}) { |(k, v), h| h[k.to_s] = __hashify(v) }
|
29
|
+
end
|
27
30
|
|
28
|
-
|
31
|
+
private
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
def __hashify(value)
|
34
|
+
case value
|
35
|
+
when Hash
|
36
|
+
value.each_with_object({}) { |(k, v), obj| obj[k.to_s] = __hashify(v) }
|
37
|
+
when Array then value.map { |v| __hashify(v) }
|
38
|
+
when Dry::Initializer::Struct then value.to_h
|
39
|
+
else value
|
40
|
+
end
|
41
|
+
end
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
data/lib/dry/initializer.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
2
4
|
|
3
5
|
# Namespace for gems in a dry-rb community
|
4
6
|
module Dry
|
@@ -6,13 +8,14 @@ module Dry
|
|
6
8
|
# DSL for declaring params and options of class initializers
|
7
9
|
#
|
8
10
|
module Initializer
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
15
|
-
require_relative
|
11
|
+
require_relative "initializer/undefined"
|
12
|
+
require_relative "initializer/dsl"
|
13
|
+
require_relative "initializer/definition"
|
14
|
+
require_relative "initializer/builders"
|
15
|
+
require_relative "initializer/config"
|
16
|
+
require_relative "initializer/mixin"
|
17
|
+
require_relative "initializer/dispatchers"
|
18
|
+
require_relative "initializer/errors"
|
16
19
|
|
17
20
|
# Adds methods [.[]] and [.define]
|
18
21
|
extend DSL
|
@@ -56,6 +59,6 @@ module Dry
|
|
56
59
|
dry_initializer.children << config
|
57
60
|
end
|
58
61
|
|
59
|
-
require_relative
|
62
|
+
require_relative "initializer/struct"
|
60
63
|
end
|
61
64
|
end
|
data/lib/dry-initializer.rb
CHANGED
data/lib/tasks/benchmark.rake
CHANGED
@@ -1,36 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
namespace :benchmark do
|
2
|
-
desc
|
4
|
+
desc "Runs benchmarks for plain params"
|
3
5
|
task :plain_params do
|
4
|
-
system
|
6
|
+
system "ruby benchmarks/plain_params.rb"
|
5
7
|
end
|
6
8
|
|
7
|
-
desc
|
9
|
+
desc "Runs benchmarks for plain options"
|
8
10
|
task :plain_options do
|
9
|
-
system
|
11
|
+
system "ruby benchmarks/plain_options.rb"
|
10
12
|
end
|
11
13
|
|
12
|
-
desc
|
14
|
+
desc "Runs benchmarks for value coercion"
|
13
15
|
task :with_coercion do
|
14
|
-
system
|
16
|
+
system "ruby benchmarks/with_coercion.rb"
|
15
17
|
end
|
16
18
|
|
17
|
-
desc
|
19
|
+
desc "Runs benchmarks with defaults"
|
18
20
|
task :with_defaults do
|
19
|
-
system
|
21
|
+
system "ruby benchmarks/with_defaults.rb"
|
20
22
|
end
|
21
23
|
|
22
|
-
desc
|
24
|
+
desc "Runs benchmarks with defaults and coercion"
|
23
25
|
task :with_defaults_and_coercion do
|
24
|
-
system
|
26
|
+
system "ruby benchmarks/with_defaults_and_coercion.rb"
|
25
27
|
end
|
26
28
|
|
27
|
-
desc
|
29
|
+
desc "Runs benchmarks for several defaults"
|
28
30
|
task :compare_several_defaults do
|
29
|
-
system
|
31
|
+
system "ruby benchmarks/with_several_defaults.rb"
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
desc
|
35
|
+
desc "Runs all benchmarks"
|
34
36
|
task benchmark: %i[
|
35
37
|
benchmark:plain_params
|
36
38
|
benchmark:plain_options
|
data/lib/tasks/profile.rake
CHANGED
@@ -1,32 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop: disable Lint/ConstantDefinitionInBlock
|
1
4
|
namespace :profile do
|
2
5
|
def profile(name, execution, &definition)
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
+
require "dry-initializer"
|
7
|
+
require "ruby-prof"
|
8
|
+
require "fileutils"
|
6
9
|
|
7
10
|
definition.call
|
8
11
|
result = RubyProf.profile do
|
9
12
|
1_000.times { execution.call }
|
10
13
|
end
|
11
14
|
|
12
|
-
FileUtils.mkdir_p
|
15
|
+
FileUtils.mkdir_p "./tmp"
|
13
16
|
|
14
17
|
FileUtils.touch "./tmp/#{name}.dot"
|
15
|
-
File.open("./tmp/#{name}.dot",
|
18
|
+
File.open("./tmp/#{name}.dot", "w+") do |output|
|
16
19
|
RubyProf::DotPrinter.new(result).print(output, min_percent: 0)
|
17
20
|
end
|
18
21
|
|
19
22
|
FileUtils.touch "./tmp/#{name}.html"
|
20
|
-
File.open("./tmp/#{name}.html",
|
23
|
+
File.open("./tmp/#{name}.html", "w+") do |output|
|
21
24
|
RubyProf::CallStackPrinter.new(result).print(output, min_percent: 0)
|
22
25
|
end
|
23
26
|
|
24
27
|
system "dot -Tpng ./tmp/#{name}.dot > ./tmp/#{name}.png"
|
25
28
|
end
|
26
29
|
|
27
|
-
desc
|
30
|
+
desc "Profiles initialization with required param and option"
|
28
31
|
task :required do
|
29
|
-
profile(
|
32
|
+
profile("required", -> { User.new :Andy, email: "andy@example.com" }) do
|
30
33
|
class User
|
31
34
|
extend Dry::Initializer
|
32
35
|
param :name
|
@@ -35,20 +38,20 @@ namespace :profile do
|
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
38
|
-
desc
|
41
|
+
desc "Profiles initialization with default param and option"
|
39
42
|
task :defaults do
|
40
|
-
profile(
|
43
|
+
profile("defaults", -> { User.new }) do
|
41
44
|
class User
|
42
45
|
extend Dry::Initializer
|
43
46
|
param :name, default: -> { :Andy }
|
44
|
-
option :email, default: -> {
|
47
|
+
option :email, default: -> { "andy@example.com" }
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
desc
|
52
|
+
desc "Profiles initialization with coerced param and option"
|
50
53
|
task :coercion do
|
51
|
-
profile(
|
54
|
+
profile("coercion", -> { User.new :Andy, email: :"andy@example.com" }) do
|
52
55
|
class User
|
53
56
|
extend Dry::Initializer
|
54
57
|
param :name, proc(&:to_s)
|
@@ -57,9 +60,9 @@ namespace :profile do
|
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
desc
|
63
|
+
desc "Profiles initialization with coerced defaults of param and option"
|
61
64
|
task :default_coercion do
|
62
|
-
profile(
|
65
|
+
profile("default_coercion", -> { User.new }) do
|
63
66
|
class User
|
64
67
|
extend Dry::Initializer
|
65
68
|
param :name, proc(&:to_s), default: -> { :Andy }
|
@@ -69,10 +72,11 @@ namespace :profile do
|
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
desc
|
75
|
+
desc "Makes all profiling at once"
|
73
76
|
task profile: %i[
|
74
77
|
profile:required
|
75
78
|
profile:defaults
|
76
79
|
profile:coercion
|
77
80
|
profile:default_coercion
|
78
81
|
]
|
82
|
+
# rubocop: enable Lint/ConstantDefinitionInBlock
|
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: 3.0
|
4
|
+
version: 3.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:
|
12
|
+
date: 2022-01-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- lib/dry/initializer/dispatchers/unwrap_type.rb
|
72
72
|
- lib/dry/initializer/dispatchers/wrap_type.rb
|
73
73
|
- lib/dry/initializer/dsl.rb
|
74
|
+
- lib/dry/initializer/errors.rb
|
74
75
|
- lib/dry/initializer/mixin.rb
|
75
76
|
- lib/dry/initializer/mixin/local.rb
|
76
77
|
- lib/dry/initializer/mixin/root.rb
|
@@ -95,14 +96,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
96
|
requirements:
|
96
97
|
- - ">="
|
97
98
|
- !ruby/object:Gem::Version
|
98
|
-
version: 2.
|
99
|
+
version: 2.7.0
|
99
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
101
|
requirements:
|
101
102
|
- - ">="
|
102
103
|
- !ruby/object:Gem::Version
|
103
104
|
version: '0'
|
104
105
|
requirements: []
|
105
|
-
rubygems_version: 3.
|
106
|
+
rubygems_version: 3.1.6
|
106
107
|
signing_key:
|
107
108
|
specification_version: 4
|
108
109
|
summary: DSL for declaring params and options of the initializer
|