Class: CMDx::Attribute
- Inherits:
-
Object
- Object
- CMDx::Attribute
- Defined in:
- lib/cmdx/attribute.rb
Overview
Represents a configurable attribute within a CMDx task. Attributes define the data structure and validation rules for task parameters. They can be nested to create complex hierarchical data structures.
Instance Attribute Summary collapse
-
#children ⇒ Array<Attribute>
readonly
Returns the child attributes for nested structures.
-
#description ⇒ String
readonly
Returns the description of the attribute.
-
#name ⇒ Symbol
readonly
Returns the name of this attribute.
-
#options ⇒ Hash{Symbol => Object}
readonly
Returns the configuration options for this attribute.
-
#parent ⇒ Attribute?
readonly
Returns the parent attribute if this is a nested attribute.
-
#task ⇒ CMDx::Task
Returns the task instance associated with this attribute.
-
#types ⇒ Array<Class>
readonly
Returns the expected type(s) for this attribute’s value.
Class Method Summary collapse
-
.build(*names, **options) {|self| ... } ⇒ Array<Attribute>
Builds multiple attributes with the same configuration.
-
.optional(*names, **options) {|self| ... } ⇒ Array<Attribute>
Creates optional attributes (not required).
-
.required(*names, **options) {|self| ... } ⇒ Array<Attribute>
Creates required attributes.
Instance Method Summary collapse
-
#allocation_name ⇒ Symbol?
Returns the method name for this attribute when it can be resolved statically (without a task instance).
-
#clear_task_tree! ⇒ Object
Recursively clears the task reference from this attribute and all children.
-
#define_and_verify_tree ⇒ Object
Defines and verifies the entire attribute tree including nested children.
-
#initialize(name, options = {}) {|self| ... } ⇒ Attribute
constructor
Creates a new attribute with the specified name and configuration.
-
#initialize_dup(source) ⇒ Object
Deep-copies children and clears task-dependent memoization so that duped attributes can be safely bound to a task without mutating the class-level originals.
-
#method_name ⇒ Symbol
Generates the method name for accessing this attribute.
-
#optional? ⇒ Boolean
Checks if the attribute is optional.
-
#required? ⇒ Boolean
Checks if the attribute is required.
-
#source ⇒ Symbol
Determines the source of the attribute value.
-
#to_h ⇒ Hash
}.
Constructor Details
#initialize(name, options = {}) {|self| ... } ⇒ Attribute
Creates a new attribute with the specified name and configuration.
108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/cmdx/attribute.rb', line 108 def initialize(name, = {}, &) @parent = .delete(:parent) @required = .delete(:required) || false @types = Utils::Wrap.array(.delete(:types) || .delete(:type)) @description = .delete(:description) || .delete(:desc) @name = name.to_sym @options = @children = [] instance_eval(&) if block_given? end |
Instance Attribute Details
#children ⇒ Array<Attribute> (readonly)
Returns the child attributes for nested structures.
53 54 55 |
# File 'lib/cmdx/attribute.rb', line 53 def children @children end |
#description ⇒ String (readonly)
Returns the description of the attribute.
83 84 85 |
# File 'lib/cmdx/attribute.rb', line 83 def description @description end |
#name ⇒ Symbol (readonly)
Returns the name of this attribute.
33 34 35 |
# File 'lib/cmdx/attribute.rb', line 33 def name @name end |
#options ⇒ Hash{Symbol => Object} (readonly)
Returns the configuration options for this attribute.
43 44 45 |
# File 'lib/cmdx/attribute.rb', line 43 def @options end |
#parent ⇒ Attribute? (readonly)
Returns the parent attribute if this is a nested attribute.
63 64 65 |
# File 'lib/cmdx/attribute.rb', line 63 def parent @parent end |
#task ⇒ CMDx::Task
Returns the task instance associated with this attribute.
23 24 25 |
# File 'lib/cmdx/attribute.rb', line 23 def task @task end |
#types ⇒ Array<Class> (readonly)
Returns the expected type(s) for this attribute’s value.
73 74 75 |
# File 'lib/cmdx/attribute.rb', line 73 def types @types end |
Class Method Details
.build(*names, **options) {|self| ... } ⇒ Array<Attribute>
Builds multiple attributes with the same configuration.
154 155 156 157 158 159 160 161 162 |
# File 'lib/cmdx/attribute.rb', line 154 def build(*names, **, &) if names.none? raise ArgumentError, "no attributes given" elsif (names.size > 1) && .key?(:as) raise ArgumentError, "the :as option only supports one attribute per definition" end names.filter_map { |name| new(name, **, &) } end |
.optional(*names, **options) {|self| ... } ⇒ Array<Attribute>
Creates optional attributes (not required).
178 179 180 |
# File 'lib/cmdx/attribute.rb', line 178 def optional(*names, **, &) build(*names, **.merge(required: false), &) end |
.required(*names, **options) {|self| ... } ⇒ Array<Attribute>
Creates required attributes.
196 197 198 |
# File 'lib/cmdx/attribute.rb', line 196 def required(*names, **, &) build(*names, **.merge(required: true), &) end |
Instance Method Details
#allocation_name ⇒ Symbol?
Returns the method name for this attribute when it can be resolved statically (without a task instance). Returns nil for Proc/callable sources whose method name depends on runtime evaluation.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/cmdx/attribute.rb', line 261 def allocation_name return @allocation_name if defined?(@allocation_name) @allocation_name = [:as] || begin src = [:source] source_name = if parent parent.allocation_name elsif !src.is_a?(Proc) && !src.respond_to?(:call) src || :context end if source_name.is_a?(Symbol) prefix = AFFIX.call([:prefix]) { "#{source_name}_" } suffix = AFFIX.call([:suffix]) { "_#{source_name}" } :"#{prefix}#{name}#{suffix}" end end end |
#clear_task_tree! ⇒ Object
Recursively clears the task reference from this attribute and all children. Prevents the class-level attribute from retaining the last-executed task instance.
321 322 323 324 |
# File 'lib/cmdx/attribute.rb', line 321 def clear_task_tree! @task = nil children.each(&:clear_task_tree!) end |
#define_and_verify_tree ⇒ Object
Defines and verifies the entire attribute tree including nested children.
308 309 310 311 312 313 314 315 |
# File 'lib/cmdx/attribute.rb', line 308 def define_and_verify_tree define_and_verify children.each do |child| child.task = task child.define_and_verify_tree end end |
#initialize_dup(source) ⇒ Object
Deep-copies children and clears task-dependent memoization so that duped attributes can be safely bound to a task without mutating the class-level originals. This makes concurrent execution thread-safe.
128 129 130 131 132 133 134 |
# File 'lib/cmdx/attribute.rb', line 128 def initialize_dup(source) super @children = source.children.map(&:dup) remove_instance_variable(:@source) if defined?(@source) remove_instance_variable(:@method_name) if defined?(@method_name) @task = nil end |
#method_name ⇒ Symbol
Generates the method name for accessing this attribute.
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/cmdx/attribute.rb', line 289 def method_name return @method_name if defined?(@method_name) result = [:as] || begin prefix = AFFIX.call([:prefix]) { "#{source}_" } suffix = AFFIX.call([:suffix]) { "_#{source}" } :"#{prefix}#{name}#{suffix}" end # Only memoize if @source is defined to avoid memoizing method # name when no task is present. return result unless defined?(@source) @method_name = result end |
#optional? ⇒ Boolean
Checks if the attribute is optional.
210 211 212 |
# File 'lib/cmdx/attribute.rb', line 210 def optional? !required? || !![:optional] end |
#required? ⇒ Boolean
Checks if the attribute is required.
222 223 224 |
# File 'lib/cmdx/attribute.rb', line 222 def required? !!@required end |
#source ⇒ Symbol
Determines the source of the attribute value. Returns :context as a safe fallback when task is not yet set (e.g., schema introspection).
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/cmdx/attribute.rb', line 235 def source return @source if defined?(@source) parent&.method_name || begin value = [:source] if value.is_a?(Proc) task ? @source = task.instance_eval(&value) : :context elsif value.respond_to?(:call) task ? @source = value.call(task) : :context else @source = value || :context end end end |
#to_h ⇒ Hash
}
340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/cmdx/attribute.rb', line 340 def to_h { name: name, method_name: method_name, description: description, required: required?, types: types, options: .except(:if, :unless), children: children.map(&:to_h) } end |