class Vissen::Input::MessageFactory

The facatory takes raw input messages and builds matching objects around them. It stores a list of input matchers that it knows about.

If an array of matchers is passed to the constructor the MessageFactory will freeze itself to create an immutable factory.

TODO: Sort the matchers on input frequency for performance?

Usage

The following example sets up a factory to build ControlChange messages.

matcher = Message::ControlChange.matcher
factory = MessageFactory.new [matcher]

factory.build [0xC0, 3, 42], 0.0 # => Message::ControlChange
factory.build [0xB0, 0, 0], 0.0  # => Message::Unknown

Public Class Methods

new(matchers = nil) click to toggle source

@param matchers [nil, Array<Matcher>] the matchers to use when building

messages. If provided the factory will be frozen after creation.
# File lib/vissen/input/message_factory.rb, line 25
def initialize(matchers = nil)
  @lookup_table = Array.new(16) { [] }
  @matchers     = []

  return unless matchers

  matchers.each { |m| add_matcher m }
  freeze
end

Public Instance Methods

add_matcher(matcher) click to toggle source

Inserts another matcher to the list of known input data matchers.

@param matcher [Matcher] the matcher to add. @return [self]

# File lib/vissen/input/message_factory.rb, line 47
def add_matcher(matcher)
  raise TypeError unless matcher.is_a? Matcher
  @matchers << matcher
  self
end
build(obj, timestamp) click to toggle source

Creates a new Message object by matching the data against the stored message classes.

@param obj [#to_a] the data object to build the new message arround. @param timestamp [Float] the time that the message was first received. @return [Message]

# File lib/vissen/input/message_factory.rb, line 59
def build(obj, timestamp)
  data  = obj.to_a
  klass =
    if obj.is_a?(Message) && obj.valid?
      return obj if obj.timestamp == timestamp
      obj.class
    else
      matcher = lookup data
      matcher ? matcher.klass : Message::Unknown
    end

  klass.new data, timestamp
end
freeze() click to toggle source

Prevents any more matchers from being added.

@return [self]

Calls superclass method
# File lib/vissen/input/message_factory.rb, line 38
def freeze
  @matchers.freeze
  super
end

Private Instance Methods

lookup(data) click to toggle source
# File lib/vissen/input/message_factory.rb, line 75
def lookup(data)
  status  = data[0] >> 4
  entry   = @lookup_table[status]
  matcher = entry&.find { |m| m.match? data }

  unless matcher
    matcher = @matchers.find { |m| m.match? data }
    @lookup_table[status] << matcher if matcher
  end

  matcher
end