dry-initializer 3.0.4 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE +1 -1
  4. data/README.md +4 -3
  5. data/dry-initializer.gemspec +15 -13
  6. data/lib/dry/initializer/builders/attribute.rb +92 -82
  7. data/lib/dry/initializer/builders/initializer.rb +56 -54
  8. data/lib/dry/initializer/builders/reader.rb +55 -49
  9. data/lib/dry/initializer/builders/signature.rb +29 -23
  10. data/lib/dry/initializer/builders.rb +9 -5
  11. data/lib/dry/initializer/config.rb +160 -158
  12. data/lib/dry/initializer/definition.rb +58 -54
  13. data/lib/dry/initializer/dispatchers/build_nested_type.rb +54 -40
  14. data/lib/dry/initializer/dispatchers/check_type.rb +45 -39
  15. data/lib/dry/initializer/dispatchers/prepare_default.rb +32 -25
  16. data/lib/dry/initializer/dispatchers/prepare_ivar.rb +13 -6
  17. data/lib/dry/initializer/dispatchers/prepare_optional.rb +14 -7
  18. data/lib/dry/initializer/dispatchers/prepare_reader.rb +29 -22
  19. data/lib/dry/initializer/dispatchers/prepare_source.rb +12 -5
  20. data/lib/dry/initializer/dispatchers/prepare_target.rb +44 -37
  21. data/lib/dry/initializer/dispatchers/unwrap_type.rb +21 -10
  22. data/lib/dry/initializer/dispatchers/wrap_type.rb +24 -17
  23. data/lib/dry/initializer/dispatchers.rb +48 -43
  24. data/lib/dry/initializer/dsl.rb +42 -34
  25. data/lib/dry/initializer/errors.rb +22 -0
  26. data/lib/dry/initializer/mixin/local.rb +19 -13
  27. data/lib/dry/initializer/mixin/root.rb +12 -7
  28. data/lib/dry/initializer/mixin.rb +17 -12
  29. data/lib/dry/initializer/struct.rb +34 -29
  30. data/lib/dry/initializer/undefined.rb +7 -1
  31. data/lib/dry/initializer/version.rb +3 -1
  32. data/lib/dry/initializer.rb +12 -9
  33. data/lib/dry-initializer.rb +3 -1
  34. data/lib/tasks/benchmark.rake +15 -13
  35. data/lib/tasks/profile.rake +20 -16
  36. metadata +5 -4
@@ -1,43 +1,51 @@
1
- module Dry::Initializer
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
- # Returns a version of the module with custom settings
9
- # @option settings [Boolean] :undefined
10
- # If unassigned params and options should be treated different from nil
11
- # @return [Dry::Initializer]
12
- def [](undefined: true, **)
13
- null = (undefined == false) ? nil : UNDEFINED
14
- Module.new.tap do |mod|
15
- mod.extend DSL
16
- mod.include self
17
- mod.send(:instance_variable_set, :@null, null)
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
- # Returns mixin module to be included to target class by hand
22
- # @return [Module]
23
- # @yield proc defining params and options
24
- def define(procedure = nil, &block)
25
- config = Config.new(null: null)
26
- config.instance_exec(&(procedure || block))
27
- config.mixin.include Mixin::Root
28
- config.mixin
29
- end
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
- private
34
+ private
32
35
 
33
- def extended(klass)
34
- config = Config.new(klass, null: null)
35
- klass.send :instance_variable_set, :@dry_initializer, config
36
- klass.include Mixin::Root
37
- end
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
- def self.extended(mod)
40
- mod.instance_variable_set :@null, UNDEFINED
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
- module Dry::Initializer::Mixin
2
- # @private
3
- module Local
4
- attr_reader :klass
1
+ # frozen_string_literal: true
5
2
 
6
- def inspect
7
- "Dry::Initializer::Mixin::Local[#{klass}]"
8
- end
9
- alias to_s inspect
10
- alias to_str inspect
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
- private
16
+ private
13
17
 
14
- def included(klass)
15
- @klass = klass
16
- super
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
- module Dry::Initializer::Mixin
2
- # @private
3
- module Root
4
- private
1
+ # frozen_string_literal: true
5
2
 
6
- def initialize(*args)
7
- __dry_initializer_initialize__(*args)
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
- module Dry::Initializer
2
- # @private
3
- module Mixin
4
- extend DSL # @deprecated
5
- include Dry::Initializer # @deprecated
6
- def self.extended(klass) # @deprecated
7
- warn '[DEPRECATED] Use Dry::Initializer instead of its alias' \
8
- ' Dry::Initializer::Mixin. The later will be removed in v2.1.0'
9
- super
10
- end
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
- require_relative 'mixin/root'
13
- require_relative 'mixin/local'
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
- class Dry::Initializer::Struct
5
- extend Dry::Initializer
5
+ module Dry
6
+ module Initializer
7
+ class Struct
8
+ extend ::Dry::Initializer
6
9
 
7
- class << self
8
- undef_method :param
10
+ class << self
11
+ undef_method :param
9
12
 
