Module: Rapid::Services::Responses::StructureBuilder

Extended by:
Forwardable
Included in:
Baps::Responses::Structures
Defined in:
lib/ury_rapid/services/responses/structure_builder.rb

Overview

DSL for defining response structures

Response structures are useful when dealing with the output of a playout system that speaks a binary protocol. They allow the mapping of a received command word to a list of expected following arguments.

Instance Method Summary collapse

Instance Method Details

#add_group_constantsnull

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Exports a group's constants into this structure builder

This allows them to be specified unqualified in a group.

Returns:

  • (null)

194
195
196
197
198
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 194

def add_group_constants
  @code_module.constants.each do |constant|
    const_set(constant, @code_module.const_get(constant))
  end
end

#create_method(name, &block) ⇒ null

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates a method at the singleton class level

Parameters:

  • name (String)

    The name of the method to create.

Returns:

  • (null)

183
184
185
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 183

def create_method(name, &block)
  singleton_class.send(:define_method, name, &block)
end

#def_argument_shortcuts(type, arguments) ⇒ null

Defines shortcuts for common argument type-name pairs

This creates, for each argument name in 'arguments', a method with that name serves as a shortcut for calling 'type' with that name.

Examples:

Defining some argument shortcuts.

# Assume 'uint32' is an existing type.
def_argument_shortcuts :uint32, %i(position count index)
# We can now substitute 'position' etc. for 'uint32(position' etc.
# in calls to #struct.

Parameters:

  • type (Symbol)

    The type, defined by #def_type, of all argument shortcuts to be defined by this method call.

  • arguments (Array)

    An array of symbols, each representing a common argument name for which a shortcut method should be made that creates an argument with type 'type' and said argument name.

Returns:

  • (null)

87
88
89
90
91
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 87

def def_argument_shortcuts(type, arguments)
  arguments.each do |argument|
    create_method(argument) { send(type, argument) }
  end
end

#def_struct(name, *arguments) ⇒ null

Defines a common structure that can be reused for multiple commands

Given a name and arguments, this creates a method of that name that, when called with a response code, expands to a #struct call with that code and the provided arguments.

For convenience, multiple codes may be provided to the shortcut, with the same result as that from invoking the shortcut once for each code.

When the same structure is repeated multiple times with only the response code varying, one can instead #def_struct the structure once and then call the created method with those codes, saving time and RSI.

Examples:

Defining a common structure with no argument.

def_struct :unary
# We can now write 'unary PLAY' instead of 'struct PLAY'.

Defining a common structure with arguments.

# Here, 'option_id' is an argument shortcut, and 'config_setting'
# is a type.
def_struct :config, option_id, config_setting(:setting)
# We can now write 'config CONFIG_SETTING, CONFIG_SETTING_INDEXED'
# instead of the rather long-winded
# 'struct CONFIG_SETTING, option_id, config_setting(:setting)' and
# 'struct CONFIG_SETTING_INDEXED, option_id,
#  config_setting(:setting)'.

Returns:

  • (null)

59
60
61
62
63
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 59

def def_struct(name, *arguments)
  create_method(name) do |*symbols|
    symbols.each { |symbol| struct(symbol, *arguments) }
  end
end

#def_types(*types) ⇒ null

Defines the types over which the structures are defined

Types are, effectively, symbols that are understood by the response parser as indicating a specific parsing pattern to use to parse arguments.

Examples:

Defining a set of types.

def_types :float32, :uint32, :string, :load_body, :config_setting

Parameters:

  • types

    The types to define in the structure builder.

Returns:

  • (null)

26
27
28
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 26

def def_types(*types)
  types.each { |type| create_method(type) { |name| [name, type] } }
end

#group(code_module) ⇒ null

Defines a response group

This effectively takes a module containing response structure codes as constants and, for the duration of the #group block, brings those codes into the global namespace. It also serves as a nice way of grouping structures by the same structure used in the code table.

Examples:

An example group block.

group Codes::Playlist do
  # The group has brought DELETE_ITEM, MOVE_ITEM_IN_PLAYLIST,
  # ITEM_COUNT, and ITEM_DATA into scope from Codes::Playlist
  struct DELETE_ITEM,           index
  struct MOVE_ITEM_IN_PLAYLIST, old_index, new_index
  struct ITEM_COUNT,            count
  struct ITEM_DATA,             index, uint32(:type), title
end

Parameters:

  • code_module (Module)

    The module, from the response code table, in which the command codes for all of the responses in this group are defined.

Returns:

  • (null)

140
141
142
143
144
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 140

def group(code_module)
  @code_module = code_module
  add_group_constants
  yield
end

#struct(code, *arguments) ⇒ null

Defines a response structure

This creates an association between the response code and the following argument types and names, so that, if the code is read by the response parser, the parser will prepare to read values with those types and store them under the respective names.

The arguments can either be defined by calling a type set up with #def_types with the intended argument name, or by calling an argument shortcut set up with #def_argument_shortcuts.

Examples:

Defining a structure.

# Assuming that the code DELETE_ITEM is in scope, and the argument
# shortcut 'index' has been defined.
struct DELETE_ITEM, index

Parameters:

  • code (Object)

    The response code. The actual type of this code will depend on the protocol.

  • arguments

    Zero or more argument specifiers, telling the structure builder which arguments will be expected of a response with the given code.

Returns:

  • (null)

171
172
173
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 171

def struct(code, *arguments)
  @structures[code] = arguments
end

#structuresnull

Allows response structures to be defined

Examples:

An example structures block.

structures do
  # See the documentation for #group for more explanation about
  # what this is doing
  group Codes::Playlist do
    struct DELETE_ITEM,           index
    struct MOVE_ITEM_IN_PLAYLIST, old_index, new_index
    struct ITEM_COUNT,            count
    struct ITEM_DATA,             index, uint32(:type), title
  end
end

Returns:

  • (null)

109
110
111
112
# File 'lib/ury_rapid/services/responses/structure_builder.rb', line 109

def structures
  @structures = {}
  yield
end