cattri 0.1.2 → 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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +34 -0
  3. data/.gitignore +72 -0
  4. data/.rubocop.yml +6 -3
  5. data/CHANGELOG.md +50 -0
  6. data/Gemfile +12 -0
  7. data/README.md +163 -144
  8. data/Steepfile +6 -0
  9. data/bin/console +33 -0
  10. data/bin/setup +8 -0
  11. data/cattri.gemspec +5 -5
  12. data/lib/cattri/attribute.rb +119 -153
  13. data/lib/cattri/attribute_compiler.rb +104 -0
  14. data/lib/cattri/attribute_options.rb +183 -0
  15. data/lib/cattri/attribute_registry.rb +155 -0
  16. data/lib/cattri/context.rb +124 -106
  17. data/lib/cattri/context_registry.rb +36 -0
  18. data/lib/cattri/deferred_attributes.rb +73 -0
  19. data/lib/cattri/dsl.rb +54 -0
  20. data/lib/cattri/error.rb +17 -90
  21. data/lib/cattri/inheritance.rb +35 -0
  22. data/lib/cattri/initializer_patch.rb +37 -0
  23. data/lib/cattri/internal_store.rb +104 -0
  24. data/lib/cattri/introspection.rb +56 -49
  25. data/lib/cattri/version.rb +3 -1
  26. data/lib/cattri.rb +38 -99
  27. data/sig/lib/cattri/attribute.rbs +105 -0
  28. data/sig/lib/cattri/attribute_compiler.rbs +61 -0
  29. data/sig/lib/cattri/attribute_options.rbs +150 -0
  30. data/sig/lib/cattri/attribute_registry.rbs +95 -0
  31. data/sig/lib/cattri/context.rbs +130 -0
  32. data/sig/lib/cattri/context_registry.rbs +31 -0
  33. data/sig/lib/cattri/deferred_attributes.rbs +53 -0
  34. data/sig/lib/cattri/dsl.rbs +55 -0
  35. data/sig/lib/cattri/error.rbs +28 -0
  36. data/sig/lib/cattri/inheritance.rbs +21 -0
  37. data/sig/lib/cattri/initializer_patch.rbs +26 -0
  38. data/sig/lib/cattri/internal_store.rbs +75 -0
  39. data/sig/lib/cattri/introspection.rbs +61 -0
  40. data/sig/lib/cattri/types.rbs +19 -0
  41. data/sig/lib/cattri/visibility.rbs +55 -0
  42. data/sig/lib/cattri.rbs +37 -0
  43. data/spec/cattri/attribute_compiler_spec.rb +179 -0
  44. data/spec/cattri/attribute_options_spec.rb +267 -0
  45. data/spec/cattri/attribute_registry_spec.rb +257 -0
  46. data/spec/cattri/attribute_spec.rb +297 -0
  47. data/spec/cattri/context_registry_spec.rb +45 -0
  48. data/spec/cattri/context_spec.rb +346 -0
  49. data/spec/cattri/deferred_attrributes_spec.rb +117 -0
  50. data/spec/cattri/dsl_spec.rb +69 -0
  51. data/spec/cattri/error_spec.rb +37 -0
  52. data/spec/cattri/inheritance_spec.rb +60 -0
  53. data/spec/cattri/initializer_patch_spec.rb +35 -0
  54. data/spec/cattri/internal_store_spec.rb +139 -0
  55. data/spec/cattri/introspection_spec.rb +90 -0
  56. data/spec/cattri/visibility_spec.rb +68 -0
  57. data/spec/cattri_spec.rb +54 -0
  58. data/spec/simplecov_helper.rb +21 -0
  59. data/spec/spec_helper.rb +16 -0
  60. metadata +79 -6
  61. data/lib/cattri/attribute_definer.rb +0 -124
  62. data/lib/cattri/class_attributes.rb +0 -204
  63. data/lib/cattri/instance_attributes.rb +0 -226
  64. data/sig/cattri.rbs +0 -4
