Esempio n. 1
0
def srv_generator(msg_context, spec, search_path):
    for mspec in (spec.request, spec.response):
        for l in msg_generator(msg_context, mspec, search_path):
            yield l

    name = spec.short_name
    req, resp = ["%s%s"%(name, suff) for suff in ['Request', 'Response']]

    fulltype = spec.full_name

    genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    md5 = genmsg.compute_md5(msg_context, spec)
    yield "module %s\n"%spec.package.capitalize()
    yield "class %s\n"%name
    yield """  def self.type
    '%s'
  end
"""%fulltype
    yield """  def self.md5sum
    '%s'
  end
"""%md5
    yield """  def self.request_class
    %s
  end
"""%req
    yield """  def self.response_class
    %s
  end
end
end"""%resp
Esempio n. 2
0
 def __init__(self, msg_context, spec, search_path):
     self.msg_context = msg_context
     self.spec = spec
     self.search_path = search_path
     self.name = spec.short_name
     self.pkg = spec.package
     self.md5 = genmsg.compute_md5(msg_context, spec)
Esempio n. 3
0
def srv_generator(msg_context, spec, search_path):
    for mspec in (spec.request, spec.response):
        for l in msg_generator(msg_context, mspec, search_path):
            yield l

    name = spec.short_name
    req, resp = ["%s%s" % (name, suff) for suff in ['Request', 'Response']]

    fulltype = spec.full_name

    genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    md5 = genmsg.compute_md5(msg_context, spec)
    yield "module %s\n" % spec.package.capitalize()
    yield "class %s\n" % name
    yield """  def self.type
    '%s'
  end
""" % fulltype
    yield """  def self.md5sum
    '%s'
  end
""" % md5
    yield """  def self.request_class
    %s
  end
""" % req
    yield """  def self.response_class
    %s
  end
end
end""" % resp
Esempio n. 4
0
def _compute_md5(msg_context, f):
    from genmsg import load_depends, compute_md5
    from genmsg.msg_loader import load_msg_from_string

    text = open(f, 'r').read()
    short_name = os.path.basename(f)[:-len('.msg')]
    full_name = "%s/%s"%(TEST_CTX, short_name)
    spec = load_msg_from_string(msg_context, text, full_name)
    search_path = get_search_path()
    load_depends(msg_context, spec, search_path)
    return compute_md5(msg_context, spec)
Esempio n. 5
0
def _compute_md5(msg_context, f):
    from genmsg import load_depends, compute_md5
    from genmsg.msg_loader import load_msg_from_string

    text = open(f, 'r').read()
    short_name = os.path.basename(f)[:-len('.msg')]
    full_name = "%s/%s" % (TEST_CTX, short_name)
    spec = load_msg_from_string(msg_context, text, full_name)
    search_path = get_search_path()
    load_depends(msg_context, spec, search_path)
    return compute_md5(msg_context, spec)
Esempio n. 6
0
def srv_generator(msg_context, spec, search_path):
    for mspec in (spec.request, spec.response):
        for l in msg_generator(msg_context, mspec, search_path):
            yield l

    name = spec.short_name
    req, resp = ["%s%s"%(name, suff) for suff in ['Request', 'Response']]

    fulltype = spec.full_name

    genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    md5 = genmsg.compute_md5(msg_context, spec)

    yield "class %s(object):"%name
    yield "  _type          = '%s'"%fulltype
    yield "  _md5sum = '%s'"%md5
    yield "  _request_class  = %s"%req
    yield "  _response_class = %s"%resp
Esempio n. 7
0
def srv_generator(msg_context, spec, search_path):
    for mspec in (spec.request, spec.response):
        for l in msg_generator(msg_context, mspec, search_path):
            yield l

    name = spec.short_name
    req, resp = ["%s%s" % (name, suff) for suff in ["Request", "Response"]]

    fulltype = spec.full_name

    genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    md5 = genmsg.compute_md5(msg_context, spec)

    yield "class %s(object):" % name
    yield "  _type          = '%s'" % fulltype
    yield "  _md5sum = '%s'" % md5
    yield "  _request_class  = %s" % req
    yield "  _response_class = %s" % resp
