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
@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
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
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
Prevents any more matchers from being added.
@return [self]
# File lib/vissen/input/message_factory.rb, line 38 def freeze @matchers.freeze super end
Private Instance Methods
# 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