Class: Cuprum::CommandFactory

Inherits:
Module
  • Object
show all
Defined in:
lib/cuprum/command_factory.rb

Overview

Builder class for instantiating command objects.

Examples:

class SpaceFactory < Cuprum::CommandFactory
  command(:build, BuildCommand)

  command(:fly) { |launch_site:| FlyCommand.new(launch_site) }

  command_class(:dream) { DreamCommand }
end

factory = SpaceFactory.new

factory::Build #=> BuildCommand
factory.build  #=> an instance of BuildCommand

rocket = factory.build.call({ size: 'big' }) #=> an instance of Rocket
rocket.size                                  #=> 'big'

command = factory.fly(launch_site: 'KSC') #=> an instance of FlyCommand
command.call(rocket)
#=> launches the rocket from KSC

factory::Dream #=> DreamCommand
factory.dream  #=> an instance of DreamCommand

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.command(name, command_class) ⇒ Object .command(name) {|args| ... } ⇒ Object

Defines a command for the factory.

Overloads:

  • .command(name, command_class) ⇒ Object

    Defines a command using the given factory class. For example, when a command is defined with the name “whirlpool” and the WhirlpoolCommand class:

    A factory instance will define the constant ::Whirlpool, and accessing factory::Whirlpool will return the WhirlpoolCommand class.

    A factory instance will define the method #whirlpool, and calling factory#whirlpool will return an instance of WhirlpoolCommand. Any arguments passed to the #whirlpool method will be forwarded to the constructor when building the command.

    Examples:

    class MoveFactory < Cuprum::CommandFactory
      command :cut, CutCommand
    end
    
    factory = MoveFactory.new
    factory::Cut #=> CutCommand
    factory.cut  #=> an instance of CutCommand

    Parameters:

    • name (String, Symbol)

      The name of the command.

    • command_class (Class)

      The command class. Must be a subclass of Cuprum::Command.

  • .command(name) {|args| ... } ⇒ Object

    Defines a command using the given block, which must return an instance of a Cuprum::Command subclass. For example, when a command is defined with the name “dive” and a block that returns an instance of the DiveCommand class:

    A factory instance will define the method #dive, and calling factory#dive will call the block and return the resulting command instance. Any arguments passed to the #dive method will be forwarded to the block when building the command.

    The block will be evaluated in the context of the factory instance, so it has access to any methods or instance variables defined for the factory instance.

    Examples:

    class MoveFactory < Cuprum::CommandFactory
      command :fly { |destination| FlyCommand.new(destination) }
    end
    
    factory = MoveFactory.new
    factory.fly_command('Indigo Plateau')
    #=> an instance of FlyCommand with a destination of 'Indigo Plateau'

    Parameters:

    • name (String, Symbol)

      The name of the command.

    Yields:

    • The block will be executed in the context of the factory instance.

    Yield Parameters:

    • args (Array)

      Any arguments given to the method factory.name() will be passed on the block.

    Yield Returns:

    • (Cuprum::Command)

      The block return an instance of a Cuprum::Command subclass, or else raise an error.



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/cuprum/command_factory.rb', line 97

def command(name, klass = nil, **, &defn)
  guard_abstract_factory!

  if klass
    define_command_from_class(klass, name: name, metadata: )
  elsif block_given?
    define_command_from_block(defn, name: name, metadata: )
  else
    require_definition!
  end
end

.command_class(name, **metadata) {|*args| ... } ⇒ Object

Defines a command using the given block, which must return a subclass of Cuprum::Command. For example, when a command is defined with the name “rock_climb” and a block returning a subclass of RockClimbCommand:

A factory instance will define the constant ::RockClimb, and accessing factory::RockClimb will call the block and return the resulting command class. This value is memoized, so subsequent factory::RockClimb accesses on the same factory instance will return the same command class.

A factory instance will define the method #rock_climb, and calling factory#rock_climb will access the constant at ::RockClimb and return an instance of that subclass of RockClimbCommand. Any arguments passed to the #whirlpool method will be forwarded to the constructor when building the command.

Examples:

class MoveFactory < Cuprum::CommandFactory
  command_class :flash do
    Class.new(FlashCommand) do
      def brightness
        :intense
      end
    end
  end
end

factory = MoveFactory.new
factory::Flash #=> a subclass of FlashCommand
factory.flash  #=> an instance of factory::Flash

command = factory.flash
command.brightness #=> :intense

Parameters:

  • name (String, Symbol)

    The name of the command.

Yields:

  • The block will be executed in the context of the factory instance.

Yield Parameters:

  • *args (Array)

    Any arguments given to the method factory.name() will be passed on the block.

Yield Returns:

  • (Cuprum::Command)

    The block return an instance of a Cuprum::Command subclass, or else raise an error.

Raises:

  • (ArgumentError)


149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/cuprum/command_factory.rb', line 149

def command_class(name, **, &defn)
  guard_abstract_factory!

  raise ArgumentError, 'must provide a block' unless block_given?

  method_name = normalize_command_name(name)

  (@command_definitions ||= {})[method_name] =
    .merge(__const_defn__: defn)

  define_lazy_command_method(method_name)
end

Instance Method Details

#command?(command_name) ⇒ Boolean

Returns true if the factory defines the given command, otherwise false.

Returns:

  • (Boolean)

    true if the factory defines the given command, otherwise false.



256
257
258
259
260
# File 'lib/cuprum/command_factory.rb', line 256

def command?(command_name)
  command_name = normalize_command_name(command_name)

  commands.include?(command_name)
end

#commandsArray<Symbol>

Returns a list of the commands defined by the factory.

Returns:

  • (Array<Symbol>)

    a list of the commands defined by the factory.



263
264
265
# File 'lib/cuprum/command_factory.rb', line 263

def commands
  self.class.send(:command_definitions).keys
end

#const_defined?(const_name, inherit = true) ⇒ Boolean

Returns:

  • (Boolean)


268
269
270
# File 'lib/cuprum/command_factory.rb', line 268

def const_defined?(const_name, inherit = true) # rubocop:disable Style/OptionalBooleanParameter
  command?(const_name) || super
end

#const_missing(const_name) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/cuprum/command_factory.rb', line 273

def const_missing(const_name)
  definitions  = self.class.send(:command_definitions)
  command_name = normalize_command_name(const_name)
  command_defn = definitions.dig(command_name, :__const_defn__)

  return super unless command_defn

  command_class =
    command_defn.is_a?(Proc) ? instance_exec(&command_defn) : command_defn

  const_set(const_name, command_class)

  command_class
end