Esempio n. 8
0
def msg_generator(msg_context, spec, search_path):
    """
    Python code generator for .msg files. Generates a Python from a
     :class:`genmsg.MsgSpec`.

    :param spec: parsed .msg :class:`genmsg.MsgSpec` instance
    :param search_path: dictionary mapping message namespaces to a directory locations
    """

    # #2990: have to compute md5sum before any calls to make_python_safe

    # generate dependencies dictionary. omit files calculation as we
    # rely on in-memory MsgSpecs instead so that we can generate code
    # for older versions of msg files
    try:
        genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    except InvalidMsgSpec as e:
        raise MsgGenerationException("Cannot generate .msg for %s/%s: %s"%(package, name, str(e)))
    md5sum = genmsg.compute_md5(msg_context, spec)

    # remap spec names to be Python-safe
    spec = make_python_safe(spec)
    spec_names = spec.names

    # #1807 : this will be much cleaner when msggenerator library is
    # rewritten to not use globals
    clear_patterns()

    yield '# This Python file uses the following encoding: utf-8'
    yield '"""autogenerated by genpy from %s.msg. Do not edit."""'%spec.full_name
    yield 'import sys'
    yield 'python3 = True if sys.hexversion > 0x03000000 else False'
    yield 'import genpy\nimport struct\n'
    import_strs = []
    for t in spec.types:
        import_strs.extend(compute_import(msg_context, spec.package, t))
    import_strs = set(import_strs)
    for i in import_strs:
        if i:
            yield i

    yield ''

    fulltype = spec.full_name
    name = spec.short_name

    #Yield data class first, e.g. Point2D
    yield 'class %s(genpy.Message):'%spec.short_name
    yield '  _md5sum = "%s"'%(md5sum)
    yield '  _type = "%s"'%(fulltype)
    yield '  _has_header = %s #flag to mark the presence of a Header object'%spec.has_header()
    
    full_text = compute_full_text_escaped(msg_context, spec)
    # escape trailing double-quote, unless already escaped, before wrapping in """
    if full_text.endswith('"') and not full_text.endswith(r'\"'):
        full_text = full_text[:-1] + r'\"'
    yield '  _full_text = """%s"""'%full_text

    if spec.constants:
        yield '  # Pseudo-constants'
        for c in spec.constants:
            if c.type == 'string':
                val = c.val
                if '"' in val and "'" in val:
                    # crude escaping of \ and "
                    escaped = c.val.replace('\\', '\\\\')
                    escaped = escaped.replace('\"', '\\"')
                    yield '  %s = "%s"'%(c.name, escaped)
                elif '"' in val: #use raw encoding for prettiness
                    yield "  %s = r'%s'"%(c.name, val)
                elif "'" in val: #use raw encoding for prettiness
                    yield '  %s = r"%s"'%(c.name, val)
                else:
                    yield "  %s = '%s'"%(c.name, val)
            else:
                yield '  %s = %s'%(c.name, c.val)
        yield ''

    if len(spec_names):
        yield "  __slots__ = ['"+"','".join(spec_names)+"']"
        yield "  _slot_types = ['"+"','".join(spec.types)+"']"
    else:
        yield "  __slots__ = []"
        yield "  _slot_types = []"

    yield """
  def __init__(self, *args, **kwds):
    \"\"\"
    Constructor. Any message fields that are implicitly/explicitly
    set to None will be assigned a default value. The recommend
    use is keyword arguments as this is more robust to future message
    changes.  You cannot mix in-order arguments and keyword arguments.

    The available fields are:
       %s

    :param args: complete set of field values, in .msg order
    :param kwds: use keyword arguments corresponding to message field names
    to set specific fields.
    \"\"\"
    if args or kwds:
      super(%s, self).__init__(*args, **kwds)"""%(','.join(spec_names), name)

    if len(spec_names):
        yield "      #message fields cannot be None, assign default values for those that are"
        for (t, s) in zip(spec.types, spec_names):
            yield "      if self.%s is None:"%s
            yield "        self.%s = %s"%(s, default_value(msg_context, t, spec.package))
    if len(spec_names) > 0:
      yield "    else:"
      for (t, s) in zip(spec.types, spec_names):
          yield "      self.%s = %s"%(s, default_value(msg_context, t, spec.package))

    yield """
  def _get_types(self):
    \"\"\"
    internal API method
    \"\"\"
    return self._slot_types

  def serialize(self, buff):
    \"\"\"
    serialize message into buffer
    :param buff: buffer, ``StringIO``
    \"\"\""""
    for y in serialize_fn_generator(msg_context, spec):
        yield "    "+ y
    yield """
  def deserialize(self, str):
    \"\"\"
    unpack serialized message in str into this message instance
    :param str: byte array of serialized message, ``str``
    \"\"\""""
    for y in deserialize_fn_generator(msg_context, spec):
        yield "    " + y
    yield ""

    yield """
  def serialize_numpy(self, buff, numpy):
    \"\"\"
    serialize message with numpy array types into buffer
    :param buff: buffer, ``StringIO``
    :param numpy: numpy python module
    \"\"\""""
    for y in serialize_fn_generator(msg_context, spec, is_numpy=True):
        yield "    "+ y
    yield """
  def deserialize_numpy(self, str, numpy):
    \"\"\"
    unpack serialized message in str into this message instance using numpy for array types
    :param str: byte array of serialized message, ``str``
    :param numpy: numpy python module
    \"\"\""""
    for y in deserialize_fn_generator(msg_context, spec, is_numpy=True):
        yield "    " + y
    yield ""


    # #1807 : this will be much cleaner when msggenerator library is
    # rewritten to not use globals
    yield '_struct_I = genpy.struct_I'
    yield 'def _get_struct_I():'
    yield '    global _struct_I'
    yield '    return _struct_I'
    patterns = get_patterns()
    for p in set(patterns):
        # I patterns are already optimized
        if p == 'I':
            continue
        var_name = '_struct_%s'%(p.replace('<',''))
        yield '%s = None' % var_name
        yield 'def _get%s():' % var_name
        yield '    global %s' % var_name
        yield '    if %s is None:' % var_name
        yield '        %s = struct.Struct("<%s")' % (var_name, p)
        yield '    return %s' % var_name
    clear_patterns()
