class Epuber::DSL::Attribute

Stores the information of an attribute. It also provides logic to implement any required logic.

Attributes

container[R]

@return [Class] if defined it can be [Array] or [Hash]. It is used as default initialization value

and to automatically wrap other values to arrays.
default_value[R]

@return [Object] if the attribute follows configuration over convention it can specify a default value.

@note The default value is not automatically wrapped and should be specified within the container

if any.
file_patterns[R]

@return [Bool] whether the attribute describes file patterns.

@note This is mostly used by the linter.

file_patterns?[R]

@return [Bool] whether the attribute describes file patterns.

@note This is mostly used by the linter.

keys[R]

@return [Array, Hash] the list of the accepted keys for an attribute wrapped by a Hash.

@note A hash is accepted to group the keys associated only with certain keys (see the source

attribute of a Book).
name[R]

@return [Symbol] name of attribute

required[R]

@return [Bool] whether the specification should be considered invalid if a value for the attribute

is not specified.
required?[R]

@return [Bool] whether the specification should be considered invalid if a value for the attribute

is not specified.
root_only[R]

@return [Bool] whether the attribute should be specified only on the root specification.

root_only?[R]

@return [Bool] whether the attribute should be specified only on the root specification.

singularize[R]

@return [Bool] whether there should be a singular alias for the attribute writer.

singularize?[R]

@return [Bool] whether there should be a singular alias for the attribute writer.

types[R]

@return [Array<Class>] the list of the classes of the values supported by the attribute writer.

If not specified defaults to [String].

Public Class Methods

new(name, inherited: false, root_only: false, required: false, singularize: false, file_patterns: false, container: nil, keys: nil, default_value: nil, auto_convert: {}, types: nil) click to toggle source

Returns a new attribute initialized with the given options.

@param [Symbol] name

@see name

@raise If there are unrecognized options.

# File lib/epuber/dsl/attribute.rb, line 26
def initialize(name, inherited: false,
               root_only: false,
               required: false,
               singularize: false,
               file_patterns: false,
               container: nil,
               keys: nil,
               default_value: nil,
               auto_convert: {},
               types: nil)

  @name = name

  @inherited     = inherited
  @root_only     = root_only
  @required      = required
  @singularize   = singularize
  @file_patterns = file_patterns
  @container     = container
  @keys          = keys
  @default_value = default_value
  @auto_convert  = auto_convert
  @types         = if !types.nil?
                     types
                   elsif @default_value && @auto_convert.empty?
                     [@default_value.class]
                   elsif !@auto_convert.empty?
                     [@auto_convert.values.first]
                   else
                     [String]
                   end
end

Public Instance Methods

converted_value(value) click to toggle source

Converts value to compatible type of attribute

Can be configured with option :auto_convert

Supports conversion from type to type, eg `{ String => Fixnum }`
    also from types to type eg `{ [String, Date] => Fixnum }`
Supports custom conversion with Proc, eg `{ String => lambda { |value| value.to_s } }`
    also with multiple types
# File lib/epuber/dsl/attribute.rb, line 218
def converted_value(value)
  begin
    validate_type(value)
  rescue StandardError
    raise if @auto_convert.nil?

    dest_class = @auto_convert[value.class]

    if dest_class.nil?
      array_keys           = @auto_convert.select { |k, _v| k.is_a?(Array) }
      array_keys_with_type = array_keys.select { |k, _v| k.any? { |klass| value.class <= klass } }

      dest_class = array_keys_with_type.values.first if array_keys_with_type.count.positive?
    end

    if dest_class.respond_to?(:call)
      return dest_class.call(value)
    elsif dest_class.respond_to?(:parse)
      return dest_class.parse(value)
    elsif dest_class <= String
      return value.to_s
    elsif dest_class.respond_to?(:new)
      return dest_class.new(value)
    else
      raise StandardError,
            "Object/class #{dest_class} doesn't support any convert method (#call, .parse or implicit .new)"
    end
  end

  value
end
inherited?() click to toggle source

@return [Bool] defines whether the attribute reader should join the values with the parent.

@note Attributes stored in wrappers are always inherited.

# File lib/epuber/dsl/attribute.rb, line 136
def inherited?
  !root_only? && @inherited
end
inspect() click to toggle source

@return [String] A string representation suitable for debugging.

# File lib/epuber/dsl/attribute.rb, line 69
def inspect
  "<#{self.class} name=#{name} types=#{types}>"
end
supported_types() click to toggle source

@return [Array<Class>] the list of the classes of the values supported by the attribute, including

the container.
# File lib/epuber/dsl/attribute.rb, line 85
def supported_types
  @supported_types ||= @types.dup.push(container).compact
end
to_s() click to toggle source

@return [String] A string representation suitable for UI.

# File lib/epuber/dsl/attribute.rb, line 63
def to_s
  "Attribute `#{name}`"
end
validate_for_writing(spec, value) click to toggle source

Validates a value before storing.

@raise If a root only attribute is set in a subspec.

@raise If a unknown key is added to a hash.

@return [void]

# File lib/epuber/dsl/attribute.rb, line 182
def validate_for_writing(spec, value)
  if root_only? && !spec.root?
    raise StandardError, "Can't set `#{name}` attribute for subspecs (in `#{spec.name}`)."
  end

  return unless keys

  # @return [Array] the flattened list of the allowed keys for the hash of a given specification.
  #
  allowed_keys = lambda do
    if keys.is_a?(Hash)
      keys.keys.concat(keys.values.flatten.compact)
    else
      keys
    end
  end

  value.each_key do |key|
    unless allowed_keys.include?(key)
      raise StandardError, "Unknown key `#{key}` for #{self}. Allowed keys: `#{allowed_keys.inspect}`"
    end
  end
end
validate_type(value) click to toggle source

Validates the value for an attribute. This validation should be performed before the value is prepared or wrapped.

@note The this is called before preparing the value.

@raise If the type is not in the allowed list.

@return [void]

# File lib/epuber/dsl/attribute.rb, line 167
def validate_type(value)
  return if value.nil?
  return if supported_types.any? { |klass| value.class <= klass }

  raise StandardError, "Non acceptable type `#{value.class}` for #{self}. Allowed types: `#{types.inspect}`"
end
writer_name() click to toggle source

@return [String] the name of the setter method for the attribute.

# File lib/epuber/dsl/attribute.rb, line 144
def writer_name
  "#{name}="
end
writer_singular_form() click to toggle source

@return [String] an aliased attribute writer offered for convenience on the DSL.

# File lib/epuber/dsl/attribute.rb, line 150
def writer_singular_form
  "#{name.to_s.singularize}=" if singularize?
end