def decode_definition_and_options(definition_and_options)
      # Only a hash (commands)
      if definition_and_options.size == 1 && definition_and_options.first.is_a?(Hash)
        options = definition_and_options.first.each_with_object({}) do |(key, value), current_options|
          current_options[key] = definition_and_options.first.delete(key) if key.is_a?(Symbol)
        end

        # If there is an empty hash left, we remove it, so it's not considered commands.
        #
        definition_and_options = [] if definition_and_options.first.empty?
      # Options passed
      elsif definition_and_options.last.is_a?(Hash)
        options = definition_and_options.pop
      # No options passed
      else
        options = {}
      end

      [definition_and_options, options]
    end
def decode_definition_and_options(definition_and_options)
      # Only a hash (commands)
      if definition_and_options.size == 1 && definition_and_options.first.is_a?(Hash)
        options = definition_and_options.first.each_with_object({}) do |(key, value), current_options|
          current_options[key] = definition_and_options.first.delete(key) if key.is_a?(Symbol)
        end

        # If there is an empty hash left, we remove it, so it's not considered commands.
        #
        definition_and_options = [] if definition_and_options.first.empty?
      # Options passed
      elsif definition_and_options.last.is_a?(Hash)
        options = definition_and_options.pop
      # No options passed
      else
        options = {}
      end

      [definition_and_options, options]
    end
This is trivial to define with named arguments, however, Ruby 2.6 removed the support for
 mixing strings and symbols as argument keys, so we're forced to perform manual decoding.
 The complexity of this code supports the rationale for the removal of the functionality.