Class: NMEAPlus::MessageFactory Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/nmea_plus/message_factory.rb

Overview

This class is abstract.

MessageFactory is meant to be extended by actual implementations of message parsing classes

The base class for MessageFactory objects, which are instantiated in the Parser. MessageFactory objects create message classes with a common prefix and variable suffix. In an NMEA example, the prefix might be GP and the suffixes might be AAM or GLL (making GPAAM and GPGLL).

If you are creating more subclasses of MessageFactory, you are probably a developer adding more NMEA-style message factories to the parser, and you are working with the repo (not the gem).

Direct Known Subclasses

AISMessageFactory, NMEAMessageFactory

Class Method Summary collapse

Class Method Details

.alternate_data_type(data_type) ⇒ Array

This method is abstract.

Sometimes we want to override the data_type specified in the message (e.g. __AAM) with an alternate type (like GPAAM) or a generic type (like AAM). This is where we put that logic.

Parameters:

  • data_type (String)

    The data_type of the NMEA message (e.g. the GPGLL of “$GPGLL,12,3,,4,5*00”)

Returns:

  • (Array)

    Array of data_type strings that we will attempt to use in decoding the message



25
26
27
# File 'lib/nmea_plus/message_factory.rb', line 25

def self.alternate_data_type(data_type)
  [data_type] # in basic implementation, there is no alternative.
end

.best_match_for_data_type(data_type) ⇒ String

Try to load a class for the data_type specified in the message. If it doesn’t exist, then try an alternate. If that doesn’t work, fail.

Parameters:

  • data_type (String)

    The data type for a given message

Returns:

  • (String)

    The fully qualified message class name



50
51
52
53
54
55
56
# File 'lib/nmea_plus/message_factory.rb', line 50

def self.best_match_for_data_type(data_type)
  return data_type if self.message_class_exists?(self.message_class_name(data_type))
  self.alternate_data_type(data_type).each do |alternate_type|
    return alternate_type if self.message_class_exists?(self.message_class_name(alternate_type))
  end
  data_type
end

.create(message_prefix, fields, checksum) ⇒ NMEAPlus::Message

Choose what message class to create, and create it based on the first of the (unsplitted) fields – which is the data_type

Parameters:

  • message_prefix (String)

    The single-character prefix for this message type (e.g. “$”, “!”)

  • fields (String)

    The entire payload of the message

  • checksum (String)

    The two-character checksum of the message

Returns:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/nmea_plus/message_factory.rb', line 73

def self.create(message_prefix, fields, checksum)
  # get the data type and adjust it if necessary (e.g. support for NMEA standard sentences like __AAM)
  data_type = fields.split(',', 2)[0].upcase  # assumed to be 'GPGGA', etc
  interpreted_type = self.best_match_for_data_type(data_type)
  class_name = self.message_class_name(interpreted_type)

  # create message and make sure it's the right type
  message = self.dynamically_get_message_object(class_name)
  unless message.is_a? NMEAPlus::Message::Base
    raise ArgumentError, "Undefined message type #{data_type} (classname #{class_name})"
  end

  # assign its data and return it
  message.checksum = checksum
  message.payload = fields
  message.prefix = message_prefix
  message.interpreted_data_type = interpreted_type
  message
end

.dynamically_get_message_object(class_identifier) ⇒ Object

Get a message class through reflection

Parameters:

  • class_identifier (String)

    the fully-qualified name of the class to instantiate

Returns:

  • (Object)

    The object for that class string



61
62
63
64
65
# File 'lib/nmea_plus/message_factory.rb', line 61

def self.dynamically_get_message_object(class_identifier)
  Object::const_get(class_identifier).new
rescue ::NameError => e
  raise ::NameError, "Couldn't instantiate a #{class_identifier} object: #{e}"
end

.message_class_exists?(class_identifier) ⇒ bool

Check whether a given object exists. this will work for all consts but shhhhhhhhh

Parameters:

  • class_identifier (String)

    The name of a ruby class

Returns:

  • (bool)


32
33
34
35
36
37
# File 'lib/nmea_plus/message_factory.rb', line 32

def self.message_class_exists?(class_identifier)
  Object::const_get(class_identifier)
  return true
rescue ::NameError
  return false
end

.message_class_name(data_type) ⇒ String

Shortcut for the full name to a message class built from this factory.

Parameters:

  • data_type (String)

Returns:

  • (String)

    The fully qualified message class name



42
43
44
# File 'lib/nmea_plus/message_factory.rb', line 42

def self.message_class_name(data_type)
  "NMEAPlus::Message::#{self.parent_module}::#{data_type}"
end

.parent_moduleString

This method is abstract.

For dynamic loading purposes. Don’t mess this up!

Returns:

  • (String)

    The name of the parent module



16
17
18
# File 'lib/nmea_plus/message_factory.rb', line 16

def self.parent_module
  "FIXME_parent_module"
end