Class: Fix::Protocol::MessagePart

Inherits:
Object
  • Object
show all
Defined in:
lib/fix/protocol/message_part.rb

Overview

Basic building block for messages. Message parts can define fields, sub-parts and collections

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ MessagePart

Returns a new instance of MessagePart.



13
14
15
16
# File 'lib/fix/protocol/message_part.rb', line 13

def initialize(opts = {})
  self.name = opts[:name]
  self.class.structure.each { |node| initialize_node(node) }
end

Instance Attribute Details

#nameObject

Returns the value of attribute name.



11
12
13
# File 'lib/fix/protocol/message_part.rb', line 11

def name
  @name
end

#parse_failureObject

Returns the value of attribute parse_failure.



11
12
13
# File 'lib/fix/protocol/message_part.rb', line 11

def parse_failure
  @parse_failure
end

Class Method Details

.collection(name, opts = {}) ⇒ Object

Defines a collection as a part of this message part, collections typically have a counter and a repeating element

Parameters:

  • name (String)

    The collection name, this will be the name of a dynamically created accessor on the message part

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

    The required options are :counter_tag and :klass



102
103
104
105
106
107
108
# File 'lib/fix/protocol/message_part.rb', line 102

def self.collection(name, opts = {})
  structure << { node_type: :collection, name: name, counter_tag: opts[:counter_tag], klass: opts[:klass] }

  define_method(name) do
    node_for_name(name)
  end
end

.field(name, opts) ⇒ Object

Defines a field as part of the structure for this class

Parameters:

  • name (String)

    The field name, this will be the base name of a set of methods created on the class instances

  • opts (Hash)

    Options hash



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/fix/protocol/message_part.rb', line 130

def self.field(name, opts)
  structure << { node_type: :field, name: name }.merge(opts)

  # Getter
  define_method(name) do
    node_for_name(name).value
  end

  # Setter
  define_method("#{name}=") do |val|
    node_for_name(name).value = val
  end

  if opts[:mapping]
    define_method("raw_#{name}") do
      node_for_name(name).raw_value
    end

    define_method("raw_#{name}=") do |val|
      node_for_name(name).raw_value = val
    end
  end
end

.inherited(klass) ⇒ Object

Inherits the @structure class instance variable but allows the child to modify it without impacting the parent, this allows for message structure refinement



23
24
25
# File 'lib/fix/protocol/message_part.rb', line 23

def self.inherited(klass)
  klass.send(:instance_variable_set, :@structure, structure.dup)
end

.parse(str) ⇒ Object

Class-level shortcut to directly parse an instance of a specific message part subclass



90
91
92
93
94
# File 'lib/fix/protocol/message_part.rb', line 90

def self.parse(str)
  instce = new
  instce.parse(str)
  instce
end

.part(name, opts = {}) ⇒ Object

Defines a reusable message part as element of this particular class

Parameters:

  • name (String)

    The part name, this will be the name of a dynamically created accessor on the message part

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

    Options hash



116
117
118
119
120
121
122
# File 'lib/fix/protocol/message_part.rb', line 116

def self.part(name, opts = {})
  structure << { node_type: :part, name: name }.merge(opts)

  define_method(name) do
    node_for_name(name)
  end
end

.structureArray

Returns this message part class’ structure

Returns:

  • (Array)

    The message structure



159
160
161
# File 'lib/fix/protocol/message_part.rb', line 159

def self.structure
  @structure ||= []
end

Instance Method Details

#dumpString

Dumps this message part as a FIX message fragment

Returns:

  • (String)

    A FIX message fragment



32
33
34
# File 'lib/fix/protocol/message_part.rb', line 32

def dump
  nodes.map(&:dump).join
end

#errorsArray

Returns the errors for this instance

Returns:

  • (Array)

     The errors for this instance



168
169
170
# File 'lib/fix/protocol/message_part.rb', line 168

def errors
  [nodes.map(&:errors), nodes.map(&:parse_failure)].flatten.compact
end

#initialize_node(node) ⇒ Object

Initializes a node depending on its type, this is called when initializing a message part instance by the constructor. Usually one node is initialized for each structure element



58
59
60
61
62
63
64
65
66
# File 'lib/fix/protocol/message_part.rb', line 58

def initialize_node(node)
  if node[:node_type] == :part
    nodes << node[:klass].new(node)
  elsif node[:node_type] == :field
    nodes << FP::Field.new(node)
  elsif node[:node_type] == :collection
    nodes << FP::RepeatingMessagePart.new(node)
  end
end

#node_for_name(n) ⇒ Object

Searches the immediate hierarchy by node name to return the requested node

Parameters:

  • n (String)

    The node name to look for

Returns:

  • (Object)

    The found node, if any



83
84
85
# File 'lib/fix/protocol/message_part.rb', line 83

def node_for_name(n)
  nodes.find { |node| node.name.to_s == n.to_s }
end

#nodesArray

The message part nodes, they’ll be either a FP::Field, an FP::RepeatingMessagePart or a FP::MessagePart

Returns:

  • (Array)

    The nodes for this message part



73
74
75
# File 'lib/fix/protocol/message_part.rb', line 73

def nodes
  @nodes ||= []
end

#parse(str) ⇒ String

Parses a full or partial FIX message string into the message part nodes

Returns:

  • (String)

    The string part that wasn’t consumed during the parsing



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/fix/protocol/message_part.rb', line 41

def parse(str)
  left_to_parse = str

  nodes.each do |node|
    unless parse_failure
      left_to_parse = node.parse(left_to_parse)
      self.parse_failure = node.parse_failure
    end
  end

  left_to_parse
end