Esempio n. 9
0
def msg_generator(msg_context, spec, search_path):
    """
    Python code generator for .msg files. Generates a Python from a
     :class:`genmsg.MsgSpec`.

    :param spec: parsed .msg :class:`genmsg.MsgSpec` instance
    :param search_path: dictionary mapping message namespaces to a directory locations
    """

    # #2990: have to compute md5sum before any calls to make_python_safe

    # generate dependencies dictionary. omit files calculation as we
    # rely on in-memory MsgSpecs instead so that we can generate code
    # for older versions of msg files
    try:
        genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    except InvalidMsgSpec as e:
        raise MsgGenerationException("Cannot generate .msg for %s/%s: %s" % (package, name, str(e)))
    md5sum = genmsg.compute_md5(msg_context, spec)

    # remap spec names to be Python-safe
    spec = make_python_safe(spec)
    spec_names = spec.names

    # #1807 : this will be much cleaner when msggenerator library is
    # rewritten to not use globals
    clear_patterns()

    yield '"""autogenerated by genpy from %s.msg. Do not edit."""' % spec.full_name
    yield "import sys"
    yield "python3 = True if sys.hexversion > 0x03000000 else False"
    yield "import genpy\nimport struct\n"
    import_strs = []
    for t in spec.types:
        import_strs.extend(compute_import(msg_context, spec.package, t))
    import_strs = set(import_strs)
    for i in import_strs:
        if i:
            yield i

    yield ""

    fulltype = spec.full_name
    name = spec.short_name

    # Yield data class first, e.g. Point2D
    yield "class %s(genpy.Message):" % spec.short_name
    yield '  _md5sum = "%s"' % (md5sum)
    yield '  _type = "%s"' % (fulltype)
    yield "  _has_header = %s #flag to mark the presence of a Header object" % spec.has_header()
    # note: we introduce an extra newline to protect the escaping from quotes in the message
    yield '  _full_text = """%s\n"""' % compute_full_text_escaped(msg_context, spec)

    if spec.constants:
        yield "  # Pseudo-constants"
        for c in spec.constants:
            if c.type == "string":
                val = c.val
                if '"' in val and "'" in val:
                    # crude escaping of \ and "
                    escaped = c.val.replace("\\", "\\\\")
                    escaped = escaped.replace('"', '\\"')
                    yield '  %s = "%s"' % (c.name, escaped)
                elif '"' in val:  # use raw encoding for prettiness
                    yield "  %s = r'%s'" % (c.name, val)
                elif "'" in val:  # use raw encoding for prettiness
                    yield '  %s = r"%s"' % (c.name, val)
                else:
                    yield "  %s = '%s'" % (c.name, val)
            else:
                yield "  %s = %s" % (c.name, c.val)
        yield ""

    if len(spec_names):
        yield "  __slots__ = ['" + "','".join(spec_names) + "']"
        yield "  _slot_types = ['" + "','".join(spec.types) + "']"
    else:
        yield "  __slots__ = []"
        yield "  _slot_types = []"

    yield """
  def __init__(self, *args, **kwds):
    \"\"\"
    Constructor. Any message fields that are implicitly/explicitly
    set to None will be assigned a default value. The recommend
    use is keyword arguments as this is more robust to future message
    changes.  You cannot mix in-order arguments and keyword arguments.

    The available fields are:
       %s

    :param args: complete set of field values, in .msg order
    :param kwds: use keyword arguments corresponding to message field names
    to set specific fields.
    \"\"\"
    if args or kwds:
      super(%s, self).__init__(*args, **kwds)""" % (
        ",".join(spec_names),
        name,
    )

    if len(spec_names):
        yield "      #message fields cannot be None, assign default values for those that are"
        for (t, s) in zip(spec.types, spec_names):
            yield "      if self.%s is None:" % s
            yield "        self.%s = %s" % (s, default_value(msg_context, t, spec.package))
    if len(spec_names) > 0:
        yield "    else:"
        for (t, s) in zip(spec.types, spec_names):
            yield "      self.%s = %s" % (s, default_value(msg_context, t, spec.package))

    yield """
  def _get_types(self):
    \"\"\"
    internal API method
    \"\"\"
    return self._slot_types

  def serialize(self, buff):
    \"\"\"
    serialize message into buffer
    :param buff: buffer, ``StringIO``
    \"\"\""""
    for y in serialize_fn_generator(msg_context, spec):
        yield "    " + y
    yield """
  def deserialize(self, str):
    \"\"\"
    unpack serialized message in str into this message instance
    :param str: byte array of serialized message, ``str``
    \"\"\""""
    for y in deserialize_fn_generator(msg_context, spec):
        yield "    " + y
    yield ""

    yield """
  def serialize_numpy(self, buff, numpy):
    \"\"\"
    serialize message with numpy array types into buffer
    :param buff: buffer, ``StringIO``
    :param numpy: numpy python module
    \"\"\""""
    for y in serialize_fn_generator(msg_context, spec, is_numpy=True):
        yield "    " + y
    yield """
  def deserialize_numpy(self, str, numpy):
    \"\"\"
    unpack serialized message in str into this message instance using numpy for array types
    :param str: byte array of serialized message, ``str``
    :param numpy: numpy python module
    \"\"\""""
    for y in deserialize_fn_generator(msg_context, spec, is_numpy=True):
        yield "    " + y
    yield ""

    # #1807 : this will be much cleaner when msggenerator library is
    # rewritten to not use globals
    yield "_struct_I = genpy.struct_I"
    patterns = get_patterns()
    for p in set(patterns):
        # I patterns are already optimized
        if p == "I":
            continue
        var_name = "_struct_%s" % (p.replace("<", ""))
        yield '%s = struct.Struct("<%s")' % (var_name, p)
    clear_patterns()
