calificador 0.1.0 → 0.2.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/README.md +35 -16
- data/TODO.md +16 -0
- data/calificador.gemspec +54 -0
- data/lib/calificador.rb +8 -4
- data/lib/calificador/assert.rb +15 -0
- data/lib/calificador/assertor.rb +79 -35
- data/lib/calificador/build/attribute_evaluator.rb +34 -30
- data/lib/calificador/build/basic_factory.rb +195 -0
- data/lib/calificador/build/mock_factory.rb +151 -0
- data/lib/calificador/build/object_factory.rb +85 -0
- data/lib/calificador/build/trait.rb +0 -20
- data/lib/calificador/context/basic_context.rb +406 -0
- data/lib/calificador/context/class_method_context.rb +0 -0
- data/lib/calificador/{spec → context}/condition_context.rb +1 -3
- data/lib/calificador/{spec/type_context.rb → context/instance_context.rb} +5 -10
- data/lib/calificador/context/operation_context.rb +27 -0
- data/lib/calificador/context/override/argument_override.rb +73 -0
- data/lib/calificador/context/override/basic_override.rb +14 -0
- data/lib/calificador/context/override/factory_override.rb +31 -0
- data/lib/calificador/context/override/property_override.rb +61 -0
- data/lib/calificador/context/test_environment.rb +283 -0
- data/lib/calificador/{spec → context}/test_method.rb +2 -31
- data/lib/calificador/{spec → context}/test_root.rb +3 -15
- data/lib/calificador/{spec/examine_context.rb → context/type_context.rb} +7 -10
- data/lib/calificador/key.rb +27 -15
- data/lib/calificador/minitest/minitest_patches.rb +0 -2
- data/lib/calificador/test.rb +1 -3
- data/lib/calificador/test_mixin.rb +143 -139
- data/lib/calificador/util/call_formatter.rb +5 -5
- data/lib/calificador/util/core_extensions.rb +104 -79
- data/lib/calificador/util/proxy_object.rb +63 -0
- data/lib/calificador/version.rb +1 -1
- metadata +22 -42
- data/lib/calificador/build/attribute_container.rb +0 -103
- data/lib/calificador/build/factory.rb +0 -132
- data/lib/calificador/spec/basic_context.rb +0 -353
- data/lib/calificador/spec/class_method_context.rb +0 -42
- data/lib/calificador/spec/instance_method_context.rb +0 -38
- data/lib/calificador/spec/test_environment.rb +0 -141
- data/lib/calificador/spec/value_override.rb +0 -37
@@ -5,11 +5,11 @@ require "pp"
|
|
5
5
|
module Calificador
|
6
6
|
module Util
|
7
7
|
class CallFormatter
|
8
|
-
def
|
8
|
+
def format_method(name:, arguments: [], keywords: {})
|
9
9
|
info = ::StringIO.new
|
10
|
-
info <<
|
10
|
+
info << name
|
11
11
|
|
12
|
-
unless arguments.empty? &&
|
12
|
+
unless arguments.empty? && keywords.empty?
|
13
13
|
info << "("
|
14
14
|
|
15
15
|
arguments.each_with_index do |argument, i|
|
@@ -17,7 +17,7 @@ module Calificador
|
|
17
17
|
append_value(value: argument, out: info)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
keywords.each_with_index do |(name, value), i|
|
21
21
|
info << ", " unless i.zero? && arguments.empty?
|
22
22
|
info << name << ": "
|
23
23
|
append_value(value: value, out: info)
|
@@ -29,7 +29,7 @@ module Calificador
|
|
29
29
|
info.string
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def format_value(value:)
|
33
33
|
append_value(value: value, out: StringIO.new).string
|
34
34
|
end
|
35
35
|
|
@@ -1,72 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "docile"
|
4
3
|
require "ostruct"
|
5
4
|
|
6
5
|
module Calificador
|
7
6
|
module Util
|
8
7
|
# Extensions to core classes
|
9
8
|
module CoreExtensions
|
10
|
-
|
11
|
-
|
12
|
-
def map_call_arguments(signature:, arguments:, options:)
|
13
|
-
min_argument_count = 0
|
14
|
-
max_argument_count = 0
|
15
|
-
option_names = Set.new
|
16
|
-
|
17
|
-
signature.each do |type, name|
|
18
|
-
case type
|
19
|
-
when :req
|
20
|
-
min_argument_count += 1
|
21
|
-
max_argument_count += 1
|
22
|
-
when :opt
|
23
|
-
max_argument_count += 1
|
24
|
-
when :rest
|
25
|
-
max_argument_count = nil
|
26
|
-
when :keyreq
|
27
|
-
raise ArgumentError, "Required option #{name} missing for #{self} #{signature}" unless options.key?(name)
|
28
|
-
|
29
|
-
option_names << name
|
30
|
-
when :key
|
31
|
-
option_names << name
|
32
|
-
when :keyrest
|
33
|
-
option_names += options.keys
|
34
|
-
when :block
|
35
|
-
# ignore
|
36
|
-
else
|
37
|
-
raise ArgumentError, "Illegal parameter type #{type} for #{self} #{signature}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
argument_count = arguments.size
|
42
|
-
argument_count = max_argument_count if max_argument_count && argument_count > max_argument_count
|
43
|
-
|
44
|
-
raise ArgumentError, "Not enough parameters to call proc with #{signature}" if argument_count < min_argument_count
|
45
|
-
|
46
|
-
arguments = arguments[0...argument_count]
|
47
|
-
options = options.slice(*option_names)
|
48
|
-
|
49
|
-
[arguments, options]
|
50
|
-
end
|
51
|
-
|
52
|
-
refine Object do
|
9
|
+
module ObjectMixins
|
53
10
|
def to_bool
|
54
11
|
self ? true : false
|
55
12
|
end
|
56
|
-
|
57
|
-
def dsl_config(&block)
|
58
|
-
target = self
|
59
|
-
|
60
|
-
if block
|
61
|
-
dsl = self.class.const_get(:Dsl).new(delegate: target)
|
62
|
-
Docile.dsl_eval(dsl, &block)
|
63
|
-
end
|
64
|
-
|
65
|
-
target
|
66
|
-
end
|
67
13
|
end
|
68
14
|
|
69
|
-
|
15
|
+
Object.include(ObjectMixins)
|
16
|
+
|
17
|
+
module StringMixins
|
70
18
|
def snake_case
|
71
19
|
gsub(%r{(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])}, "_").downcase
|
72
20
|
end
|
@@ -78,9 +26,14 @@ module Calificador
|
|
78
26
|
end
|
79
27
|
end
|
80
28
|
|
81
|
-
|
29
|
+
String.include(StringMixins)
|
30
|
+
|
31
|
+
module ModuleMixins
|
82
32
|
def parent_module
|
83
|
-
|
33
|
+
if !instance_variable_defined?(:@__calificador_parent_module) || @__calificador_parent_module.nil?
|
34
|
+
@__calificador_parent_module = Nil[parent_name&.then { |m| const_get(m) }]
|
35
|
+
end
|
36
|
+
|
84
37
|
@__calificador_parent_module.unmask_nil
|
85
38
|
end
|
86
39
|
|
@@ -89,47 +42,119 @@ module Calificador
|
|
89
42
|
end
|
90
43
|
|
91
44
|
def base_name
|
92
|
-
|
93
|
-
%r{\
|
94
|
-
|
95
|
-
|
45
|
+
if !instance_variable_defined?(:@__calificador_base_name) || @__calificador_base_name.nil?
|
46
|
+
@__calificador_base_name = if %r{(?:^|::)(?<base_name>(?:[^:]|:[^:])+)\z} =~ name
|
47
|
+
Nil[base_name]
|
48
|
+
else
|
49
|
+
Nil.instance
|
50
|
+
end
|
96
51
|
end
|
97
52
|
|
98
53
|
@__calificador_base_name.unmask_nil
|
99
54
|
end
|
100
55
|
|
101
56
|
def parent_name
|
102
|
-
|
103
|
-
%r{
|
104
|
-
|
105
|
-
|
57
|
+
if !instance_variable_defined?(:@__calificador_parent_name) || @__calificador_parent_name.nil?
|
58
|
+
@__calificador_parent_name = if %r{(?<parent_name>\A.*)::} =~ name
|
59
|
+
parent_name
|
60
|
+
else
|
61
|
+
Nil.instance
|
62
|
+
end
|
106
63
|
end
|
107
64
|
|
108
65
|
@__calificador_parent_name.unmask_nil
|
109
66
|
end
|
110
|
-
end
|
111
67
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
68
|
+
def name_without_common_parents(base:)
|
69
|
+
path = name&.split("::")
|
70
|
+
|
71
|
+
result = if path
|
72
|
+
base_path = base&.name&.split("::")
|
73
|
+
path.remove_common_prefix(base_path).join("::") if base_path
|
116
74
|
end
|
117
75
|
|
118
|
-
|
119
|
-
|
120
|
-
|
76
|
+
result || name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Module.include(ModuleMixins)
|
81
|
+
|
82
|
+
module ArrayMixins
|
83
|
+
def remove_common_prefix(other)
|
84
|
+
drop_while.with_index do |element, index|
|
85
|
+
index < size && element == other[index]
|
121
86
|
end
|
87
|
+
end
|
88
|
+
end
|
122
89
|
|
123
|
-
|
124
|
-
|
125
|
-
|
90
|
+
Array.include(ArrayMixins)
|
91
|
+
|
92
|
+
module CallableMixins
|
93
|
+
REQUIRED_ARGUMENT_TYPES = %i[req keyreq].freeze
|
94
|
+
|
95
|
+
def map_call_arguments(arguments:, keywords:)
|
96
|
+
min_argument_count = 0
|
97
|
+
max_argument_count = 0
|
98
|
+
option_names = Set.new
|
99
|
+
|
100
|
+
parameters.each do |type, name|
|
101
|
+
case type
|
102
|
+
when :req
|
103
|
+
min_argument_count += 1
|
104
|
+
max_argument_count += 1
|
105
|
+
when :opt
|
106
|
+
max_argument_count += 1
|
107
|
+
when :rest
|
108
|
+
max_argument_count = nil
|
109
|
+
when :keyreq
|
110
|
+
raise ArgumentError, "Required option #{name} missing for #{self} #{parameters}" unless keywords.key?(name)
|
111
|
+
|
112
|
+
option_names << name
|
113
|
+
when :key
|
114
|
+
option_names << name
|
115
|
+
when :keyrest
|
116
|
+
option_names += keywords.keys
|
117
|
+
when :block
|
118
|
+
# ignore
|
119
|
+
else
|
120
|
+
raise ArgumentError, "Illegal parameter type #{type} for #{self} #{parameters}"
|
121
|
+
end
|
126
122
|
end
|
127
123
|
|
128
|
-
|
129
|
-
|
124
|
+
argument_count = arguments.size
|
125
|
+
argument_count = max_argument_count if max_argument_count && argument_count > max_argument_count
|
126
|
+
|
127
|
+
if argument_count < min_argument_count
|
128
|
+
raise ArgumentError, "Not enough parameters to call proc with #{parameters}"
|
130
129
|
end
|
130
|
+
|
131
|
+
arguments = arguments[0...argument_count]
|
132
|
+
keywords = keywords.slice(*option_names)
|
133
|
+
|
134
|
+
[arguments, keywords]
|
135
|
+
end
|
136
|
+
|
137
|
+
def invoke(*arguments, **keywords, &block)
|
138
|
+
arguments, keywords = map_call_arguments(arguments: arguments, keywords: keywords)
|
139
|
+
call(*arguments, **keywords, &block)
|
140
|
+
end
|
141
|
+
|
142
|
+
def invoke_with_target(target, *arguments, **keywords)
|
143
|
+
arguments, keywords = map_call_arguments(arguments: arguments, keywords: keywords)
|
144
|
+
target.instance_exec(*arguments, **keywords, &self)
|
145
|
+
end
|
146
|
+
|
147
|
+
def source_location_info
|
148
|
+
source_location ? source_location.join(":") : nil
|
149
|
+
end
|
150
|
+
|
151
|
+
def required_arguments?
|
152
|
+
parameters.any? { |type, _name| REQUIRED_ARGUMENT_TYPES.include?(type) }
|
131
153
|
end
|
132
154
|
end
|
155
|
+
|
156
|
+
Method.include(CallableMixins)
|
157
|
+
Proc.include(CallableMixins)
|
133
158
|
end
|
134
159
|
end
|
135
160
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Calificador
|
4
|
+
module Util
|
5
|
+
# Base class for proxy objects
|
6
|
+
class ProxyObject < BasicObject
|
7
|
+
FALLBACK_METHODS = %i[class to_s inspect eval].freeze
|
8
|
+
|
9
|
+
def respond_to?(name, include_all = false) # rubocop:disable Style/OptionalBooleanParameter
|
10
|
+
__class.public_instance_methods(true).include?(name) ||
|
11
|
+
include_all && (
|
12
|
+
__class.protected_instance_methods(true).include?(name) ||
|
13
|
+
__class.private_instance_methods(true).include?(name)
|
14
|
+
) ||
|
15
|
+
respond_to_missing?(name, include_all)
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_to_missing?(name, include_all)
|
19
|
+
name.start_with?("__") ? false : __respond_to_missing?(name: name, include_all: include_all)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(name, *arguments, **keywords, &block)
|
23
|
+
if name.start_with?("__")
|
24
|
+
super(name, *arguments, **keywords, &block)
|
25
|
+
else
|
26
|
+
__method_missing(name: name, arguments: arguments, keywords: keywords, block: block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def __class
|
33
|
+
(class << self; self end).superclass
|
34
|
+
end
|
35
|
+
|
36
|
+
def __to_s
|
37
|
+
"#<#{__class}>"
|
38
|
+
end
|
39
|
+
|
40
|
+
def __inspect
|
41
|
+
"#<#{__class}>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def __eval(*arguments)
|
45
|
+
instance_eval(*arguments)
|
46
|
+
end
|
47
|
+
|
48
|
+
def __respond_to_missing?(name:, include_all:)
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
def __method_missing(name:, arguments:, keywords:, block:)
|
53
|
+
if ::Kernel.respond_to?(name)
|
54
|
+
::Kernel.send(name, *arguments, **keywords, &block)
|
55
|
+
elsif FALLBACK_METHODS.include?(name)
|
56
|
+
__send__(:"__#{name}", *arguments, **keywords, &block)
|
57
|
+
else
|
58
|
+
::Kernel.raise ::NoMethodError, "undefined name `#{name}' for #{__class}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/calificador/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calificador
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jochen Seeber
|
8
8
|
autorequire:
|
9
9
|
bindir: cmd
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: docile
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.3.5
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 1.3.5
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: minitest
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,20 +52,6 @@ dependencies:
|
|
66
52
|
- - "~>"
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: '2.1'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: coveralls
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - '='
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 0.8.23.js
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - '='
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 0.8.23.js
|
83
55
|
- !ruby/object:Gem::Dependency
|
84
56
|
name: debase
|
85
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -201,25 +173,32 @@ extra_rdoc_files: []
|
|
201
173
|
files:
|
202
174
|
- LICENSE.txt
|
203
175
|
- README.md
|
176
|
+
- TODO.md
|
177
|
+
- calificador.gemspec
|
204
178
|
- lib/calificador.rb
|
179
|
+
- lib/calificador/assert.rb
|
205
180
|
- lib/calificador/assertor.rb
|
206
181
|
- lib/calificador/build/attribute.rb
|
207
|
-
- lib/calificador/build/attribute_container.rb
|
208
182
|
- lib/calificador/build/attribute_evaluator.rb
|
209
|
-
- lib/calificador/build/
|
183
|
+
- lib/calificador/build/basic_factory.rb
|
184
|
+
- lib/calificador/build/mock_factory.rb
|
185
|
+
- lib/calificador/build/object_factory.rb
|
210
186
|
- lib/calificador/build/trait.rb
|
187
|
+
- lib/calificador/context/basic_context.rb
|
188
|
+
- lib/calificador/context/class_method_context.rb
|
189
|
+
- lib/calificador/context/condition_context.rb
|
190
|
+
- lib/calificador/context/instance_context.rb
|
191
|
+
- lib/calificador/context/operation_context.rb
|
192
|
+
- lib/calificador/context/override/argument_override.rb
|
193
|
+
- lib/calificador/context/override/basic_override.rb
|
194
|
+
- lib/calificador/context/override/factory_override.rb
|
195
|
+
- lib/calificador/context/override/property_override.rb
|
196
|
+
- lib/calificador/context/test_environment.rb
|
197
|
+
- lib/calificador/context/test_method.rb
|
198
|
+
- lib/calificador/context/test_root.rb
|
199
|
+
- lib/calificador/context/type_context.rb
|
211
200
|
- lib/calificador/key.rb
|
212
201
|
- lib/calificador/minitest/minitest_patches.rb
|
213
|
-
- lib/calificador/spec/basic_context.rb
|
214
|
-
- lib/calificador/spec/class_method_context.rb
|
215
|
-
- lib/calificador/spec/condition_context.rb
|
216
|
-
- lib/calificador/spec/examine_context.rb
|
217
|
-
- lib/calificador/spec/instance_method_context.rb
|
218
|
-
- lib/calificador/spec/test_environment.rb
|
219
|
-
- lib/calificador/spec/test_method.rb
|
220
|
-
- lib/calificador/spec/test_root.rb
|
221
|
-
- lib/calificador/spec/type_context.rb
|
222
|
-
- lib/calificador/spec/value_override.rb
|
223
202
|
- lib/calificador/test.rb
|
224
203
|
- lib/calificador/test_mixin.rb
|
225
204
|
- lib/calificador/util/call_formatter.rb
|
@@ -227,6 +206,7 @@ files:
|
|
227
206
|
- lib/calificador/util/core_extensions.rb
|
228
207
|
- lib/calificador/util/missing.rb
|
229
208
|
- lib/calificador/util/nil.rb
|
209
|
+
- lib/calificador/util/proxy_object.rb
|
230
210
|
- lib/calificador/version.rb
|
231
211
|
homepage: https://github.com/jochenseeber/calificador
|
232
212
|
licenses: []
|
@@ -1,103 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
using Calificador::Util::CoreExtensions
|
4
|
-
|
5
|
-
module Calificador
|
6
|
-
module Build
|
7
|
-
# Factory calss
|
8
|
-
class AttributeContainer
|
9
|
-
class Dsl
|
10
|
-
def initialize(delegate:)
|
11
|
-
@delegate = delegate
|
12
|
-
@property_type = nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def add_attribute(name, type: nil, &config)
|
16
|
-
type ||= @delegate.parent&.attribute(name: name)&.type || @property_type || :property
|
17
|
-
@delegate.add_attribute(Attribute.new(name: name, type: type, config: config))
|
18
|
-
end
|
19
|
-
|
20
|
-
def transient(&block)
|
21
|
-
raise ArgumentError, "Transient requires a block" if block.nil?
|
22
|
-
|
23
|
-
old_property_type = @property_type
|
24
|
-
@property_type = :transient
|
25
|
-
|
26
|
-
begin
|
27
|
-
instance_exec(self, &block)
|
28
|
-
ensure
|
29
|
-
@property_type = old_property_type
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def init_with(&block)
|
34
|
-
raise "Initializer requires a block to create the object" if block.nil?
|
35
|
-
|
36
|
-
@delegate.init_with = block
|
37
|
-
end
|
38
|
-
|
39
|
-
def before_create(&block)
|
40
|
-
raise "Before requires a block to call" if block.nil?
|
41
|
-
|
42
|
-
@delegate.before_create = block
|
43
|
-
end
|
44
|
-
|
45
|
-
def after_create(&block)
|
46
|
-
raise "After requires a block to call" if block.nil?
|
47
|
-
|
48
|
-
@delegate.after_create = block
|
49
|
-
end
|
50
|
-
|
51
|
-
def respond_to_missing?(method, include_all = false)
|
52
|
-
if method.start_with?("__")
|
53
|
-
super
|
54
|
-
else
|
55
|
-
true
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def method_missing(method, *arguments, &block)
|
60
|
-
if method.start_with?("__")
|
61
|
-
super
|
62
|
-
else
|
63
|
-
unless arguments.empty?
|
64
|
-
raise ::ArgumentError, <<~ERROR
|
65
|
-
Attribute #{method} cannot have arguments. Please use a block to configure the value
|
66
|
-
ERROR
|
67
|
-
end
|
68
|
-
|
69
|
-
raise ::ArgumentError, "Attribute #{method} must have a block to provide the value" if block.nil?
|
70
|
-
|
71
|
-
add_attribute(method, &block)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
attr_reader :parent, :description
|
77
|
-
attr_accessor :init_with, :before_create, :after_create
|
78
|
-
|
79
|
-
def initialize(parent:, description:)
|
80
|
-
@parent = parent
|
81
|
-
@description = description.dup.freeze
|
82
|
-
@attributes = {}
|
83
|
-
@init_with = nil
|
84
|
-
@before_create = nil
|
85
|
-
@after_create = nil
|
86
|
-
end
|
87
|
-
|
88
|
-
def attributes
|
89
|
-
@attributes.dup.freeze
|
90
|
-
end
|
91
|
-
|
92
|
-
def attribute(name:)
|
93
|
-
@attributes[name]
|
94
|
-
end
|
95
|
-
|
96
|
-
def add_attribute(attribute)
|
97
|
-
raise KeyError, "Duplicate attribute name #{name}" if @attributes.key?(attribute.name)
|
98
|
-
|
99
|
-
@attributes[attribute.name] = attribute
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|