dry-interface 1.0.1 → 1.0.2
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/lib/dry/{interface → concrete}/extensions/default.rb +1 -1
- data/lib/dry/{interface → concrete}/extensions/type.rb +15 -1
- data/lib/dry/concrete/extensions.rb +10 -0
- data/lib/dry/concrete/value.rb +21 -0
- data/lib/dry/concrete.rb +121 -0
- data/lib/dry/interface/interfaces/abstract.rb +14 -5
- data/lib/dry/interface/interfaces/concrete.rb +28 -8
- data/lib/dry/interface/interfaces/unit.rb +49 -0
- data/lib/dry/interface/interfaces.rb +1 -2
- data/lib/dry/interface/patch.rb +11 -0
- data/lib/dry/interface.rb +80 -132
- metadata +9 -7
- data/lib/dry/interface/extensions.rb +0 -10
- data/lib/dry/interface/interfaces/common.rb +0 -17
- data/lib/dry/interface/interfaces/value.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b05534847a5f500b3095bc1e1f752006395f4de8b9f3da99e6a6535a26ada354
|
4
|
+
data.tar.gz: d8bf8f9f0d1fcf5eeaf10bfcaa29d83630c0ffbbd9bcc4274436e90bfe7a935f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a31c77b1aefa20e3ea3f763d1bbde2630f9599134ddbce053c9da574f65e77c84c4b8bf1b56812de401ab94fdd36695f3c36c9bd97d74c6ce830217f49ef8a2
|
7
|
+
data.tar.gz: 2d7f3a2ad607d2ac0628840eaf0a6ac6dcffd244c2736a18cfa8ac166170a06defb08b5e0a77cc9fdb8622fe06cf2fe8a29f3843fb85169bbb1ec2c8d21193c6
|
@@ -4,7 +4,7 @@ require "dry/struct"
|
|
4
4
|
require "dry/types"
|
5
5
|
|
6
6
|
module Dry
|
7
|
-
class
|
7
|
+
class Concrete
|
8
8
|
module Extensions
|
9
9
|
module Type
|
10
10
|
module Types
|
@@ -84,6 +84,20 @@ module Dry
|
|
84
84
|
alias_method :to_type, :itself
|
85
85
|
end
|
86
86
|
|
87
|
+
refine Dry::Concrete.singleton_class do
|
88
|
+
# Dry::Types::Type is already a type in itself
|
89
|
+
# Used to streamline the API for all objects
|
90
|
+
#
|
91
|
+
# @example Dry type to dry type
|
92
|
+
# type = Dry::Types['string'].to_type
|
93
|
+
#
|
94
|
+
# type.valid?("string") # => true
|
95
|
+
# type.valid?(:string) # => false
|
96
|
+
#
|
97
|
+
# @return [Dry::Types::Type]
|
98
|
+
alias_method :to_type, :itself
|
99
|
+
end
|
100
|
+
|
87
101
|
refine Module do
|
88
102
|
# Ensures passed value includes module
|
89
103
|
#
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
class Concrete
|
5
|
+
class Value < self
|
6
|
+
def self.new(value, *other, &block)
|
7
|
+
case value
|
8
|
+
in Hash => attributes then super(attributes, *other, &block)
|
9
|
+
in Dry::Struct => instance then instance
|
10
|
+
else
|
11
|
+
case attribute_names
|
12
|
+
in [] then raise ArgumentError, "[#{self}] has no attributes, one is required"
|
13
|
+
in [key] then super({ key => value }, *other, &block)
|
14
|
+
else
|
15
|
+
raise ArgumentError, "[#{self}] has more than one attribute: #{attribute_names.join(', ')}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/dry/concrete.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/concerning"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
5
|
+
require "active_support/descendants_tracker"
|
6
|
+
require "active_support/configurable"
|
7
|
+
require "active_support/inflector"
|
8
|
+
require "active_support/concern"
|
9
|
+
require "dry/struct"
|
10
|
+
require "dry/types"
|
11
|
+
|
12
|
+
module Dry
|
13
|
+
autoload :Interface, "dry/interface"
|
14
|
+
|
15
|
+
class Concrete < Dry::Struct
|
16
|
+
autoload :Extensions, "dry/concrete/extensions"
|
17
|
+
autoload :Value, "dry/concrete/value"
|
18
|
+
autoload :Types, "dry/interface/types"
|
19
|
+
|
20
|
+
schema schema.strict(true)
|
21
|
+
|
22
|
+
include Dry.Types(:strict, :nominal, :coercible)
|
23
|
+
|
24
|
+
extend ActiveSupport::DescendantsTracker
|
25
|
+
include ActiveSupport::Configurable
|
26
|
+
extend ActiveSupport::Inflector
|
27
|
+
|
28
|
+
using Extensions::Default
|
29
|
+
using Extensions::Type
|
30
|
+
|
31
|
+
config.order = Hash.new(-1)
|
32
|
+
|
33
|
+
delegate(*%i[
|
34
|
+
Constructor
|
35
|
+
Interface
|
36
|
+
Instance
|
37
|
+
Constant
|
38
|
+
Nominal
|
39
|
+
Value
|
40
|
+
Array
|
41
|
+
Hash
|
42
|
+
Any
|
43
|
+
], to: :Types)
|
44
|
+
|
45
|
+
def self.initializer(owner, &block)
|
46
|
+
owner.schema owner.schema.constructor(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adds attribute {name} to the struct
|
50
|
+
#
|
51
|
+
# @example Add a new attribute
|
52
|
+
# class User < Dry::Struct
|
53
|
+
# attribute :name, String
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# @example Add a new attribute with a default value
|
57
|
+
# class User < Dry::Struct
|
58
|
+
# attribute :name, String, default: "John"
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# @example Add a new attribute with constraints
|
62
|
+
# class User < Dry::Struct
|
63
|
+
# attribute :name, String, size: 3..20
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @example Add a new attribute with array type
|
67
|
+
# class User < Dry::Struct
|
68
|
+
# attribute :name, [String]
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @param name [Symbol]
|
72
|
+
# @param constrains [Array<#to_type>]
|
73
|
+
# @option default [#call, Any]
|
74
|
+
# @return [void]
|
75
|
+
def self.attribute(field, *constrains, **options, &block)
|
76
|
+
alias_fields(field, **options) do |inner_options|
|
77
|
+
super(field, build_type_from(*constrains, **inner_options), &block)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Optional version of {#attribute}
|
82
|
+
#
|
83
|
+
# @see #attribute
|
84
|
+
def self.attribute?(field, *constrains, **options, &block)
|
85
|
+
alias_fields(field, **options) do |inner_options|
|
86
|
+
super(field, build_type_from(*constrains, **inner_options), &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.alias_fields(field, aliases: [], **options, &block)
|
91
|
+
if options.key?(:alias)
|
92
|
+
aliases << options.delete(:alias)
|
93
|
+
end
|
94
|
+
|
95
|
+
block[options]
|
96
|
+
|
97
|
+
aliases.each do |alias_name|
|
98
|
+
alias_method alias_name, field
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
def self.build_type_from(*constrains, **options)
|
104
|
+
unless (type = constrains.map(&:to_type).reduce(:|))
|
105
|
+
return build_type_from(Dry::Types["any"], **options)
|
106
|
+
end
|
107
|
+
|
108
|
+
if options.key?(:default)
|
109
|
+
options.delete(:default).to_default.then do |default_proc|
|
110
|
+
return build_type_from(type.default(&default_proc), **options)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
if options.empty?
|
115
|
+
return type
|
116
|
+
end
|
117
|
+
|
118
|
+
build_type_from(type.constrained(**options))
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -1,19 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/module/introspection"
|
4
|
+
require "active_support/core_ext/module/attribute_accessors"
|
5
|
+
|
3
6
|
module Dry
|
4
7
|
class Interface
|
5
8
|
module Interfaces
|
6
9
|
module Abstract
|
7
10
|
extend ActiveSupport::Concern
|
8
|
-
include Common
|
9
11
|
|
10
12
|
class_methods do
|
11
|
-
|
12
|
-
|
13
|
+
# Class name without parent module
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
def name
|
17
|
+
demodulize(super)
|
13
18
|
end
|
14
19
|
|
15
|
-
def
|
16
|
-
|
20
|
+
def new(input, safe = false, &block)
|
21
|
+
if safe
|
22
|
+
call_safe(input, &block)
|
23
|
+
else
|
24
|
+
call_unsafe(input)
|
25
|
+
end
|
17
26
|
end
|
18
27
|
end
|
19
28
|
end
|
@@ -1,25 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# module C
|
4
|
+
# def structs
|
5
|
+
# [self]
|
6
|
+
# end
|
7
|
+
|
8
|
+
# def named
|
9
|
+
# to_s
|
10
|
+
# end
|
11
|
+
|
12
|
+
# def type
|
13
|
+
# self
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
|
3
17
|
module Dry
|
4
18
|
class Interface
|
5
19
|
module Interfaces
|
6
20
|
module Concrete
|
7
21
|
extend ActiveSupport::Concern
|
8
|
-
include Common
|
9
22
|
|
10
|
-
|
23
|
+
prepended do
|
11
24
|
class << self
|
25
|
+
alias_method :call_safe, :_call_safe
|
26
|
+
alias_method :call_unsafe, :_call_unsafe
|
12
27
|
alias_method :new, :_new
|
28
|
+
alias_method :call, :_call
|
13
29
|
end
|
14
30
|
end
|
31
|
+
# included do
|
32
|
+
# class << self
|
33
|
+
# alias_method :call, :_call
|
34
|
+
# end
|
35
|
+
# end
|
15
36
|
|
16
37
|
class_methods do
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
direct_descendants.first&.name or name
|
38
|
+
# Class name without parent module
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
def to_s
|
42
|
+
demodulize(name)
|
23
43
|
end
|
24
44
|
end
|
25
45
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
class Interface
|
5
|
+
module Interfaces
|
6
|
+
module Unit
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
prepended do
|
10
|
+
class << self
|
11
|
+
alias_method :call, :_call
|
12
|
+
alias_method :call_unsafe, :_call_unsafe
|
13
|
+
alias_method :call_safe, :_call_safe
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class_methods do
|
18
|
+
# Class name without parent module
|
19
|
+
#
|
20
|
+
# @return [String]
|
21
|
+
def to_s
|
22
|
+
demodulize(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Allows a struct to be called without a hash
|
26
|
+
#
|
27
|
+
# @param value [Dry::Struct, Hash, Any]
|
28
|
+
# @param block [Proc]
|
29
|
+
#
|
30
|
+
# @return [Dry::Struct]
|
31
|
+
|
32
|
+
def new(value, *other, &block)
|
33
|
+
case value
|
34
|
+
in Hash => attributes then _new(attributes, *other, &block)
|
35
|
+
in Dry::Struct => instance then instance
|
36
|
+
else
|
37
|
+
case attribute_names
|
38
|
+
in [] then raise ArgumentError, "[#{self}] has no attributes, one is required"
|
39
|
+
in [key] then _new({ key => value }, *other, &block)
|
40
|
+
else
|
41
|
+
raise ArgumentError, "[#{self}] has more than one attribute: #{attribute_names.join(', ')}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -3,8 +3,7 @@
|
|
3
3
|
module Dry
|
4
4
|
class Interface
|
5
5
|
module Interfaces
|
6
|
-
autoload :
|
7
|
-
autoload :Common, "dry/interface/interfaces/common"
|
6
|
+
autoload :Unit, "dry/interface/interfaces/unit"
|
8
7
|
autoload :Abstract, "dry/interface/interfaces/abstract"
|
9
8
|
autoload :Concrete, "dry/interface/interfaces/concrete"
|
10
9
|
end
|
data/lib/dry/interface.rb
CHANGED
@@ -6,170 +6,118 @@ require "active_support/descendants_tracker"
|
|
6
6
|
require "active_support/configurable"
|
7
7
|
require "active_support/inflector"
|
8
8
|
require "active_support/concern"
|
9
|
-
require "dry/struct"
|
10
9
|
require "dry/types"
|
11
10
|
|
12
11
|
module Dry
|
13
|
-
|
12
|
+
autoload :Concrete, "dry/concrete"
|
13
|
+
|
14
|
+
class Interface < Concrete
|
14
15
|
autoload :Interfaces, "dry/interface/interfaces"
|
15
|
-
autoload :Extensions, "dry/interface/extensions"
|
16
|
-
autoload :Types, "dry/interface/types"
|
17
|
-
|
18
|
-
extend ActiveSupport::DescendantsTracker
|
19
|
-
extend ActiveSupport::Inflector
|
20
|
-
|
21
|
-
using Extensions::Default
|
22
|
-
using Extensions::Type
|
23
|
-
|
24
|
-
schema schema.strict(true)
|
25
|
-
|
26
|
-
delegate(*%i[
|
27
|
-
Constructor
|
28
|
-
Interface
|
29
|
-
Instance
|
30
|
-
Constant
|
31
|
-
Nominal
|
32
|
-
Value
|
33
|
-
Array
|
34
|
-
Hash
|
35
|
-
Any
|
36
|
-
], to: Types)
|
37
|
-
|
38
|
-
Types.constants.each do |constant|
|
39
|
-
raise "#{const_get(constant)} is already defined"
|
40
|
-
rescue NameError
|
41
|
-
const_set(constant, Types.const_get(constant))
|
42
|
-
end
|
43
16
|
|
44
|
-
|
45
|
-
prepended do
|
46
|
-
class << self
|
47
|
-
alias_method :_new, :new
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
17
|
+
include ActiveSupport::Configurable
|
51
18
|
|
52
|
-
|
53
|
-
include Dry.Types()
|
54
|
-
end
|
19
|
+
config.order = Hash.new(-1)
|
55
20
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
direct_descendants.map(&:type).reduce(&:|)
|
62
|
-
end
|
21
|
+
class << self
|
22
|
+
alias _new new
|
23
|
+
alias _call call
|
24
|
+
alias _call_safe call_safe
|
25
|
+
alias _call_unsafe call_unsafe
|
63
26
|
|
64
|
-
|
65
|
-
|
27
|
+
delegate :call, to: :subtype
|
28
|
+
delegate :call_safe, to: :subtype
|
29
|
+
delegate :call_unsafe, to: :subtype
|
66
30
|
end
|
67
31
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
32
|
+
# Allow types structs to be ordered
|
33
|
+
#
|
34
|
+
# @param names [Array<Symbol>]
|
35
|
+
def self.order(*names)
|
36
|
+
result = names.each_with_index.reduce(EMPTY_HASH) do |acc, (name, index)|
|
37
|
+
acc.merge(name.to_s => index)
|
38
|
+
end
|
73
39
|
|
74
|
-
|
75
|
-
owner.schema owner.schema.constructor(&block)
|
40
|
+
config.order = result
|
76
41
|
end
|
77
42
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
43
|
+
# @return [String]
|
44
|
+
def self.to_s
|
45
|
+
format("%<name>s<[%<types>s]>", name: name, types: subtypes.map(&:to_s).join(" | "))
|
82
46
|
end
|
83
47
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
#
|
91
|
-
# @example Add a new attribute with a default value
|
92
|
-
# class User < Dry::Struct
|
93
|
-
# attribute :name, String, default: "John"
|
94
|
-
# end
|
95
|
-
#
|
96
|
-
# @example Add a new attribute with constraints
|
97
|
-
# class User < Dry::Struct
|
98
|
-
# attribute :name, String, size: 3..20
|
99
|
-
# end
|
100
|
-
#
|
101
|
-
# @example Add a new attribute with array type
|
102
|
-
# class User < Dry::Struct
|
103
|
-
# attribute :name, [String]
|
104
|
-
# end
|
105
|
-
#
|
106
|
-
# @param name [Symbol]
|
107
|
-
# @param constrains [Array<#to_type>]
|
108
|
-
# @option default [#call, Any]
|
109
|
-
# @return [void]
|
110
|
-
def self.attribute(field, *constrains, **options, &block)
|
111
|
-
alias_fields(field, **options) do |inner_options|
|
112
|
-
super(field, build_type_from(*constrains, **inner_options), &block)
|
48
|
+
def self.reduce(input, subtype)
|
49
|
+
case input
|
50
|
+
in { result: }
|
51
|
+
input
|
52
|
+
in { value: }
|
53
|
+
{ result: subtype.call(value) }
|
113
54
|
end
|
55
|
+
rescue Dry::Struct::Error => e
|
56
|
+
em = Dry::Types::ConstraintError.new(e.message, input.fetch(:value))
|
57
|
+
input.merge(errors: input.fetch(:errors, []) + [em])
|
58
|
+
rescue Dry::Types::CoercionError => e
|
59
|
+
input.merge(errors: input.fetch(:errors, []) + [e])
|
114
60
|
end
|
115
61
|
|
116
|
-
#
|
62
|
+
# Internal type represented by {self}
|
117
63
|
#
|
118
|
-
# @
|
119
|
-
def self.
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
def self.const_missing(name)
|
126
|
-
case name
|
127
|
-
when :Abstract
|
128
|
-
return Class.new(self) do
|
129
|
-
include Interfaces::Abstract
|
64
|
+
# @return [Dry::Struct::Sum, Dry::Struct::Class]
|
65
|
+
def self.subtype
|
66
|
+
Constructor(self) do |value, _type, &error|
|
67
|
+
error ||= lambda do |error|
|
68
|
+
raise error
|
130
69
|
end
|
131
|
-
|
132
|
-
|
133
|
-
|
70
|
+
|
71
|
+
if subtypes.empty?
|
72
|
+
raise NotImplementedError, "No subtypes defined for #{name}"
|
134
73
|
end
|
135
|
-
|
136
|
-
|
137
|
-
|
74
|
+
|
75
|
+
output = subtypes.reduce({ value: value }, &method(:reduce))
|
76
|
+
|
77
|
+
case output
|
78
|
+
in { result: }
|
79
|
+
result
|
80
|
+
in { errors: }
|
81
|
+
error[Dry::Types::MultipleError.new(errors)]
|
82
|
+
in Dry::Struct
|
83
|
+
output
|
138
84
|
end
|
139
85
|
end
|
140
|
-
|
141
|
-
super
|
142
86
|
end
|
143
87
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
88
|
+
# Internal types represented by {self}
|
89
|
+
#
|
90
|
+
# @return [Dry::Struct::Class]
|
91
|
+
def self.subtypes
|
92
|
+
types = subclasses.flat_map(&:subclasses)
|
148
93
|
|
149
|
-
|
94
|
+
return types if config.order.empty?
|
150
95
|
|
151
|
-
|
152
|
-
|
96
|
+
types.sort_by do |type|
|
97
|
+
config.order.fetch(demodulize(type.name))
|
153
98
|
end
|
154
99
|
end
|
155
100
|
|
156
|
-
# @
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
return build_type_from(type.default(&default_proc), **options)
|
101
|
+
# @param name [Symbol]
|
102
|
+
#
|
103
|
+
# @return [Abstract::Class]
|
104
|
+
def self.const_missing(name)
|
105
|
+
case name
|
106
|
+
in :Concrete
|
107
|
+
Class.new(self) do
|
108
|
+
prepend Interfaces::Concrete
|
165
109
|
end
|
110
|
+
in :Abstract
|
111
|
+
Class.new(self) do
|
112
|
+
prepend Interfaces::Abstract
|
113
|
+
end
|
114
|
+
in :Unit
|
115
|
+
Class.new(self) do
|
116
|
+
prepend Interfaces::Unit
|
117
|
+
end
|
118
|
+
else
|
119
|
+
super
|
166
120
|
end
|
167
|
-
|
168
|
-
if options.empty?
|
169
|
-
return type
|
170
|
-
end
|
171
|
-
|
172
|
-
build_type_from(type.constrained(**options))
|
173
121
|
end
|
174
122
|
end
|
175
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-interface
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Linus Oleander
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-11-
|
11
|
+
date: 2021-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -59,15 +59,17 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
+
- lib/dry/concrete.rb
|
63
|
+
- lib/dry/concrete/extensions.rb
|
64
|
+
- lib/dry/concrete/extensions/default.rb
|
65
|
+
- lib/dry/concrete/extensions/type.rb
|
66
|
+
- lib/dry/concrete/value.rb
|
62
67
|
- lib/dry/interface.rb
|
63
|
-
- lib/dry/interface/extensions.rb
|
64
|
-
- lib/dry/interface/extensions/default.rb
|
65
|
-
- lib/dry/interface/extensions/type.rb
|
66
68
|
- lib/dry/interface/interfaces.rb
|
67
69
|
- lib/dry/interface/interfaces/abstract.rb
|
68
|
-
- lib/dry/interface/interfaces/common.rb
|
69
70
|
- lib/dry/interface/interfaces/concrete.rb
|
70
|
-
- lib/dry/interface/interfaces/
|
71
|
+
- lib/dry/interface/interfaces/unit.rb
|
72
|
+
- lib/dry/interface/patch.rb
|
71
73
|
- lib/dry/interface/types.rb
|
72
74
|
homepage: https://github.com/oleander/dry-interface
|
73
75
|
licenses:
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
class Interface
|
5
|
-
module Interfaces
|
6
|
-
module Value
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
include Concrete
|
9
|
-
|
10
|
-
included do |child|
|
11
|
-
otherwise do |value, type, &error|
|
12
|
-
names = child.type.attribute_names
|
13
|
-
|
14
|
-
unless names.one?
|
15
|
-
raise ArgumentError, "Value classes must have exactly one attribute, got [#{names.join(', ')}] (#{names.count}) for [#{child}]"
|
16
|
-
end
|
17
|
-
|
18
|
-
type[names.first => value, &error]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|