Module: Quant::Attributes

Included in:
Indicators::IndicatorPoint
Defined in:
lib/quant/attributes.rb

Overview

Attributes is similar to an attr_accessor definition. It provides a simple DSL for defining attributes or properies on an Indicators::IndicatorPoint class.

Attributes tracks all defined attributes from child to parent classes, allowing child classes to inherit their parent’s attributes as well as redefine them.

The exception on redefining is that a serialized key cannot be redefined. Experience has proven that this leads to serialization surprises where what was written to a specific key is not what was expected!

NOTE: The above design constraint could be improved with a force or overwrite option.

If :default is an immediate value (Integer, Float, Boolean, etc.), it will be used as the initial value for the attribute. If :default is a Symbol, it will send a message on current instance of the class get the default value.

Examples:

class FooPoint < IndicatorPoint
  # will not serialize to a key
  attribute :bar
  # serializes to "bzz" key
  attribute :baz, key: "bzz"
  # calls the random method on the instance for the default value
  attribute :foobar, default: :random
  # delegated to the tick's high_price method
  attribute :high, default: :high_price
  # calls the lambda bound to instance for default
  attribute :low, default: -> { high_price - 5 }

  def random
    rand(100)
  end
end

class BarPoint < FooPoint
  attribute :bar, key: "brr"                 # redefines and sets the key for bar
  attribute :qux, key: "qxx", default: 5.0   # serializes to "qxx" and defaults to 5.0
end

FooPoint.attributes
# => { bar: { key: nil, default: nil },
       baz: { key: "bzz", default: nil } }

BarPoint.attributes
# => { bar: { key: "brr", default: nil },
#      baz: { key: "bzz", default: nil },
#      qux: { key: "qxx", default: nil } }

BarPoint.new.bar # => nil
BarPoint.new.qux # => 5.0
BarPoint.new.bar = 2.0 => 2.0

Defined Under Namespace

Modules: ClassMethods, InstanceMethods

Class Method Summary collapse

Class Method Details

.deregister(klass) ⇒ Object

Removes the given class from the registry. Useful for testing.



77
78
79
# File 'lib/quant/attributes.rb', line 77

def self.deregister(klass)
  registry.delete(klass)
end

.included(base) ⇒ Object

:nodoc:



201
202
203
204
# File 'lib/quant/attributes.rb', line 201

def self.included(base) # :nodoc:
  base.extend(ClassMethods)
  base.prepend(InstanceMethods)
end

.register(klass, name, key, default) ⇒ Object

Registers an attribute for a class in the registry. Internal use only.

Parameters:

  • klass (Class)

    The class registering the attribute

  • name (Symbol)

    The name of the attribute

  • key (String)

    The key to use when serializing the attribute

  • default (Object)

    The default value for the attribute



88
89
90
91
92
93
94
95
96
97
# File 'lib/quant/attributes.rb', line 88

def self.register(klass, name, key, default)
  # Disallow redefining or replacing a key as it is easy to miss the overwrite
  # and leads to serialization surprises.
  if key && registry.values.flat_map(&:values).map{ |entry| entry[:key] }.include?(key)
    raise Errors::DuplicateAttributesKeyError, "Attribute Key #{key} already defined!"
  end

  registry[klass] ||= {}
  registry[klass][name] = { key:, default: }
end

.registryHash

The registry key is the class registering an attrbritute and is itself a hash of the attribute name and the attribute’s key and default value. Internal use only.

Examples:

{ Quant::Indicators::IndicatorPoint => {
    tick: { key: nil, default: nil },
    source: { key: "src", default: nil },
    input: { key: "in", default: nil }
  },
  Quant::Indicators::PingPoint => {
    pong: { key: nil, default: nil },
    compute_count: { key: nil, default: 0 }
  }
}

Returns:

  • (Hash)

    The registry of all defined attributes.



72
73
74
# File 'lib/quant/attributes.rb', line 72

def self.registry
  @registry ||= {}
end