🔥 MessageRegistry

This commit is contained in:
Michelle Tilley
2017-09-18 17:33:42 -07:00
parent 9e74e164b6
commit bf4985e265
2 changed files with 0 additions and 215 deletions

View File

@@ -1,84 +0,0 @@
MessageRegistry = require '../src/message-registry'
describe 'MessageRegistry', ->
[registry] = []
beforeEach ->
registry = new MessageRegistry
describe '::add', ->
it 'throws an error when the listener is not a function', ->
badAdder = -> registry.add 'package:message', 'not a function'
expect(badAdder).toThrow()
describe 'the returned disosable', ->
it 'removes the callback', ->
spy = jasmine.createSpy('callback')
disposable = registry.add 'package:message', spy
disposable.dispose()
registry.dispatch 'atom://atom/package:message'
expect(spy).not.toHaveBeenCalled()
it 'removes only the associated callback', ->
spy1 = jasmine.createSpy('callback 1')
spy2 = jasmine.createSpy('callback 2')
registry.add 'package:message', spy1
disposable = registry.add 'package:message', spy2
disposable.dispose()
registry.dispatch 'atom://atom/package:message'
expect(spy1).toHaveBeenCalledWith('package:message', {})
expect(spy2).not.toHaveBeenCalledWith('package:message', {})
it 'removes all callbacks when created via ::add(object)', ->
spy1 = jasmine.createSpy('callback 1')
spy2 = jasmine.createSpy('callback 2')
disposable = registry.add
'package:message1': spy1
'package:message2': spy2
disposable.dispose()
registry.dispatch 'atom://atom/package:message1'
registry.dispatch 'atom://atom/package:message2'
expect(spy1).not.toHaveBeenCalled()
expect(spy2).not.toHaveBeenCalled()
describe '::dispatch', ->
describe 'when a single callback is registered', ->
[spy1, spy2] = []
beforeEach ->
spy1 = jasmine.createSpy('callback1 ')
spy2 = jasmine.createSpy('callback 2')
it 'invokes callbacks for matching messages', ->
registry.add 'package:message', spy1
registry.add 'package:other-message', spy2
registry.dispatch 'atom://atom/package:message'
expect(spy1).toHaveBeenCalledWith 'package:message', {}
expect(spy2).not.toHaveBeenCalled()
describe 'when multiple callbacks are registered', ->
[spy1, spy2, spy3] = []
beforeEach ->
spy1 = jasmine.createSpy('callback 1')
spy2 = jasmine.createSpy('callback 2')
spy3 = jasmine.createSpy('callback 3')
it 'invokes all the registered callbacks for matching messages', ->
registry.add 'package:message', spy1
registry.add 'package:message', spy2
registry.add 'package:other-message', spy3
registry.dispatch 'atom://atom/package:message'
expect(spy1).toHaveBeenCalledWith('package:message', {})
expect(spy2).toHaveBeenCalledWith('package:message', {})
expect(spy3).not.toHaveBeenCalled()
describe 'when a message with params is dispatched', ->
it 'invokes the callback with the given params', ->
spy = jasmine.createSpy('callback')
registry.add 'package:message', spy
registry.dispatch 'atom://atom/package:message?one=1&2=two'
expectedParams =
one: '1'
2: 'two'
expect(spy).toHaveBeenCalledWith('package:message', expectedParams)

View File

@@ -1,131 +0,0 @@
querystring = require 'querystring'
url = require 'url'
{Disposable, CompositeDisposable} = require 'event-kit'
# Public: Associates listener functions with messages from outside the
# application. You can access a global instance of this class via
# `atom.messages`.
#
# The global message registry is similar to the {CommandRegistry} in that it
# maps messages, identified by strings, to listener functions; however, unlike
# commands, messages can originate from outside the application, and thus the
# range of actions that messages can trigger should be more limited.
#
# Message names must follow the `namespace:action` pattern, where `namespace`
# will typically be the name of your package, and `action` describes the
# behavior of your command. If either part consists of multiple words, these
# must be separated by hyphens. E.g. `awesome-package:turn-it-up-to-eleven`. All
# words should be lowercased.
#
# Messages are exposed to applications outside Atom via special URIs that begin
# with `atom://atom/`. For example, a message named `package:show-pane` could
# be triggered by visiting `atom://atom/package:show-pane`. Additional
# parameters can be passed via query string parameters.
#
# Since messages can originate from outside the application, you should avoid
# registering messages for operations that can be destructive to the user's
# environment; for example, a message to open the install page for a package is
# fine, but a message that immediately installs a package is not.
#
# ## Example
#
# Here is a message that could open a specific panel in a package's view:
#
# ```coffee
# atom.messages.add 'package:show-panel', (message, params) ->
# packageView.showPanel(params.panel)
# ```
#
# Such a message could be triggered by visiting the associated URL:
#
# ```
# atom://atom/package:show-panel?panel=help
# ```
module.exports =
class MessageRegistry
constructor: ->
@clear()
clear: ->
@listenersByMessageName = {}
# Public: Add one or more message listeners.
#
# ## Arguments: Registering One Message
#
# * `messageName` A {String} containing the name of a message you want to
# handle such as `package:show-panel`.
# * `callback` A {Function} to call when the given message is activated.
# * `message` An {String} containing the message that triggered this
# callback.
# * `params` An {Object} containing any key-value pairs passed to the
# message via query string parameters. The values will always be {String}s.
#
# ## Arguments: Registering Multiple Messages
#
# * `messages` An {Object} mapping message names like `package:show-panel`
# to listener {Function}s.
#
# Returns a {Disposable} on which `.dispose()` can be called to remove the
# added message handler(s).
add: (messageName, callback) ->
if typeof messageName is 'object'
messages = messageName
disposable = new CompositeDisposable
for messageName, callback of messages
disposable.add @add(messageName, callback)
return disposable
if typeof callback isnt 'function'
throw new Error("Can't register a message with a non-function callback")
@addListener(messageName, callback)
addListener: (messageName, callback) ->
messageListeners = @listenersByMessageName[messageName]
if typeof messageListeners is 'function'
@listenersByMessageName[messageName] = [
messageListeners,
callback
]
else if messageListeners?
messageListeners.push(callback)
else
@listenersByMessageName[messageName] = callback
new Disposable =>
@removeListener(messageName, callback)
removeListener: (messageName, callback) ->
messageListeners = @listenersByMessageName[messageName]
if callback? and messageListeners is callback
delete @listenersByMessageName[messageName]
else
messageListeners.splice(messageListeners.indexOf(callback), 1)
# Public: Simulates the dispatch of a given message URI.
#
# This can be useful for testing when you want to simulate a mesasge being
# passed from outside Atom.
#
# * `uri` {String} The URI to dispatch. URIs are expected to be in the form
# `atom://atom/package:message?param=value&other=more`, where
# `package:message?param=value&other=more` describes the message to
# dispatch.
dispatch: (uri) ->
parsedUri = url.parse(uri)
return unless parsedUri.host is 'atom'
path = parsedUri.pathname or ''
messageName = path.substr(1)
listeners = @listenersByMessageName[messageName]
return unless listeners?
params = querystring.parse(parsedUri.query)
if typeof listeners is 'function'
listeners(messageName, params)
else
listeners.forEach (l) -> l(messageName, params)