Class: PureMVC::View

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

Overview

A Multiton IView implementation.

In PureMVC, the IView class assumes these responsibilities:

  • Maintains a cache of IMediatorinstances.

  • Provides methods for registering, retrieving, and removing IMediators.

  • Notifies IMediatorswhen they are registered or removed.

  • Manages the observer lists for each INotificationin the application.

  • Provides a method for attaching IObserversto an INotification‘s observer list.

  • Provides a method for broadcasting an INotification.

  • Notifies the IObserversof a given INotificationwhen it is broadcast.

Constant Summary collapse

MULTITON_MSG =
'View instance for this Multiton key already constructed!'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ View

Constructor.

This IView implementation is a Multiton, so you should not call the constructor directly. Instead, call the static Multiton factory method View.get_instance(multiton_key) { |key| View.new(key) }.

Parameters:

  • key (String)

Raises:

  • (RuntimeError)

    if an instance for this Multiton key has already been constructed.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'src/core/view.rb', line 68

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
  # Mapping of Notification names to Observer lists
  # @type var observer_map: Hash[String, Array[_IObserver]]
  @observer_map = {}
  # Mutex used to synchronize access to the observer_map
  # @type var observer_mutex: Mutex
  @observer_mutex = Mutex.new
  # Mapping of Mediator names to Mediator instances
  # @type var mediator_map: Hash[String, _IMediator]
  @mediator_map = {}
  # Mutex used to synchronize access to the mediator_map
  # @type var mediator_mutex: Mutex
  @mediator_mutex = Mutex.new
  initialize_view
end

Class Method Details

.get_instance(key, &factory) ⇒ _IView

View Multiton Factory method.

Parameters:

  • key (String)

    the unique key identifying the Multiton instance

  • factory (^(String) -)

    _IView] the unique key passed to the factory block

Returns:

  • (_IView)

    the Multiton instance of View



44
45
46
47
48
# File 'src/core/view.rb', line 44

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

.instance_mapHash{String => IView}

The Multiton IModel instanceMap.

Returns:

  • (Hash{String => IView})


33
# File 'src/core/view.rb', line 33

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

.mutexMutex

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

Returns:

  • (Mutex)


37
# File 'src/core/view.rb', line 37

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

.remove_view(key) ⇒ Object

Remove an IView instance.

Parameters:

  • key (String)

    the key of the IView instance to remove



53
54
55
56
57
# File 'src/core/view.rb', line 53

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

Instance Method Details

#has_mediator?(mediator_name) ⇒ Boolean

Check if a Mediator is registered or not.

Parameters:

  • mediator_name (String)

    the name of the mediator to check.

Returns:

  • (Boolean)

    whether a Mediator is registered with the given mediatorName.



199
200
201
202
203
# File 'src/core/view.rb', line 199

def has_mediator?(mediator_name)
  @mediator_mutex.synchronize do
    @mediator_map.key?(mediator_name)
  end
end

#initialize_viewObject

Initialize the Multiton View instance.

Called automatically by the constructor, this is your opportunity to initialize the Multiton instance in your subclass without overriding the constructor.



96
# File 'src/core/view.rb', line 96

def initialize_view; end

#notify_observers(notification) ⇒ Object

Notify the IObservers for a particular INotification.

All previously attached IObservers for this INotification‘s list are notified and are passed a reference to the INotification in the order in which they were registered.

Parameters:

  • notification (INotification)

    the INotification to notify IObservers of.



117
118
119
120
121
122
123
124
125
126
127
128
# File 'src/core/view.rb', line 117

def notify_observers(notification)
  # @type var observers: Array[_IObserver]?
  observers = nil
  @observer_mutex.synchronize do
    # Get a reference to the observers list for this notification name
    # Iteration safe, copy observers from reference array to working array,
    # since the reference array may change during the notification loop
    observers = @observer_map[notification.name].dup
  end
  # Notify Observers from the working array
  observers&.each { |observer| observer.notify_observer(notification) }
