cattri 0.1.0 → 0.1.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 +4 -4
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +31 -1
- data/README.md +141 -85
- data/lib/cattri/attribute.rb +202 -0
- data/lib/cattri/attribute_definer.rb +112 -0
- data/lib/cattri/class_attributes.rb +60 -171
- data/lib/cattri/context.rb +155 -0
- data/lib/cattri/error.rb +67 -0
- data/lib/cattri/instance_attributes.rb +62 -110
- data/lib/cattri/introspection.rb +1 -1
- data/lib/cattri/version.rb +1 -1
- data/lib/cattri/visibility.rb +66 -0
- data/lib/cattri.rb +91 -8
- metadata +6 -5
- data/.idea/workspace.xml +0 -350
- data/.rspec_status +0 -75
- data/lib/cattri/helpers.rb +0 -75
@@ -1,68 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
4
|
-
require_relative "
|
3
|
+
require_relative "attribute"
|
4
|
+
require_relative "context"
|
5
|
+
require_relative "attribute_definer"
|
6
|
+
require_relative "visibility"
|
5
7
|
|
6
8
|
module Cattri
|
7
|
-
#
|
9
|
+
# Mixin that provides support for defining class-level attributes.
|
8
10
|
#
|
9
|
-
#
|
11
|
+
# This module is intended to be extended onto a class and provides a DSL
|
12
|
+
# for defining configuration-style attributes at the class level using `cattr`.
|
13
|
+
#
|
14
|
+
# Features:
|
15
|
+
# - Default values (static, frozen, or callable)
|
10
16
|
# - Optional coercion via setter blocks
|
11
17
|
# - Optional instance-level readers
|
12
|
-
# -
|
13
|
-
# - Inheritance-safe duplication
|
14
|
-
# - Attribute locking to prevent mutation in subclasses
|
15
|
-
#
|
16
|
-
# This module is designed for advanced metaprogramming needs such as DSL builders,
|
17
|
-
# configuration objects, and plugin systems that require reusable and introspectable
|
18
|
-
# class-level state.
|
19
|
-
#
|
20
|
-
# @example
|
21
|
-
# class MyClass
|
22
|
-
# extend Cattri::ClassAttributes
|
23
|
-
#
|
24
|
-
# cattr :format, default: :json
|
25
|
-
# cattr_reader :version, default: "1.0.0"
|
26
|
-
# cattr :enabled, default: true do |value|
|
27
|
-
# !!value
|
28
|
-
# end
|
29
|
-
# end
|
18
|
+
# - Visibility enforcement (`:public`, `:protected`, `:private`)
|
30
19
|
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# MyClass.format # => :xml
|
34
|
-
# MyClass.version # => "1.0.0"
|
35
|
-
#
|
36
|
-
# instance = MyClass.new
|
37
|
-
# instance.format # => :xml
|
20
|
+
# Class attributes are stored internally as `Cattri::Attribute` instances and
|
21
|
+
# values are memoized using class-level instance variables.
|
38
22
|
module ClassAttributes
|
39
|
-
include Cattri::Helpers
|
40
|
-
|
41
|
-
# Default options applied to all class-level attributes.
|
42
|
-
DEFAULT_OPTIONS = { default: nil, readonly: false }.freeze
|
43
|
-
|
44
23
|
# Defines a class-level attribute with optional default, coercion, and reader access.
|
45
24
|
#
|
46
25
|
# @param name [Symbol] the attribute name
|
47
26
|
# @param options [Hash] additional attribute options
|
48
|
-
# @option options [Object, Proc] :default the default value or
|
27
|
+
# @option options [Object, Proc] :default the default value or lambda
|
49
28
|
# @option options [Boolean] :readonly whether the attribute is read-only
|
50
|
-
# @option options [Boolean] :instance_reader whether to define an instance-level reader
|
51
|
-
# @
|
52
|
-
# @
|
53
|
-
# @
|
29
|
+
# @option options [Boolean] :instance_reader whether to define an instance-level reader (default: true)
|
30
|
+
# @option options [Symbol] :access visibility level (:public, :protected, :private)
|
31
|
+
# @yieldparam value [Object] an optional custom setter block
|
32
|
+
# @raise [Cattri::AttributeError] or its subclasses, including `Cattri::AttributeDefinedError` or
|
33
|
+
# `Cattri::AttributeDefinitionError` if defining the attribute fails (e.g., if the attribute is
|
34
|
+
# already defined or an error occurs while defining methods)
|
54
35
|
def class_attribute(name, **options, &block)
|
55
|
-
|
36
|
+
options[:access] ||= __cattri_visibility
|
37
|
+
attribute = Cattri::Attribute.new(name, :class, options, block)
|
38
|
+
|
39
|
+
raise Cattri::AttributeDefinedError, attribute if class_attribute_defined?(attribute.name)
|
56
40
|
|
57
|
-
|
58
|
-
|
41
|
+
begin
|
42
|
+
__cattri_class_attributes[name] = attribute
|
59
43
|
|
60
|
-
|
61
|
-
|
62
|
-
|
44
|
+
Cattri::AttributeDefiner.define_callable_accessor(attribute, context)
|
45
|
+
Cattri::AttributeDefiner.define_instance_level_reader(attribute, context) if attribute[:instance_reader]
|
46
|
+
rescue StandardError => e
|
47
|
+
raise Cattri::AttributeDefinitionError.new(self, attribute, e)
|
48
|
+
end
|
63
49
|
end
|
64
50
|
|
65
|
-
# Defines a read-only class attribute
|
51
|
+
# Defines a read-only class attribute.
|
52
|
+
#
|
53
|
+
# Equivalent to calling `class_attribute(name, readonly: true, ...)`
|
66
54
|
#
|
67
55
|
# @param name [Symbol]
|
68
56
|
# @param options [Hash]
|
@@ -71,14 +59,14 @@ module Cattri
|
|
71
59
|
class_attribute(name, readonly: true, **options)
|
72
60
|
end
|
73
61
|
|
74
|
-
# Returns
|
62
|
+
# Returns a list of defined class attribute names.
|
75
63
|
#
|
76
64
|
# @return [Array<Symbol>]
|
77
65
|
def class_attributes
|
78
66
|
__cattri_class_attributes.keys
|
79
67
|
end
|
80
68
|
|
81
|
-
# Checks whether a class
|
69
|
+
# Checks whether a class attribute has been defined.
|
82
70
|
#
|
83
71
|
# @param name [Symbol]
|
84
72
|
# @return [Boolean]
|
@@ -86,161 +74,62 @@ module Cattri
|
|
86
74
|
__cattri_class_attributes.key?(name.to_sym)
|
87
75
|
end
|
88
76
|
|
89
|
-
# Returns
|
77
|
+
# Returns the full attribute definition object.
|
90
78
|
#
|
91
79
|
# @param name [Symbol]
|
92
|
-
# @return [
|
80
|
+
# @return [Cattri::Attribute, nil]
|
93
81
|
def class_attribute_definition(name)
|
94
82
|
__cattri_class_attributes[name.to_sym]
|
95
83
|
end
|
96
84
|
|
97
|
-
# Resets all defined class attributes to their default values.
|
98
|
-
#
|
99
|
-
# @return [void]
|
100
|
-
def reset_class_attributes!
|
101
|
-
reset_attributes!(self, __cattri_class_attributes.values)
|
102
|
-
end
|
103
|
-
|
104
|
-
# Resets a single class attribute to its default value.
|
105
|
-
#
|
106
|
-
# @param name [Symbol]
|
107
|
-
# @return [void]
|
108
|
-
def reset_class_attribute!(name)
|
109
|
-
definition = __cattri_class_attributes[name]
|
110
|
-
return unless definition
|
111
|
-
|
112
|
-
reset_attributes!(self, [definition])
|
113
|
-
end
|
114
|
-
|
115
|
-
# alias lock_cattrs! lock_class_attributes!
|
116
|
-
# alias cattrs_locked? class_attributes_locked?
|
117
|
-
|
118
85
|
# @!method cattr(name, **options, &block)
|
119
86
|
# Alias for {.class_attribute}
|
120
|
-
# @see
|
87
|
+
# @see #class_attribute
|
121
88
|
alias cattr class_attribute
|
122
89
|
|
123
90
|
# @!method cattr_accessor(name, **options, &block)
|
124
91
|
# Alias for {.class_attribute}
|
125
|
-
# @see
|
92
|
+
# @see #class_attribute
|
126
93
|
alias cattr_accessor class_attribute
|
127
94
|
|
128
95
|
# @!method cattr_reader(name, **options)
|
129
96
|
# Alias for {.class_attribute_reader}
|
130
|
-
# @see
|
97
|
+
# @see #class_attribute_reader
|
131
98
|
alias cattr_reader class_attribute_reader
|
132
99
|
|
133
100
|
# @!method cattrs
|
134
|
-
#
|
135
|
-
# @
|
101
|
+
# Alias for {.class_attributes}
|
102
|
+
# @return [Array<Symbol>]
|
136
103
|
alias cattrs class_attributes
|
137
104
|
|
138
105
|
# @!method cattr_defined?(name)
|
139
|
-
#
|
140
|
-
# @
|
106
|
+
# Alias for {.class_attribute_defined?}
|
107
|
+
# @param name [Symbol]
|
108
|
+
# @return [Boolean]
|
141
109
|
alias cattr_defined? class_attribute_defined?
|
142
110
|
|
143
|
-
# @!method
|
144
|
-
#
|
145
|
-
# @
|
111
|
+
# @!method cattr_definition(name)
|
112
|
+
# Alias for {.class_attribute_definition}
|
113
|
+
# @param name [Symbol]
|
114
|
+
# @return [Cattri::Attribute, nil]
|
146
115
|
alias cattr_definition class_attribute_definition
|
147
116
|
|
148
|
-
# @!method reset_cattrs!
|
149
|
-
# Resets all class attributes to their default values.
|
150
|
-
# @see .reset_class_attributes!
|
151
|
-
alias reset_cattrs! reset_class_attributes!
|
152
|
-
|
153
|
-
# @!method reset_cattr!(name)
|
154
|
-
# Resets a specific class attribute to its default value.
|
155
|
-
# @see .reset_class_attribute!
|
156
|
-
alias reset_cattr! reset_class_attribute!
|
157
|
-
|
158
117
|
private
|
159
118
|
|
160
|
-
#
|
161
|
-
#
|
162
|
-
# @return [void]
|
163
|
-
def define_inheritance
|
164
|
-
unless singleton_class.method_defined?(:__cattri_class_attributes)
|
165
|
-
define_singleton_method(:__cattri_class_attributes) { @__cattri_class_attributes ||= {} }
|
166
|
-
end
|
167
|
-
|
168
|
-
define_singleton_method(:inherited) do |subclass|
|
169
|
-
super(subclass)
|
170
|
-
subclass_attributes = {}
|
171
|
-
|
172
|
-
__cattri_class_attributes.each do |name, definition|
|
173
|
-
apply_attribute!(subclass, subclass_attributes, name, definition)
|
174
|
-
end
|
175
|
-
|
176
|
-
subclass.instance_variable_set(:@__cattri_class_attributes, subclass_attributes)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Defines the primary accessor method on the class.
|
181
|
-
#
|
182
|
-
# @param name [Symbol]
|
183
|
-
# @param definition [Hash]
|
184
|
-
# @return [void]
|
185
|
-
def define_accessor(name, definition)
|
186
|
-
ivar = definition[:ivar]
|
187
|
-
|
188
|
-
define_singleton_method(name) do |*args, **kwargs|
|
189
|
-
readonly = readonly_call?(args, kwargs) || definition[:readonly]
|
190
|
-
return apply_readonly(ivar, definition[:default]) if readonly
|
191
|
-
|
192
|
-
instance_variable_set(ivar, definition[:setter].call(*args, **kwargs))
|
193
|
-
end
|
194
|
-
|
195
|
-
return if definition[:readonly]
|
196
|
-
|
197
|
-
define_singleton_method("#{name}=") do |value|
|
198
|
-
instance_variable_set(ivar, definition[:setter].call(value))
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
# Defines an instance-level reader that delegates to the class-level method.
|
203
|
-
#
|
204
|
-
# @param name [Symbol]
|
205
|
-
# @return [void]
|
206
|
-
def define_instance_reader(name)
|
207
|
-
define_method(name) { self.class.__send__(name) }
|
208
|
-
end
|
209
|
-
|
210
|
-
# Applies the default value for a read-only call.
|
119
|
+
# Internal registry of defined class-level attributes.
|
211
120
|
#
|
212
|
-
# @
|
213
|
-
|
214
|
-
|
215
|
-
def apply_readonly(ivar, default)
|
216
|
-
return instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
217
|
-
|
218
|
-
value = default.call
|
219
|
-
instance_variable_set(ivar, value)
|
121
|
+
# @return [Hash{Symbol => Cattri::Attribute}]
|
122
|
+
def __cattri_class_attributes
|
123
|
+
@__cattri_class_attributes ||= {}
|
220
124
|
end
|
221
125
|
|
222
|
-
#
|
126
|
+
# Context object used to define accessors with scoped visibility.
|
223
127
|
#
|
224
|
-
# @
|
225
|
-
#
|
226
|
-
|
227
|
-
|
228
|
-
# @return [void]
|
229
|
-
def apply_attribute!(subclass, attributes, name, definition)
|
230
|
-
value = instance_variable_get(definition[:ivar])
|
231
|
-
value = value.dup rescue value # rubocop:disable Style/RescueModifier
|
232
|
-
|
233
|
-
subclass.instance_variable_set(definition[:ivar], value)
|
234
|
-
attributes[name] = definition
|
235
|
-
end
|
236
|
-
|
237
|
-
# Determines if the method call should be treated as read-only access.
|
238
|
-
#
|
239
|
-
# @param args [Array]
|
240
|
-
# @param kwargs [Hash]
|
241
|
-
# @return [Boolean]
|
242
|
-
def readonly_call?(args, kwargs)
|
243
|
-
args.empty? && kwargs.empty?
|
128
|
+
# @return [Cattri::Context]
|
129
|
+
# :nocov:
|
130
|
+
def context
|
131
|
+
@context ||= Context.new(self)
|
244
132
|
end
|
133
|
+
# :nocov:
|
245
134
|
end
|
246
135
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
module Cattri
|
6
|
+
# Provides a controlled interface for defining methods and instance variables
|
7
|
+
# on a target class or module. Used internally by Cattri to define attribute
|
8
|
+
# readers and writers while preserving access visibility and tracking which
|
9
|
+
# methods were explicitly created.
|
10
|
+
#
|
11
|
+
# This abstraction allows class and instance attribute logic to be composed
|
12
|
+
# consistently and safely across both standard and singleton contexts.
|
13
|
+
class Context
|
14
|
+
# Allowed Ruby visibility levels for methods.
|
15
|
+
ACCESS_LEVELS = %i[public protected private].freeze
|
16
|
+
private_constant :ACCESS_LEVELS
|
17
|
+
|
18
|
+
# @return [Module, Class] the receiver to which accessors will be added
|
19
|
+
attr_reader :target
|
20
|
+
|
21
|
+
# Initializes a new context wrapper around the given target.
|
22
|
+
#
|
23
|
+
# @param target [Module, Class] the object to define methods or ivars on
|
24
|
+
def initialize(target)
|
25
|
+
@target = target
|
26
|
+
@defined_methods = Set.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the singleton class of the target.
|
30
|
+
#
|
31
|
+
# This is used to define methods on the class itself (not its instances).
|
32
|
+
#
|
33
|
+
# @return [Class]
|
34
|
+
def singleton
|
35
|
+
@target.singleton_class
|
36
|
+
end
|
37
|
+
|
38
|
+
# Checks whether a method is already defined on the target.
|
39
|
+
#
|
40
|
+
# This includes public, protected, private, and previously defined methods
|
41
|
+
# via this context (tracked in `@defined_methods`).
|
42
|
+
#
|
43
|
+
# @param method [String, Symbol]
|
44
|
+
# @return [Boolean]
|
45
|
+
def method_defined?(method)
|
46
|
+
@target.method_defined?(method) ||
|
47
|
+
@target.private_method_defined?(method) ||
|
48
|
+
@target.protected_method_defined?(method) ||
|
49
|
+
@defined_methods.include?(method.to_sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Defines a method on the appropriate context (class or singleton).
|
53
|
+
#
|
54
|
+
# If the method already exists, it is not redefined. Visibility is applied
|
55
|
+
# according to the attribute's `:access` setting (defaulting to `:public`).
|
56
|
+
#
|
57
|
+
# @param attribute [Cattri::Attribute]
|
58
|
+
# @param name [Symbol, nil] optional method name override
|
59
|
+
# @yield the method implementation
|
60
|
+
# @raise [Cattri::AttributeDefinitionError] if method definition fails
|
61
|
+
# @return [void]
|
62
|
+
def define_method(attribute, name: nil, &block)
|
63
|
+
name = (name || attribute.name).to_sym
|
64
|
+
return if method_defined?(name)
|
65
|
+
|
66
|
+
target = target_for(attribute)
|
67
|
+
|
68
|
+
begin
|
69
|
+
target.define_method(name, &block)
|
70
|
+
@defined_methods << name
|
71
|
+
apply_access(name, attribute)
|
72
|
+
rescue StandardError => e
|
73
|
+
raise Cattri::AttributeDefinitionError.new(target, attribute, e)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Checks whether the target has the given instance variable.
|
78
|
+
#
|
79
|
+
# @param name [Symbol, String]
|
80
|
+
# @return [Boolean]
|
81
|
+
def ivar_defined?(name)
|
82
|
+
@target.instance_variable_defined?(sanitize_ivar(name))
|
83
|
+
end
|
84
|
+
|
85
|
+
# Retrieves the value of the specified instance variable on the target.
|
86
|
+
#
|
87
|
+
# @param name [Symbol, String]
|
88
|
+
# @return [Object]
|
89
|
+
def ivar_get(name)
|
90
|
+
@target.instance_variable_get(sanitize_ivar(name))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Assigns a value to the specified instance variable on the target.
|
94
|
+
#
|
95
|
+
# @param name [Symbol, String]
|
96
|
+
# @param value [Object]
|
97
|
+
# @return [void]
|
98
|
+
def ivar_set(name, value)
|
99
|
+
@target.instance_variable_set(sanitize_ivar(name), value)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Memoizes a value in the instance variable only if not already defined.
|
103
|
+
#
|
104
|
+
# @param name [Symbol, String]
|
105
|
+
# @param value [Object]
|
106
|
+
# @return [Object] the existing or assigned value
|
107
|
+
def ivar_memoize(name, value)
|
108
|
+
return ivar_get(name) if ivar_defined?(name)
|
109
|
+
|
110
|
+
ivar_set(name, value)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
# Selects the correct definition target based on attribute type.
|
116
|
+
#
|
117
|
+
# @param attribute [Cattri::Attribute]
|
118
|
+
# @return [Module] either the target or its singleton class
|
119
|
+
def target_for(attribute)
|
120
|
+
attribute.class_level? ? singleton : @target
|
121
|
+
end
|
122
|
+
|
123
|
+
# Validates and normalizes access level.
|
124
|
+
#
|
125
|
+
# @param access [Symbol, String, nil]
|
126
|
+
# @return [Symbol] a valid visibility level
|
127
|
+
def validate_access(access)
|
128
|
+
access = (access || :public).to_sym
|
129
|
+
return access if ACCESS_LEVELS.include?(access)
|
130
|
+
|
131
|
+
warn "[Cattri] `#{access.inspect}` is not a supported access level, defaulting to :public"
|
132
|
+
:public
|
133
|
+
end
|
134
|
+
|
135
|
+
# Applies method visibility to a newly defined method.
|
136
|
+
#
|
137
|
+
# @param method_name [Symbol]
|
138
|
+
# @param attribute [Cattri::Attribute]
|
139
|
+
# @return [void]
|
140
|
+
def apply_access(method_name, attribute)
|
141
|
+
return if attribute.public?
|
142
|
+
|
143
|
+
access = validate_access(attribute[:access])
|
144
|
+
Module.instance_method(access).bind(@target).call(method_name)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Ensures consistent formatting for ivar keys.
|
148
|
+
#
|
149
|
+
# @param name [Symbol, String]
|
150
|
+
# @return [Symbol]
|
151
|
+
def sanitize_ivar(name)
|
152
|
+
:"@#{name.to_s.delete_prefix("@")}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/lib/cattri/error.rb
CHANGED
@@ -1,5 +1,72 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Cattri
|
4
|
+
# Base error class for all exceptions raised by Cattri.
|
5
|
+
#
|
6
|
+
# All Cattri-specific errors inherit from this class.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# rescue Cattri::Error => e
|
10
|
+
# puts "Something went wrong with Cattri: #{e.message}"
|
4
11
|
class Error < StandardError; end
|
12
|
+
|
13
|
+
# Parent class for all attribute-related errors in Cattri.
|
14
|
+
#
|
15
|
+
# This includes definition conflicts, setter failures, or configuration issues.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# rescue Cattri::AttributeError => e
|
19
|
+
# puts "Attribute error: #{e.message}"
|
20
|
+
class AttributeError < Cattri::Error; end
|
21
|
+
|
22
|
+
# Raised when a class or instance attribute is defined more than once.
|
23
|
+
#
|
24
|
+
# This helps detect naming collisions during DSL usage.
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# raise Cattri::AttributeDefinedError.new(attribute)
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# rescue Cattri::AttributeDefinedError => e
|
31
|
+
# puts e.message
|
32
|
+
class AttributeDefinedError < Cattri::AttributeError
|
33
|
+
# @param attribute [Cattri::Attribute] the conflicting attribute
|
34
|
+
def initialize(attribute)
|
35
|
+
super("#{attribute.type.capitalize} attribute :#{attribute.name} has already been defined")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Raised when a method definition (reader, writer, or callable) fails.
|
40
|
+
#
|
41
|
+
# This wraps the original error that occurred during `define_method` or visibility handling.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# raise Cattri::AttributeDefinitionError.new(target, attribute, error)
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# rescue Cattri::AttributeDefinitionError => e
|
48
|
+
# puts e.message
|
49
|
+
class AttributeDefinitionError < Cattri::AttributeError
|
50
|
+
# @param target [Module] the class or module receiving the method
|
51
|
+
# @param attribute [Cattri::Attribute] the attribute being defined
|
52
|
+
# @param error [StandardError] the original raised exception
|
53
|
+
def initialize(target, attribute, error)
|
54
|
+
super("Failed to define method :#{attribute.name} on #{target}. Error: #{error.message}")
|
55
|
+
set_backtrace(error.backtrace)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Raised when an unsupported attribute type is passed to Cattri.
|
60
|
+
#
|
61
|
+
# Valid types are typically `:class` and `:instance`. Any other value is invalid.
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# raise Cattri::UnsupportedTypeError.new(:foo)
|
65
|
+
# # => Attribute type :foo is not supported
|
66
|
+
class UnsupportedTypeError < Error
|
67
|
+
# @param type [Symbol] the invalid type that triggered the error
|
68
|
+
def initialize(type)
|
69
|
+
super("Attribute type :#{type} is not supported")
|
70
|
+
end
|
71
|
+
end
|
5
72
|
end
|