Class: PureMVC::Controller

Inherits:
Object
  • Object
show all
Defined in:
src/core/controller.rb

Overview

A Multiton IController implementation.

In PureMVC, the Controller class follows the ‘Command and Controller’ strategy and assumes these responsibilities:

  • Remembering which ICommands are intended to handle which INotifications.

  • Registering itself as an IObserver with the View for each INotification that has an ICommand mapping.

  • Creating a new instance of the proper ICommand to handle a given INotification when notified by the View.

  • Calling the ICommand‘s execute method, passing in the INotification.

Your application must register ICommands with the Controller.

The simplest way is to subclass Facade, and use its initializeController method. to add your registrations.

Constant Summary collapse

MULTITON_MSG =

Message Constants

'Controller instance for this Multiton key already constructed!'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ Controller

Constructor.

This IController implementation is a Multiton, so you should not call the constructor directly. Instead, call the static factory method, passing the unique key for this instance: PureMVC::Controller.getInstance(key) { |key| PureMVC::Controller.new(key) }

Parameters:

  • key (String)

Raises:

  • (RuntimeError)

    if an instance for this Multiton key has already been constructed



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'src/core/controller.rb', line 76

def initialize(key)
  raise MULTITON_MSG if self.class.instance_map[key]

  self.class.instance_map[key] = self
  # The Multiton Key for this Core
  # @type var multiton_key: String
  @multiton_key = key
  # Local reference to View
  # @type var component: _IView?
  @view = nil
  # Mapping of Notification names to Command factories
  # @type var command_map: Hash[String, ^() -> _ICommand]
  @command_map = {}
  # Mutex used to synchronize access to the @command_map
  # @type var command_mutex: Mutex
  @command_mutex = Mutex.new
  initialize_controller
end

Class Method Details

.get_instance(key, &factory) ⇒ IController

Gets an instance using the provided factory block

Parameters:

  • key (String)

    the unique key identifying the Multiton instance

  • factory (^(String) -)

    _IController] the unique key passed to the factory block

Returns:

  • (IController)

    The controller instance created by the factory



52
53
54
55
56
# File 'src/core/controller.rb', line 52

def get_instance(key, &factory)
  mutex.synchronize do
    instance_map[key] ||= factory.call(key)
  end
end

.instance_mapHash{String => IController}

The Multiton IController instanceMap.

Returns:

  • (Hash{String => IController})


41
# File 'src/core/controller.rb', line 41

def instance_map = (@instance_map ||= {})

.mutexMutex

Mutex used to synchronize access to the instance map for thread safety.

Returns:

  • (Mutex)


45
# File 'src/core/controller.rb', line 45

def mutex = (@mutex ||= Mutex.new)

.remove_controller(key) ⇒ Object

Remove an IController instance

Parameters:

  • key (String)

    the multiton key of the IController instance to remove



61
62
63
64
65
# File 'src/core/controller.rb', line 61

def remove_controller(key)
  mutex.synchronize do
    instance_map.delete(key)
  end
end

Instance Method Details

#execute_command(notification) ⇒ Object

If an ICommand has previously been registered to handle the given INotification, then it is executed.

Parameters:

  • notification (INotification)

    the notification to handle



136
137
138
139
140
141
142
143
144
145
146
147
# File 'src/core/controller.rb', line 136

def execute_command(notification)
  @command_mutex.synchronize do
    # @type factory: [^() -> ICommand]?
    factory = @command_map[notification.name]
    return if factory.nil?

    # @type var command: _ICommand
    command = factory.call
    command.initialize_notifier(@multiton_key)
    command.execute(notification)
  end
end

#has_command?(notification_name) ⇒ Boolean

Check if a Command is registered for a given Notification.

Parameters:

  • notification_name (String)

    the name of the Notification

Returns:

  • (Boolean)

    whether a Command is currently registered for the given notification_name



153
154
155
156
157
# File 'src/core/controller.rb', line 153

def has_command?(notification_name)
  @command_mutex.synchronize do
    @command_map.key?(notification_name)
  end
end

#initialize_controllerObject

Initialize the Multiton Controller instance.

Called automatically by the constructor.

Note that if you are using a subclass of View in your application, you should also subclass Controller and override the initialize_controller method in the following way:

Examples:

# ensure that the Controller is talking to my IView implementation
def initialize_controller
  @view = MyView::get_instance(key) { |key| MyView.new(key) }
end


110
111
112
# File 'src/core/controller.rb', line 110

def initialize_controller
  @view = View.get_instance(@multiton_key) { |key| View.new(key) }
end

#register_command(notification_name, &factory) ⇒ Object

Register a particular ICommand class as the handler for a particular INotification.

If an ICommand has already been registered to handle INotifications with this name, it is replaced by the new ICommand.

The Observer for the new ICommand is only created if this is the first time an ICommand has been registered for this notification name.

Parameters:

  • notification_name (String)

    the name of the INotification

  • factory (^<() -> ICommand)

    ] the factory to produce an instance of the ICommand



124
125
126
127
128
129
130
131
# File 'src/core/controller.rb', line 124

def register_command(notification_name, &factory)
  @command_mutex.synchronize do
    if @command_map[notification_name].nil?
      @view&.register_observer(notification_name, Observer.new(method(:execute_command), self))
    end
    @command_map[notification_name] = factory
  end
end

#remove_command(notification_name) ⇒ Object

Remove a previously registered ICommand to INotification mapping.

Parameters:

  • notification_name (String)

    the name of the INotification to remove the ICommand mapping for



162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'src/core/controller.rb', line 162

def remove_command(notification_name)
  @command_mutex.synchronize do
    # @type var command: [^() -> ICommand]?
    command = @command_map[notification_name]

    # if the Command is registered...
    if command
      # remove the observer
      @view&.remove_observer(notification_name, self)
      # remove the command
      @command_map.delete(notification_name)
    end
  end
end