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

  • :description (String)

    The description of the attribute

  • :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



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cmdx/attribute.rb', line 108

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

  @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

#descriptionString (readonly)

Returns the description of the attribute.

Examples:

attribute.description # => "The user's name"

Returns:

  • (String)

    The description of the attribute



83
84
85
# File 'lib/cmdx/attribute.rb', line 83

def description
  @description
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



139
140
141
142
143
144
145
146
147
# File 'lib/cmdx/attribute.rb', line 139

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



163
164
165
# File 'lib/cmdx/attribute.rb', line 163

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



181
182
183
# File 'lib/cmdx/attribute.rb', line 181

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.



241
242
243
244
245
246
247
248
# File 'lib/cmdx/attribute.rb', line 241

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



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

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



195
196
197
# File 'lib/cmdx/attribute.rb', line 195

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



207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/cmdx/attribute.rb', line 207

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

#to_hHash

}

Examples:

attribute.to_h # => {
name: :user_id,
method_name: :current_user_id,
description: "The user's name",
required: true,
types: [:integer],
options: {},
children: []

Returns:

  • (Hash)

    A hash representation of the attribute



264
265
266
267
268
269
270
271
272
273
274
# File 'lib/cmdx/attribute.rb', line 264

def to_h
  {
    name: name,
    method_name: method_name,
    description: description,
    required: required?,
    types: types,
    options: options.except(:if, :unless),
    children: children.map(&:to_h)
  }
end