end

#register_mediator(mediator) ⇒ Object

Register an IMediator instance with the View.

Registers the IMediator so that it can be retrieved by name, and further interrogates the IMediator for its INotification interests.

If the IMediator returns any INotification names to be notified about, an Observer is created encapsulating the IMediator instance’s handleNotification method and registering it as an Observer for all INotifications the IMediator is interested in.

Parameters:

  • mediator (IMediator)

    a reference to the IMediator instance



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'src/core/view.rb', line 162

def register_mediator(mediator)
  @mediator_mutex.synchronize do
    return if @mediator_map.key?(mediator.name)

    @mediator_map[mediator.name] = mediator
  end

  mediator.initialize_notifier(@multiton_key)

  # Create Observer referencing this mediator's handleNotification method
  # @type observer [IObserver]
  observer = Observer.new(mediator.method(:handle_notification), mediator)

  # Get Notification interests, if any.
  # @type interests [Array<String>]
  interests = mediator.list_notification_interests
  # Register Mediator as Observer for its list of Notification interests
  interests.each { |interest| register_observer(interest, observer) }

  # alert the mediator that it has been registered
  mediator.on_register
end

#register_observer(notification_name, observer) ⇒ Object

Register an IObserver to be notified of INotifications with a given name.

Parameters:

  • notification_name (String)

    the name of the INotifications to notify IObserver of

  • observer (IObserver)

    the IObserver to register



103
104
105
106
107
108
# File 'src/core/view.rb', line 103

def register_observer(notification_name, observer)
  @observer_mutex.synchronize do
    observers = (@observer_map[notification_name] ||= [])
    observers << observer
  end
end

#remove_mediator(mediator_name) ⇒ IMediator?

Remove an IMediator from the View.

Parameters:

  • mediator_name (String)

    name of the IMediator instance to be removed.

Returns:

  • (IMediator, nil)

    IMediator that was removed from the View, or nil if none found.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'src/core/view.rb', line 209

def remove_mediator(mediator_name)
  # @type var mediator: _IMediator?
  mediator = nil
  @mediator_mutex.synchronize do
    # retrieve the named mediator and delete from the mediator map
    mediator = @mediator_map.delete(mediator_name)
  end
  return unless mediator

  # for every notification this mediator is interested in...
  # @type var interests: Array[String]
  interests = mediator.list_notification_interests
  # remove the observer linking the mediator
  # to the notification interest
  interests.each { |interest| remove_observer(interest, mediator) }

  # alert the mediator that it has been removed
  mediator.on_remove
  mediator
end

#remove_observer(notification_name, notify_context) ⇒ Object

Remove the observer for a given notifyContext from an observer list for a given Notification name.

Parameters:

  • notification_name (String)

    which observer list to remove from

  • notify_context (Object)

    remove the observer with this object as its notifyContext



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

def remove_observer(notification_name, notify_context)
  @observer_mutex.synchronize do
    # the observer list for the notification under inspection
    # @type var observers: Array[_IObserver]?
    observers = @observer_map[notification_name]
    # find and remove the sole Observer for the given notify_context
    # there can only be one Observer for a given notify_context
    # in any given Observer list, so remove it
    observers&.reject! { |observer| observer.compare_notify_context?(notify_context) }
    # Also, when a Notification's Observer list length falls to
    # zero, delete the notification key from the observer map
    @observer_map.delete(notification_name) if observers&.empty?
  end
end

#retrieve_mediator(mediator_name) ⇒ IMediator?

Retrieve an IMediator from the View.

Parameters:

  • mediator_name (String)

    the name of the IMediator instance to retrieve.

Returns:

  • (IMediator, nil)

    IMediator previously registered with the given mediatorName.



189
190
191
192
193
# File 'src/core/view.rb', line 189

def retrieve_mediator(mediator_name)
  @mediator_mutex.synchronize do
    @mediator_map[mediator_name]
  end
end