10
- def new(options)
11
- super(**Hash(options).each_with_object({}) { |(k, v), h| h[k.to_sym] = v })
12
- end
13
- alias call new
14
- end
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
- # Represents event data as a nested hash with deeply stringified keys
18
- # @return [Hash<String, ...>]
19
- #
20
- def to_h
21
- self
22
- .class
23
- .dry_initializer
24
- .attributes(self)
25
- .each_with_object({}) { |(k, v), h| h[k.to_s] = __hashify(v) }
26
- end
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
- private
31
+ private
29
32
 
30
- def __hashify(value)
31
- case value
32
- when Hash
33
- value.each_with_object({}) { |(k, v), obj| obj[k.to_s] = __hashify(v) }
34
- when Array then value.map { |v| __hashify(v) }
35
- when Dry::Initializer::Struct then value.to_h
36
- else value
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
@@ -1,2 +1,8 @@
1
- module Dry::Initializer::UNDEFINED
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Initializer
5
+ module UNDEFINED
6
+ end
7
+ end
2
8
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dry
2
4
  module Initializer
3
- VERSION = '3.0.4'.freeze
5
+ VERSION = "3.1.0"
4
6
  end
5
7
  end
@@ -1,4 +1,6 @@
1
- require 'set'
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 'initializer/undefined'
10
- require_relative 'initializer/dsl'
11
- require_relative 'initializer/definition'
12
- require_relative 'initializer/builders'
13
- require_relative 'initializer/config'
14
- require_relative 'initializer/mixin'
15
- require_relative 'initializer/dispatchers'
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 'initializer/struct'
62
+ require_relative "initializer/struct"
60
63
  end
61
64
  end
@@ -1 +1,3 @@
1
- require_relative 'dry/initializer'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dry/initializer"
@@ -1,36 +1,38 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :benchmark do
2
- desc 'Runs benchmarks for plain params'
4
+ desc "Runs benchmarks for plain params"
3
5
  task :plain_params do
4
- system 'ruby benchmarks/plain_params.rb'
6
+ system "ruby benchmarks/plain_params.rb"
5
7
  end
6
8
 
7
- desc 'Runs benchmarks for plain options'
9
+ desc "Runs benchmarks for plain options"
8
10
  task :plain_options do
9
- system 'ruby benchmarks/plain_options.rb'
11
+ system "ruby benchmarks/plain_options.rb"
10
12
  end
11
13
 
12
- desc 'Runs benchmarks for value coercion'
14
+ desc "Runs benchmarks for value coercion"
13
15
  task :with_coercion do
14
- system 'ruby benchmarks/with_coercion.rb'
16
+ system "ruby benchmarks/with_coercion.rb"
15
17
  end
16
18
 
17
- desc 'Runs benchmarks with defaults'
19
+ desc "Runs benchmarks with defaults"
18
20
  task :with_defaults do
19
- system 'ruby benchmarks/with_defaults.rb'
21
+ system "ruby benchmarks/with_defaults.rb"
20
22
  end
21
23
 
22
- desc 'Runs benchmarks with defaults and coercion'
24
+ desc "Runs benchmarks with defaults and coercion"
23
25
  task :with_defaults_and_coercion do
24
- system 'ruby benchmarks/with_defaults_and_coercion.rb'
26
+ system "ruby benchmarks/with_defaults_and_coercion.rb"
25
27
  end
26
28
 
27
- desc 'Runs benchmarks for several defaults'
29
+ desc "Runs benchmarks for several defaults"
28
30
  task :compare_several_defaults do
29
- system 'ruby benchmarks/with_several_defaults.rb'
31
+ system "ruby benchmarks/with_several_defaults.rb"
30
32
  end
31
33
  end
32
34
 
33
- desc 'Runs all benchmarks'
35
+ desc "Runs all benchmarks"
34
36
  task benchmark: %i[
35
37
  benchmark:plain_params
36
38
  benchmark:plain_options
@@ -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 'dry-initializer'
4
- require 'ruby-prof'
5
- require 'fileutils'
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 './tmp'
15
+ FileUtils.mkdir_p "./tmp"
13
16
 
14
17
  FileUtils.touch "./tmp/#{name}.dot"
15
- File.open("./tmp/#{name}.dot", 'w+') do |output|
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", 'w+') do |output|
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 'Profiles initialization with required param and option'
30
+ desc "Profiles initialization with required param and option"
28
31
  task :required do
29
- profile('required', -> { User.new :Andy, email: 'andy@example.com' }) do
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 'Profiles initialization with default param and option'
41
+ desc "Profiles initialization with default param and option"
39
42
  task :defaults do
40
- profile('defaults', -> { User.new }) do
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: -> { 'andy@example.com' }
47
+ option :email, default: -> { "andy@example.com" }
45
48
  end
46
49
  end
47
50
  end
48
51
 
49
- desc 'Profiles initialization with coerced param and option'
52
+ desc "Profiles initialization with coerced param and option"
50
53
  task :coercion do
51
- profile('coercion', -> { User.new :Andy, email: :"andy@example.com" }) do
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 'Profiles initialization with coerced defaults of param and option'
63
+ desc "Profiles initialization with coerced defaults of param and option"
61
64
  task :default_coercion do
62
- profile('default_coercion', -> { User.new }) do
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 'Makes all profiling at once'
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
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: 2020-09-29 00:00:00.000000000 Z
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.4.0
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.0.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