Class: IGMarkets::Model

Inherits:
Object
  • Object
show all
Defined in:
lib/ig_markets/model.rb

Overview

This class is intended to be subclassed in order to create models that contain a set of attributes, where each attribute is defined by a call to Model.attribute. Attributes have standard accessor methods and can also be subject to a variety of constraints and validations, see Model.attribute for further details.

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Model

Initializes this new model with the given attribute values. Attributes not known to this model will raise ArgumentError.

Parameters:

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

    The attribute values to set on this new model.


15
16
17
18
19
20
21
22
23
24
25
# File 'lib/ig_markets/model.rb', line 15

def initialize(attributes = {})
  self.class.defined_attribute_names.each do |name|
    send "#{name}=", attributes[name]
  end

  attributes.each do |name, value|
    next if respond_to? "#{name}="

    raise ArgumentError, "unknown attribute: #{self.class.name}##{name}, value: #{inspect_value value}"
  end
end

Class Attribute Details

.defined_attributesHash

Returns a hash containing details of all attributes that have been defined on this model.

Returns:

  • (Hash)

    a hash containing details of all attributes that have been defined on this model.


94
95
96
# File 'lib/ig_markets/model.rb', line 94

def defined_attributes
  @defined_attributes
end

.deprecated_attributesArray

Returns the names of the deprecated attributes on this model.

Returns:

  • (Array)

    the names of the deprecated attributes on this model.


97
98
99
# File 'lib/ig_markets/model.rb', line 97

def deprecated_attributes
  @deprecated_attributes
end

Instance Attribute Details

#attributesHash

The current attribute values set on this model.

Returns:

  • (Hash)

9
10
11
# File 'lib/ig_markets/model.rb', line 9

def attributes
  @attributes
end

Class Method Details

.allowed_values(attribute_name) ⇒ Array

Returns the array of allowed values for the specified attribute that was passed to attribute.

Parameters:

  • attribute_name (Symbol)

    The name of the attribute to return the allowed values for.

Returns:

  • (Array)

139
140
141
# File 'lib/ig_markets/model.rb', line 139

def allowed_values(attribute_name)
  Hash(defined_attributes).fetch(attribute_name).fetch :allowed_values
end

.attribute(name, type = String, options = {}) ⇒ Object

Defines setter and getter instance methods and a sanitizer class method for a new attribute on this class.

Parameters:

  • name (Symbol)

    The name of the new attribute.

  • type (Boolean, String, Date, Time, Integer, Float, Symbol, Model) (defaults to: String)

    The attribute's type.

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

    The configuration options for the new attribute.

Options Hash (options):

  • :allowed_values (Array)

    The set of values that this attribute is allowed to be set to. An attempt to set this attribute to a value not in this list will raise ArgumentError. Optional.

  • :nil_if (Array)

    Values that, when set on the attribute, should be converted to nil.

  • :regex (Regexp)

    When type is String only values matching this regex will be allowed. Optional.

  • :format (String)

    When type is Date or Time this specifies the format or formats for parsing String and Integer instances assigned to this attribute.


171
172
173
174
175
176
177
178
# File 'lib/ig_markets/model.rb', line 171

def attribute(name, type = String, options = {})
  define_attribute_reader name
  define_attribute_writer name
  define_attribute_sanitizer name, type, options

  @defined_attributes ||= {}
  @defined_attributes[name] = options.merge type: type
end

.attribute_type(attribute_name) ⇒ Object

Returns the type of the specified attribute.

Parameters:

  • attribute_name (Symbol)

    The name of the attribute to return the type for.

Returns:

  • The type of the specified attribute.


128
129
130
131
132
# File 'lib/ig_markets/model.rb', line 128

def attribute_type(attribute_name)
  return NilClass if Array(deprecated_attributes).include? attribute_name

  Hash(defined_attributes).fetch(attribute_name).fetch :type
end

.attribute_value_allowed?(attribute_name, value) ⇒ Boolean

Returns whether the passed value is allowed to set be set as the value of the specified attribute.

Parameters:

  • attribute_name (Symbol)
  • value

    The candidate attribute value.

Returns:

  • (Boolean)

    Whether the passed value is allowed for the attribute.


149
150
151
152
153
# File 'lib/ig_markets/model.rb', line 149

def attribute_value_allowed?(attribute_name, value)
  allowed_values = Hash(defined_attributes).fetch(attribute_name, {})[:allowed_values]

  value.nil? || allowed_values.nil? || allowed_values.include?(value)
end

.defined_attribute_namesArray<Symbol>

Returns the names of all currently defined attributes for this model.

Returns:

  • (Array<Symbol>)

102
103
104
# File 'lib/ig_markets/model.rb', line 102

def defined_attribute_names
  Hash(defined_attributes).keys
end

.deprecated_attribute(*names) ⇒ Object

Defines no-op setter, getter and sanitize methods for each of the passed attribute names. This is used to silently allow deprecated attributes to be used on the model but not have them be part of the model's structure.

Parameters:

  • names (Array<Symbol>)

    The names of the deprecated attributes.


184
185
186
187
188
189
190
191
192
# File 'lib/ig_markets/model.rb', line 184

def deprecated_attribute(*names)
  names.each do |name|
    define_method(name) {}
    define_method("#{name}=") { |_value| }
    define_singleton_method("sanitize_#{name}_value") { |value| value }

    (@deprecated_attributes ||= []) << name
  end
end

.valid_attribute?(name) ⇒ Boolean

Returns whether the passed value is a valid attribute name. If the passed attribute name is not recognized then an error will be printed to stderr. Only one warning will be printed for each unrecognized attribute.

Parameters:

  • name (Symbol)

    The candidate attribute name.

Returns:


112
113
114
115
116
117
118
119
120
121
# File 'lib/ig_markets/model.rb', line 112

def valid_attribute?(name)
  return true if defined_attribute_names.include?(name) || Array(deprecated_attributes).include?(name)

  unless Array(@reported_invalid_attributes).include? name
    warn "ig_markets: unrecognized attribute #{self}##{name}"
    (@reported_invalid_attributes ||= []) << name
  end

  false
end

Instance Method Details

#==(other) ⇒ Boolean

Compares this model to another, the attributes and class must match for them to be considered equal.

Parameters:

  • other (Model)

    The other model to compare to.

Returns:


41
42
43
# File 'lib/ig_markets/model.rb', line 41

def ==(other)
  self.class == other.class && to_h == other.to_h
end

#initialize_copy(other) ⇒ Object

Copy initializer that duplicates the #attributes hash in full.

Parameters:

  • other (Model)

    The model to copy.


30
31
32
33
34
# File 'lib/ig_markets/model.rb', line 30

def initialize_copy(other)
  super

  @attributes = other.attributes.dup
end

#inspectString

Returns a human-readable string containing this model's type and all its current attribute values.

Returns:

  • (String)

62
63
64
65
66
67
68
# File 'lib/ig_markets/model.rb', line 62

def inspect
  formatted_attributes = self.class.defined_attribute_names.map do |attribute|
    "#{attribute}: #{inspect_value send(attribute)}"
  end

  "#<#{self.class.name} #{formatted_attributes.join ', '}>"
end

#to_hHash

Converts this model into a nested hash of attributes. This is simlar to just calling #attributes, but in this case any attributes that are instances of IGMarkets::Model will also be transformed into a hash in the return value.

Returns:

  • (Hash)

49
50
51
52
53
54
55
56
57
# File 'lib/ig_markets/model.rb', line 49

def to_h
  attributes.each_with_object({}) do |(key, value), hash|
    hash[key] = if value.is_a? Model
                  value.to_h
                else
                  value
                end
  end
end