Esempio n. 10
0
def msg_generator_internal(msg_context, spec, search_path):
    """
    Python code generator for .msg files. Takes in a package name,
    message name, and message specification and generates a Python
    message class.

    @param package: name of package for message
    @type  package: str
    @param name: base type name of message, e.g. 'Empty', 'String'
    @type  name: str
    @param spec: parsed .msg specification
    @type  spec: L{MsgSpec}
    """

    # #2990: have to compute md5sum before any calls to make_python_safe

    # generate dependencies dictionary. omit files calculation as we
    # rely on in-memory MsgSpecs instead so that we can generate code
    # for older versions of msg files
    try:
        genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    except InvalidMsgSpec as e:
        raise MsgGenerationException("Cannot generate .msg for %s/%s: %s"%(package, name, str(e)))
    md5sum = genmsg.compute_md5(msg_context, spec)

    # remap spec names to be Python-safe
    spec = make_ruby_safe(spec)
    spec_names = spec.names

    # for not capital class like tfMessages
    name = spec.short_name
    capitalized_name = name[0].upper() + name[1:]

    # #1807 : this will be much cleaner when msggenerator library is
    # rewritten to not use globals
    clear_patterns()

    yield '# autogenerated by genrb from %s.msg. Do not edit.'%name
    yield "require 'ros/message'\n"
    import_strs = []
    for t in spec.types:
        import_strs.extend(compute_import(msg_context, spec.package, t))
    import_strs = set(import_strs)
    for i in import_strs:
        if i:
            yield i

    yield ''

    yield "module %s\n"%spec.package.capitalize()

    fulltype = '%s%s%s'%(spec.package, genmsg.SEP, name)

    #Yield data class first, e.g. Point2D
    yield 'class %s <::ROS::Message'%capitalized_name

    yield """  def self.md5sum
    \"%s\"
  end
"""%(md5sum)
    yield """  def self.type
    \"%s\"
  end
"""%(fulltype)
    if spec.has_header():
        bool_val = 'true'
    else:
        bool_val = 'false'
    yield """  def has_header?
    %s
  end
"""%bool_val
    # note: we introduce an extra newline to protect the escaping from quotes in the message
    yield """  def message_definition
    \"%s\n\"
  end"""%compute_full_text_escaped(msg_context, spec)

    if spec.constants:
        yield '  # Pseudo-constants'
        for c in spec.constants:
            if c.type == 'string':
                val = c.val
                if '"' in val and "'" in val:
                    # crude escaping of \ and "
                    escaped = c.val.replace('\\', '\\\\')
                    escaped = escaped.replace('\"', '\\"')
                    yield '  %s = "%s"'%(c.name, escaped)
                elif '"' in val: #use raw encoding for prettiness
                    yield "  %s = r'%s'"%(c.name, val)
                elif "'" in val: #use raw encoding for prettiness
                    yield '  %s = r"%s"'%(c.name, val)
                else:
                    yield "  %s = '%s'"%(c.name, val)
            else:
                yield '  %s = %s'%(c.name, c.val)
        yield ''
    yield "  attr_accessor "+", ".join([":"+x for x in spec_names])+"\n"

    yield '_REPLACE_FOR_STRUCT_'
    if len(spec_names):
        yield "  @@struct_L = ::ROS::Struct.new(\"L\")"
        yield "  @@slot_types = ['"+"','".join(spec.types)+"']"
    else:
        yield "  @@struct_L = ::ROS::Struct.new(\"L\")"
        yield "  @@slot_types = []"

    yield """
  # Constructor. You can set the default values using keyword operators.
  #
  # @param [Hash] args keyword for initializing values"""
    for (t, s) in zip(spec.types, spec_names):
        yield "  # @option args [%s] :%s initialize value"%(t, s)
    yield "  def initialize(args={})"
    if len(spec_names):
        yield "    # message fields cannot be None, assign default values for those that are"
    if len(spec_names) > 0:
      for (t, s) in zip(spec.types, spec_names):
        yield """    if args[:%s]
      @%s = args[:%s]
    else"""%(s, s, s)
        yield "      @%s = %s"%(s, default_value(msg_context, t, spec.package))
        yield "    end"
    yield "  end" # end of initialize

    yield """
  # internal API method
  # @return [String] Message type string.
  def _get_types
    @slot_types
  end

  # serialize message into buffer
  # @param [IO] buff buffer
  def serialize(buff)"""
    for y in serialize_fn_generator(msg_context, spec):
        yield "    "+ y
    yield "  end"
    yield """
  #  unpack serialized message in str into this message instance
  #  @param [String] str: byte array of serialized message
  def deserialize(str)
"""
    for y in deserialize_fn_generator(msg_context, spec):
        yield "    " + y
    yield "  end"
    yield "end # end of class"
    yield "end # end of module"
