Class: Fin::Model

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/fin/models/model.rb

Overview

Represents business domain model for a single item (Quote, Deal, Instrument, etc…) Currently it is only used to extract common functionality from record wrappers, down the road the goal is to add ActiveModel compatibility

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Model

TODO: Builder pattern, to avoid args Array creation on each initialize?



101
102
103
104
105
106
# File 'lib/fin/models/model.rb', line 101

def initialize *args
  @attributes = {}
  opts = args.last.is_a?(Hash) ? args.pop : {}
  each_with_index { |(name, _), i| send "#{name}=", args[i] } unless args.empty?
  opts.each { |name, value| send "#{name}=", value }
end

Class Method Details

.attribute_typesObject



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

def self.attribute_types
  @attribute_types ||= (superclass.attribute_types.dup rescue {})
end

.from_msg(msg) ⇒ Object

Unpacks attributes into appropriate Model subclass



81
82
83
84
# File 'lib/fin/models/model.rb', line 81

def self.from_msg msg
  class_id = msg.first
  model_classes[class_id].new *msg[1..-1]
end

.from_record(rec) ⇒ Object



76
77
78
# File 'lib/fin/models/model.rb', line 76

def self.from_record rec
  new *extract_attributes(rec)
end

.model_class_id(value = nil) ⇒ Object



13
14
15
16
17
18
19
20
# File 'lib/fin/models/model.rb', line 13

def self.model_class_id value = nil
  if value
    @model_class_id ||= value
    model_classes[@model_class_id] = self
  else
    @model_class_id
  end
end

.model_classesObject



22
23
24
# File 'lib/fin/models/model.rb', line 22

def self.model_classes
  @model_classes ||= (superclass.model_classes rescue {}) #shared list for all subclasses
end

.property(prop_hash) ⇒ Object



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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/fin/models/model.rb', line 26

def self.property prop_hash
  prop_hash.each do |arg, type|
    aliases = [arg].flatten
    name = aliases.shift
    instance_eval do

      attribute_types[name.to_s] = type.to_s

      define_method(name) do
        @attributes[name]
      end

      define_method("#{name}=") do |value|
        @attributes[name] = value
      end

      aliases.each do |ali|
        alias_method "#{ali}", name
        alias_method "#{ali}=", "#{name}="
      end
    end
  end

  # Using static calls, create class method extracting attributes from raw records
  attribute_extractor = attribute_types.map do |name, type|
    case type
       # TODO: Using indexes (...ByIndex) instead of names gives ~60% speed boost
      when /^i[14]/
        "rec.GetValAsLong('#{name}')"
      when /^i8/
        "rec.GetValAsVariant('#{name}')"
      when /^[df]/
        "rec.GetValAsString('#{name}').to_f"
      when /^[c]/
        "rec.GetValAsString('#{name}')"
      when /^[t]/ # "2009/12/01 12:35:44.785" => 20091201123544785
        "rec.GetValAsVariant('#{name}')"
      else
        raise "Unrecognized attribute type: #{name} => #{type}"
    end
  end.join(",\n")

  extractor_body = "def self.extract_attributes rec
                      [#{attribute_extractor}]
                    end"

#      puts "In #{self}:, #{extractor_body"
  instance_eval extractor_body
end

.to_msg(rec) ⇒ Object

Extracts attributes from record into a serializable format (Array) Returns an Array where 1st element is a model_class_id of our Model subclass, followed by a list of arguments to its initialize. Class method!



89
90
91
# File 'lib/fin/models/model.rb', line 89

def self.to_msg rec
  extract_attributes(rec).unshift(model_class_id)
end

Instance Method Details

#eachObject Also known as: each_property



108
109
110
111
112
113
114
# File 'lib/fin/models/model.rb', line 108

def each
  if block_given?
    self.class.attribute_types.each { |name, _| yield [name, send(name)] }
  else
    self.class.attribute_types.map { |name, _| [name, send(name)].to_enum }
  end
end

#indexObject



131
132
133
# File 'lib/fin/models/model.rb', line 131

def index
  object_id # TODO: @repl_id?
end

#inspect(divider = ',') ⇒ Object



118
119
120
# File 'lib/fin/models/model.rb', line 118

def inspect divider=','
  map { |property, value| "#{property}=#{value}" }.join(divider)
end

#to_msgObject

Converts OBJECT attributes into a serializable format (Array) Returns an Array where 1st element is a model_class_id of our Model subclass, followed by a list of arguments to its initialize. Instance method!



96
97
98
# File 'lib/fin/models/model.rb', line 96

def to_msg
  inject([self.class.model_class_id]) { |array, (name, _)| array << send(name) }
end