@@ -1,226 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "attribute_definer"
4
-
5
- module Cattri
6
- # Mixin that provides support for defining instance-level attributes.
7
- #
8
- # This module is included into a class (via `include Cattri`) and exposes
9
- # a DSL similar to `attr_accessor`, with enhancements:
10
- #
11
- # - Lazy or static default values
12
- # - Coercion via custom setter blocks
13
- # - Visibility control (`:public`, `:protected`, `:private`)
14
- # - Read-only or write-only support
15
- #
16
- # Each defined attribute is stored as metadata and linked to a reader and/or writer.
17
- # Values are accessed and stored via standard instance variables.
18
- module InstanceAttributes
19
- # Hook called when this module is included into a class.
20
- #
21
- # @param base [Class]
22
- # @return [void]
23
- def self.included(base)
24
- base.extend(ClassMethods)
25
- end
26
-
27
- # Defines instance-level attribute DSL methods.
28
- module ClassMethods
29
- # Defines one or more instance-level attributes with optional default and coercion.
30
- #
31
- # This method supports defining multiple attributes at once, provided they share the same options.
32
- # If a block is given, only one attribute may be defined to avoid ambiguity.
33
- #
34
- # @example Define multiple attributes with shared defaults
35
- # iattr :foo, :bar, default: []
36
- #
37
- # @example Define a single attribute with coercion
38
- # iattr :level do |val|
39
- # Integer(val)
40
- # end
41
- #
42
- # @param names [Array<Symbol | String>] the names of the attributes to define
43
- # @param options [Hash] additional options like `:default`, `:reader`, `:writer`
44
- # @option options [Object, Proc] :default the default value or lambda
45
- # @option options [Boolean] :reader whether to define a reader method (default: true)
46
- # @option options [Boolean] :writer whether to define a writer method (default: true)
47
- # @option options [Symbol] :access method visibility (:public, :protected, :private)
48
- # @yieldparam value [Object] optional custom coercion logic for the setter
49
- # @raise [Cattri::AttributeError] or its subclasses, including `Cattri::AttributeDefinedError` or
50
- # `Cattri::AttributeDefinitionError` if defining the attribute fails (e.g., if the attribute is
51
- # already defined or an error occurs while defining methods)
52
- # @return [void]
53
- def instance_attribute(*names, **options, &block)
54
- raise Cattri::AmbiguousBlockError if names.size > 1 && block_given?
55
-
56
- names.each { |name| define_instance_attribute(name, options, block) }
57
- end
58
-
59
- # Defines a read-only instance-level attribute.
60
- #
61
- # Equivalent to `instance_attribute(..., writer: false)`
62
- #
63
- # @param names [Array<Symbol | String>] the names of the attributes to define
64
- # @param options [Hash] additional options like `:default`, `:reader`, `:writer`
65
- # @option options [Object, Proc] :default the default value or lambda
66
- # @option options [Boolean] :reader whether to define a reader method (default: true)
67
- # @option options [Symbol] :access method visibility (:public, :protected, :private)
68
- # @yieldparam value [Object] optional custom coercion logic for the setter
69
- # @raise [Cattri::AttributeError] or its subclasses, including `Cattri::AttributeDefinedError` or
70
- # `Cattri::AttributeDefinitionError` if defining the attribute fails (e.g., if the attribute is
71
- # already defined or an error occurs while defining methods)
72
- # @return [void]
73
- def instance_attribute_reader(*names, **options)
74
- instance_attribute(*names, **options, writer: false)
75
- end
76
-
77
- # Defines a write-only instance-level attribute.
78
- #
79
- # Equivalent to `instance_attribute(..., reader: false)`
80
- #
81
- # @param names [Array<Symbol | String>] the names of the attributes to define
82
- # @param options [Hash] additional options like `:default`, `:reader`, `:writer`
83
- # @option options [Object, Proc] :default the default value or lambda
84
- # @option options [Boolean] :writer whether to define a writer method (default: true)
85
- # @option options [Symbol] :access method visibility (:public, :protected, :private)
86
- # @yieldparam value [Object] optional custom coercion logic for the setter
87
- # @raise [Cattri::AttributeError] or its subclasses, including `Cattri::AttributeDefinedError` or
88
- # `Cattri::AttributeDefinitionError` if defining the attribute fails (e.g., if the attribute is
89
- # already defined or an error occurs while defining methods)
90
- # @return [void]
91
- def instance_attribute_writer(*names, **options, &block)
92
- instance_attribute(*names, **options.merge(reader: false), &block)
93
- end
94
-
95
- # Updates the setter behavior of an existing instance-level attribute.
96
- #
97
- # This allows coercion logic to be defined or overridden after the attribute
98
- # has been declared using `iattr`, as long as the writer method exists.
99
- #
100
- # @example Add coercion to an existing attribute
101
- # iattr :format
102
- # iattr_setter :format do |val|
103
- # val.to_s.downcase.to_sym
104
- # end
105
- #
106
- # @param name [Symbol, String] the name of the attribute
107
- # @yieldparam value [Object] the value passed to the setter
108
- # @yieldreturn [Object] the coerced value to be assigned
109
- # @raise [Cattri::AttributeNotDefinedError] if the attribute is not defined or the writer method does not exist
110
- # @raise [Cattri::AttributeDefinitionError] if method redefinition fails
111
- # @return [void]
112
- def instance_attribute_setter(name, &block)
113
- attribute = __cattri_instance_attributes[name.to_sym]
114
-
115
- raise Cattri::AttributeNotDefinedError.new(:instance, name) if attribute.nil?
116
- raise Cattri::AttributeError, "Cannot define setter for readonly attribute :#{name}" unless attribute[:writer]
117
-
118
- attribute.instance_variable_set(:@setter, attribute.send(:normalize_setter, block))
119
- Cattri::AttributeDefiner.define_writer!(attribute, context)
120
- end
121
-
122
- # Returns a list of defined instance-level attribute names.
123
- #
124
- # @return [Array<Symbol>]
125
- def instance_attributes
126
- __cattri_instance_attributes.keys
127
- end
128
-
129
- # Checks if an instance-level attribute has been defined.
130
- #
131
- # @param name [Symbol, String]
132
- # @return [Boolean]
133
- def instance_attribute_defined?(name)
134
- __cattri_instance_attributes.key?(name.to_sym)
135
- end
136
-
137
- # Returns the full attribute definition for a given name.
138
- #
139
- # @param name [Symbol, String]
140
- # @return [Cattri::Attribute, nil]
141
- def instance_attribute_definition(name)
142
- __cattri_instance_attributes[name.to_sym]
143
- end
144
-
145
- # @!method iattr(name, **options, &block)
146
- # Alias for {#instance_attribute}
147
- alias iattr instance_attribute
148
-
149
- # @!method iattr_accessor(name, **options, &block)
150
- # Alias for {#instance_attribute}
151
- alias iattr_accessor instance_attribute
152
-
153
- # @!method iattr_reader(name, **options)
154
- # Alias for {#instance_attribute_reader}
155
- alias iattr_reader instance_attribute_reader
156
-
157
- # @!method iattr_writer(name, **options, &block)
158
- # Alias for {#instance_attribute_writer}
159
- alias iattr_writer instance_attribute_writer
160
-
161
- # @!method iattr_setter(name, &block)
162
- # Alias for {#instance_attribute_setter}
163
- alias iattr_setter instance_attribute_setter
164
-
165
- # @!method iattrs
166
- # Alias for {#instance_attributes}
167
- alias iattrs instance_attributes
168
-
169
- # @!method iattr_defined?(name)
170
- # Alias for {#instance_attribute_defined?}
171
- alias iattr_defined? instance_attribute_defined?
172
-
173
- # @!method iattr_definition(name)
174
- # Alias for {#instance_attribute_definition}
175
- alias iattr_definition instance_attribute_definition
176
-
177
- private
178
-
179
- # Defines a single instance-level attribute.
180
- #
181
- # This is the internal implementation used by {.instance_attribute} and its aliases.
182
- # It creates a `Cattri::Attribute`, registers it, and defines the appropriate
183
- # reader and/or writer methods on the class.
184
- #
185
- # @param name [Symbol, String] the attribute name
186
- # @param options [Hash] additional options for the attribute
187
- # @param block [Proc, nil] optional setter coercion logic
188
- #
189
- # @raise [Cattri::AttributeDefinedError] if the attribute has already been defined
190
- # @raise [Cattri::AttributeDefinitionError] if method definition fails
191
- #
192
- # @return [void]
193
- def define_instance_attribute(name, options, block)
194
- options[:access] ||= __cattri_visibility
195
- attribute = Cattri::Attribute.new(name, :instance, options, block)
196
-
197
- raise Cattri::AttributeDefinedError.new(:instance, name) if instance_attribute_defined?(attribute.name)
198
-
199
- begin
200
- __cattri_instance_attributes[name.to_sym] = attribute
201
- Cattri::AttributeDefiner.define_accessor(attribute, context)
202
- rescue StandardError => e
203
- raise Cattri::AttributeDefinitionError.new(self, attribute, e)
204
- end
205
- end
206
-
207
- # Internal registry of instance attributes defined on the class.
208
- #
209
- # @return [Hash{Symbol => Cattri::Attribute}]
210
- def __cattri_instance_attributes
211
- @__cattri_instance_attributes ||= {}
212
- end
213
-
214
- # Returns the context used to define methods for this class.
215
- #
216
- # Used internally to encapsulate method definition and visibility rules.
217
- #
218
- # @return [Cattri::Context]
219
- # :nocov:
220
- def context
221
- @context ||= Context.new(self)
222
- end
223
- # :nocov:
224
- end
225
- end
226
- end
data/sig/cattri.rbs DELETED
@@ -1,4 +0,0 @@
1
- module Cattri
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end