Class: Epuber::DSL::Attribute

Inherits:
Object
  • Object
show all
Defined in:
lib/epuber/dsl/attribute.rb

Overview

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

Options collapse

Instance Attribute Summary collapse

Options collapse

Values validation collapse

Automatic conversion collapse

Instance Method Summary collapse

Constructor Details

#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) ⇒ Attribute

Returns a new attribute initialized with the given options.

Parameters:

  • name (Symbol)

Raises:

  • If there are unrecognized options.

See Also:



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 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

Instance Attribute Details

#containerClass (readonly)

Returns if defined it can be [Array] or [Hash]. It is used as default initialization value and to automatically wrap other values to arrays.

Returns:

  • (Class)

    if defined it can be [Array] or [Hash]. It is used as default initialization value and to automatically wrap other values to arrays.



92
93
94
# File 'lib/epuber/dsl/attribute.rb', line 92

def container
  @container
end

#default_valueObject (readonly)

Note:

The default value is not automatically wrapped and should be specified within the container if any.

Returns if the attribute follows configuration over convention it can specify a default value.

Returns:

  • (Object)

    if the attribute follows configuration over convention it can specify a default value.



106
107
108
# File 'lib/epuber/dsl/attribute.rb', line 106

def default_value
  @default_value
end

#file_patternsBool (readonly) Also known as: file_patterns?

Note:

This is mostly used by the linter.

Returns whether the attribute describes file patterns.

Returns:

  • (Bool)

    whether the attribute describes file patterns.



129
130
131
# File 'lib/epuber/dsl/attribute.rb', line 129

def file_patterns
  @file_patterns
end

#keysArray, Hash (readonly)

Note:

A hash is accepted to group the keys associated only with certain keys (see the source attribute of a Book).

Returns the list of the accepted keys for an attribute wrapped by a Hash.

Returns:

  • (Array, Hash)

    the list of the accepted keys for an attribute wrapped by a Hash.



99
100
101
# File 'lib/epuber/dsl/attribute.rb', line 99

def keys
  @keys
end

#nameSymbol (readonly)

Returns name of attribute.

Returns:

  • (Symbol)

    name of attribute



14
15
16
# File 'lib/epuber/dsl/attribute.rb', line 14

def name
  @name
end

#requiredBool (readonly) Also known as: required?

Returns whether the specification should be considered invalid if a value for the attribute is not specified.

Returns:

  • (Bool)

    whether the specification should be considered invalid if a value for the attribute is not specified.



111
112
113
# File 'lib/epuber/dsl/attribute.rb', line 111

def required
  @required
end

#root_onlyBool (readonly) Also known as: root_only?

Returns whether the attribute should be specified only on the root specification.

Returns:

  • (Bool)

    whether the attribute should be specified only on the root specification.



116
117
118
# File 'lib/epuber/dsl/attribute.rb', line 116

def root_only
  @root_only
end

#singularizeBool (readonly) Also known as: singularize?

Returns whether there should be a singular alias for the attribute writer.

Returns:

  • (Bool)

    whether there should be a singular alias for the attribute writer.



122
123
124
# File 'lib/epuber/dsl/attribute.rb', line 122

def singularize
  @singularize
end

#typesArray<Class> (readonly)

Returns the list of the classes of the values supported by the attribute writer. If not specified defaults to [String].

Returns:

  • (Array<Class>)

    the list of the classes of the values supported by the attribute writer. If not specified defaults to [String].



80
81
82
# File 'lib/epuber/dsl/attribute.rb', line 80

def types
  @types
end

Instance Method Details

#converted_value(value) ⇒ Object

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


218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# 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?Bool

Note:

Attributes stored in wrappers are always inherited.

Returns defines whether the attribute reader should join the values with the parent.

Returns:

  • (Bool)

    defines whether the attribute reader should join the values with the parent.



136
137
138
# File 'lib/epuber/dsl/attribute.rb', line 136

def inherited?
  !root_only? && @inherited
end

#inspectString

Returns A string representation suitable for debugging.

Returns:

  • (String)

    A string representation suitable for debugging.



69
70
71
# File 'lib/epuber/dsl/attribute.rb', line 69

def inspect
  "<#{self.class} name=#{name} types=#{types}>"
end

#supported_typesArray<Class>

Returns the list of the classes of the values supported by the attribute, including the container.

Returns:

  • (Array<Class>)

    the list of the classes of the values supported by the attribute, including the container.



85
86
87
# File 'lib/epuber/dsl/attribute.rb', line 85

def supported_types
  @supported_types ||= @types.dup.push(container).compact
end

#to_sString

Returns A string representation suitable for UI.

Returns:

  • (String)

    A string representation suitable for UI.



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

def to_s
  "Attribute `#{name}`"
end

#validate_for_writing(spec, value) ⇒ void

This method returns an undefined value.

Validates a value before storing.

Raises:

  • If a root only attribute is set in a subspec.

  • If a unknown key is added to a hash.



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# 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) ⇒ void

Note:

The this is called before preparing the value.

This method returns an undefined value.

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

Raises:

  • If the type is not in the allowed list.



167
168
169
170
171
172
# 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_nameString

Returns the name of the setter method for the attribute.

Returns:

  • (String)

    the name of the setter method for the attribute.



144
145
146
# File 'lib/epuber/dsl/attribute.rb', line 144

def writer_name
  "#{name}="
end

#writer_singular_formString

Returns an aliased attribute writer offered for convenience on the DSL.

Returns:

  • (String)

    an aliased attribute writer offered for convenience on the DSL.



150
151
152
# File 'lib/epuber/dsl/attribute.rb', line 150

def writer_singular_form
  "#{name.to_s.singularize}=" if singularize?
end