Esempio n. 11
0
def msg_generator_internal(msg_context, spec, search_path):
    """
    Python code generator for .msg files. Takes in a package name,
    message name, and message specification and generates a Python
    message class.

    @param package: name of package for message
    @type  package: str
    @param name: base type name of message, e.g. 'Empty', 'String'
    @type  name: str
    @param spec: parsed .msg specification
    @type  spec: L{MsgSpec}
    """

    # #2990: have to compute md5sum before any calls to make_python_safe

    # generate dependencies dictionary. omit files calculation as we
    # rely on in-memory MsgSpecs instead so that we can generate code
    # for older versions of msg files
    try:
        genmsg.msg_loader.load_depends(msg_context, spec, search_path)
    except InvalidMsgSpec as e:
        raise MsgGenerationException("Cannot generate .msg for %s/%s: %s" %
                                     (package, name, str(e)))
    md5sum = genmsg.compute_md5(msg_context, spec)

    # remap spec names to be Python-safe
    spec = make_ruby_safe(spec)
    spec_names = spec.names

    # for not capital class like tfMessages
    name = spec.short_name
    capitalized_name = name[0].upper() + name[1:]

    # #1807 : this will be much cleaner when msggenerator library is
    # rewritten to not use globals
    clear_patterns()

    yield '# autogenerated by genrb from %s.msg. Do not edit.' % name
    yield "require 'ros/message'\n"
    import_strs = []
    for t in spec.types:
        import_strs.extend(compute_import(msg_context, spec.package, t))
    import_strs = set(import_strs)
    for i in import_strs:
        if i:
            yield i

    yield ''

    yield "module %s\n" % spec.package.capitalize()

    fulltype = '%s%s%s' % (spec.package, genmsg.SEP, name)

    #Yield data class first, e.g. Point2D
    yield 'class %s <::ROS::Message' % capitalized_name

    yield """  def self.md5sum
    \"%s\"
  end
""" % (md5sum)
    yield """  def self.type
    \"%s\"
  end
""" % (fulltype)
    if spec.has_header():
        bool_val = 'true'
    else:
        bool_val = 'false'
    yield """  def has_header?
    %s
  end
""" % bool_val
    # note: we introduce an extra newline to protect the escaping from quotes in the message
    yield """  def message_definition
    \"%s\n\"
  end""" % compute_full_text_escaped(msg_context, spec)

    if spec.constants:
        yield '  # Pseudo-constants'
        for c in spec.constants:
            if c.type == 'string':
                val = c.val
                if '"' in val and "'" in val:
                    # crude escaping of \ and "
                    escaped = c.val.replace('\\', '\\\\')
                    escaped = escaped.replace('\"', '\\"')
                    yield '  %s = "%s"' % (c.name, escaped)
                elif '"' in val:  #use raw encoding for prettiness
                    yield "  %s = r'%s'" % (c.name, val)
                elif "'" in val:  #use raw encoding for prettiness
                    yield '  %s = r"%s"' % (c.name, val)
                else:
                    yield "  %s = '%s'" % (c.name, val)
            else:
                yield '  %s = %s' % (c.name, c.val)
        yield ''
    yield "  attr_accessor " + ", ".join([":" + x for x in spec_names]) + "\n"

    yield '_REPLACE_FOR_STRUCT_'
    if len(spec_names):
        yield "  @@struct_L = ::ROS::Struct.new(\"L\")"
        yield "  @@slot_types = ['" + "','".join(spec.types) + "']"
    else:
        yield "  @@struct_L = ::ROS::Struct.new(\"L\")"
        yield "  @@slot_types = []"

    yield """
  # Constructor. You can set the default values using keyword operators.
  #
  # @param [Hash] args keyword for initializing values"""
    for (t, s) in zip(spec.types, spec_names):
        yield "  # @option args [%s] :%s initialize value" % (t, s)
    yield "  def initialize(args={})"
    if len(spec_names):
        yield "    # message fields cannot be None, assign default values for those that are"
    if len(spec_names) > 0:
        for (t, s) in zip(spec.types, spec_names):
            yield """    if args[:%s]
      @%s = args[:%s]
    else""" % (s, s, s)
            yield "      @%s = %s" % (
                s, default_value(msg_context, t, spec.package))
            yield "    end"
    yield "  end"  # end of initialize

    yield """
  # internal API method
  # @return [String] Message type string.
  def _get_types
    @slot_types
  end

  # serialize message into buffer
  # @param [IO] buff buffer
  def serialize(buff)"""
    for y in serialize_fn_generator(msg_context, spec):
        yield "    " + y
    yield "  end"
    yield """
  #  unpack serialized message in str into this message instance
  #  @param [String] str: byte array of serialized message
  def deserialize(str)
"""
    for y in deserialize_fn_generator(msg_context, spec):
        yield "    " + y
    yield "  end"
    yield "end # end of class"
    yield "end # end of module"