Class: CMDx::Attribute

Inherits:
Object
  • Object
show all
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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, options = {}) {|self| ... } ⇒ Attribute

Creates a new attribute with the specified name and configuration.

Examples:

Attribute.new(:user_id, required: true, types: [Integer, String]) do
  required :name, types: String
  optional :email, types: String
end

Parameters:

  • name (Symbol, String)

    The name of the attribute

  • options (Hash) (defaults to: {})

    Configuration options for the attribute

Options Hash (options):

  • :parent (Attribute)

    The parent attribute for nested structures

  • :required (Boolean)

    Whether the attribute is required (default: false)

  • :types (Array<Class>, Class)

    The expected type(s) for the attribute value

  • :source (Symbol, String, Proc)

    The source of the attribute value

  • :as (Symbol, String)

    The method name to use for this attribute

  • :prefix (Symbol, String, Boolean)

    The prefix to add to the method name

  • :suffix (Symbol, String, Boolean)

    The suffix to add to the method name

  • :default (Object)

    The default value for the attribute

Yields:

  • (self)

    Block to configure nested attributes



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/cmdx/attribute.rb', line 97

def initialize(name, options = {}, &)
  @parent = options.delete(:parent)
  @required = options.delete(:required) || false
  @types = Array(options.delete(:types) || options.delete(:type))

  @name = name.to_sym
  @options = options
  @children = []

  instance_eval(&) if block_given?
end

Instance Attribute Details

#childrenArray<Attribute> (readonly)

Returns the child attributes for nested structures.

Examples:

attribute.children # => [#<Attribute @name=:street>, #<Attribute @name=:city>]

Returns:

  • (Array<Attribute>)

    Array of child attributes



53
54
55
# File 'lib/cmdx/attribute.rb', line 53

def children
  @children
end

#nameSymbol (readonly)

Returns the name of this attribute.

Examples:

attribute.name # => :user_id

Returns:

  • (Symbol)

    The attribute name



33
34
35
# File 'lib/cmdx/attribute.rb', line 33

def name
  @name
end

#optionsHash{Symbol => Object} (readonly)

Returns the configuration options for this attribute.

Examples:

attribute.options # => { required: true, default: 0 }

Returns:

  • (Hash{Symbol => Object})

    Configuration options hash



43
44
45
# File 'lib/cmdx/attribute.rb', line 43

def options
  @options
end

#parentAttribute? (readonly)

Returns the parent attribute if this is a nested attribute.

Examples:

attribute.parent # => #<Attribute @name=:address>

Returns:

  • (Attribute, nil)

    The parent attribute, or nil if root-level



63
64
65
# File 'lib/cmdx/attribute.rb', line 63

def parent
  @parent
end

#taskCMDx::Task

Returns the task instance associated with this attribute.

Examples:

attribute.task.context[:user_id] # => 42

Returns:



23
24
25
# File 'lib/cmdx/attribute.rb', line 23

def task
  @task
end

#typesArray<Class> (readonly)

Returns the expected type(s) for this attribute’s value.

Examples:

attribute.types # => [Integer, String]

Returns:

  • (Array<Class>)

    Array of expected type classes



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.

Examples:

Attribute.build(:first_name, :last_name, required: true, types: String)

Parameters:

  • names (Array<Symbol, String>)

    The names of the attributes to create

  • options (Hash)

    Configuration options for the attributes

Options Hash (**options):

  • :* (Object)

    Any attribute configuration option

Yields:

  • (self)

    Block to configure nested attributes

Returns:

  • (Array<Attribute>)

    Array of created attributes

Raises:

  • (ArgumentError)

    When no names are provided or :as is used with multiple attributes



127
128
129
130
131
132
133
134
135
# File 'lib/cmdx/attribute.rb', line 127

def build(*names, **options, &)
  if names.none?
    raise ArgumentError, "no attributes given"
  elsif (names.size > 1) && options.key?(:as)
    raise ArgumentError, "the :as option only supports one attribute per definition"
  end

  names.filter_map { |name| new(name, **options, &) }
end

.optional(*names, **options) {|self| ... } ⇒ Array<Attribute>

Creates optional attributes (not required).

Examples:

Attribute.optional(:description, :tags, types: String)

Parameters:

  • names (Array<Symbol, String>)

    The names of the attributes to create

  • options (Hash)

    Configuration options for the attributes

Options Hash (**options):

  • :* (Object)

    Any attribute configuration option

Yields:

  • (self)

    Block to configure nested attributes

Returns:

  • (Array<Attribute>)

    Array of created optional attributes



151
152
153
# File 'lib/cmdx/attribute.rb', line 151

def optional(*names, **options, &)
  build(*names, **options.merge(required: false), &)
end

.required(*names, **options) {|self| ... } ⇒ Array<Attribute>

Creates required attributes.

Examples:

Attribute.required(:id, :name, types: [Integer, String])

Parameters:

  • names (Array<Symbol, String>)

    The names of the attributes to create

  • options (Hash)

    Configuration options for the attributes

Options Hash (**options):

  • :* (Object)

    Any attribute configuration option

Yields:

  • (self)

    Block to configure nested attributes

Returns:

  • (Array<Attribute>)

    Array of created required attributes



169
170
171
# File 'lib/cmdx/attribute.rb', line 169

def required(*names, **options, &)
  build(*names, **options.merge(required: true), &)
end

Instance Method Details

#define_and_verify_treeObject

Defines and verifies the entire attribute tree including nested children.



229
230
231
232
233
234
235
236
# File 'lib/cmdx/attribute.rb', line 229

def define_and_verify_tree
  define_and_verify

  children.each do |child|
    child.task = task
    child.define_and_verify_tree
  end
end

#method_nameSymbol

Generates the method name for accessing this attribute.

Examples:

attribute.method_name # => :user_name

Returns:

  • (Symbol)

    The method name for the attribute



217
218
219
220
221
222
223
224
# File 'lib/cmdx/attribute.rb', line 217

def method_name
  @method_name ||= options[:as] || begin
    prefix = AFFIX.call(options[:prefix]) { "#{source}_" }
    suffix = AFFIX.call(options[:suffix]) { "_#{source}" }

    :"#{prefix}#{name}#{suffix}"
  end
end

#required?Boolean

Checks if the attribute is required.

Examples:

attribute.required? # => true

Returns:

  • (Boolean)

    true if the attribute is required, false otherwise



183
184
185
# File 'lib/cmdx/attribute.rb', line 183

def required?
  !!@required
end

#sourceSymbol

Determines the source of the attribute value.

Examples:

attribute.source # => :context

Returns:

  • (Symbol)

    The source identifier for the attribute value



195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/cmdx/attribute.rb', line 195

def source
  @source ||= parent&.method_name || begin
    value = options[:source]

    if value.is_a?(Proc)
      task.instance_eval(&value)
    elsif value.respond_to?(:call)
      value.call(task)
    else
      value || :context
    end
  end
end