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.



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

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)


147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/cuprum/command_factory.rb', line 147

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

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

  name = normalize_command_name(name)

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

  const_name = tools.string.camelize(name)

  define_method(name) do |*args, &block|
    command_class = const_get(const_name)

    build_command(command_class, *args, &block)
  end
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.



234
235
236
237
238
# File 'lib/cuprum/command_factory.rb', line 234

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.



241
242
243
# File 'lib/cuprum/command_factory.rb', line 241

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

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

Returns:

  • (Boolean)


246
247
248
# File 'lib/cuprum/command_factory.rb', line 246

def const_defined?(const_name, inherit = true)
  command?(const_name) || super
end

#const_missing(const_name) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/cuprum/command_factory.rb', line 251

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