emittance 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04b42fbe154e0d5cde79009304ca822446cdab4a
4
- data.tar.gz: 7ab0a1d41824b4ac72b0eea7ffb452a1d4023434
3
+ metadata.gz: 5aa08e8db74f9be24f08a38983291c67293c204e
4
+ data.tar.gz: 738f991042e17d4414fc491bdf74df4360801f30
5
5
  SHA512:
6
- metadata.gz: f7a2c245677fbedd995c14a097111051f9b5e545d72d3653e5ffa18eb7b931531453c050c8d8f6cfd58b9c1dec2a55637a63b1a21f374e56ac7e86754e3f3d03
7
- data.tar.gz: b96f64c4b769476dab89bd3922db4db33b3cb14a5f4c7f6d91b7db3263148e2fcc25cac845c0915452afc696bf34604c6ee65da9575fc196c8350711ae71900b
6
+ metadata.gz: 86045a1315babc710189b66ddde7e800ff830048c3bbcd954469adb915d689ebcd4d3dea42dc91a2ceca3c5e3932da5c260bb955c8381b02342e97a1579cfabc
7
+ data.tar.gz: ec7772819f3e6e0e47a367667b2fb986547ebe293a1ccb5a318eaf05ac279f2bb480f6d66e30c172f1de92ea1f966e0096f7cb438d838cebcafe7f21489a55ef
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- emittance (0.0.6)
4
+ emittance (0.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emittance
4
+ class Dispatcher
5
+ ##
6
+ # A collection proxy for registrations. Can include multiple key/value pairs.
7
+ #
8
+ class RegistrationCollectionProxy
9
+ # @param lookup_term the term initially used to lookup the registrations
10
+ # @param mappings [Hash] the mappings of identifiers to their respective registrations
11
+ def initialize(lookup_term, mappings)
12
+ @lookup_term = lookup_term
13
+ @mappings = mappings
14
+ end
15
+
16
+ # @param args args passed to +Array#each+
17
+ # @param blk block passed to +Array#each+
18
+ # @return [RegistrationCollectionProxy] self
19
+ def each(*args, &blk)
20
+ arrays = mappings.values.map(&:to_a)
21
+ arrays.flatten.each(*args, &blk)
22
+ self
23
+ end
24
+
25
+ # @return [Boolean] true if there are no registrations at all, false otherwise
26
+ def empty?
27
+ mappings.values.all?(&:empty?)
28
+ end
29
+
30
+ # @return [RegistrationCollectionProxy] self
31
+ def <<(item)
32
+ mappings[lookup_term] << item
33
+ self
34
+ end
35
+
36
+ # @return [RegistrationCollectionProxy] self
37
+ def clear
38
+ mappings.values.each(&:clear)
39
+ self
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :lookup_term, :mappings
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'emittance/dispatcher/registration_collection_proxy'
4
+
5
+ module Emittance
6
+ class Dispatcher
7
+ ##
8
+ # A proxy for a hash. Identifies special identifiers.
9
+ #
10
+ class RegistrationMap
11
+ SPECIAL_IDENTIFIER_REGEX = /^\@/
12
+
13
+ class << self
14
+ # @param identifier the identifier we want to know information about
15
+ # @return [Boolean] true if the identifier is a special one, false otherwise
16
+ def special_identifier?(identifier)
17
+ identifier.to_s =~ SPECIAL_IDENTIFIER_REGEX
18
+ end
19
+ end
20
+
21
+ # Build a registration map.
22
+ def initialize
23
+ @reg_map = {}
24
+ end
25
+
26
+ # @param identifier the identifier you wish to lookup registrations for
27
+ # @return [RegistrationCollectionProxy] a collection of registrations for that identifier
28
+ def [](identifier)
29
+ lookup_term, keys = keys_for(identifier)
30
+ collection_for(lookup_term, keys)
31
+ end
32
+
33
+ # @param args args passed to +Hash#each_key+
34
+ # @param blk block passed to +Hash#each_key+
35
+ # @return [RegistrationMap] self
36
+ def each_key(*args, &blk)
37
+ reg_map.each_key(*args, &blk)
38
+ self
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :reg_map
44
+
45
+ def keys_for(identifier)
46
+ if special_identifier?(identifier)
47
+ keys_for_special_identifier(identifier)
48
+ else
49
+ keys_for_event_identifier(identifier)
50
+ end
51
+ end
52
+
53
+ def keys_for_special_identifier(identifier)
54
+ keys = [identifier.to_sym]
55
+
56
+ case identifier.to_s
57
+ when '@all'
58
+ keys += reg_map.keys.select { |key| key.is_a?(Class) }
59
+ end
60
+
61
+ [identifier.to_sym, keys]
62
+ end
63
+
64
+ def keys_for_event_identifier(identifier)
65
+ klass = Emittance::EventLookup.find_event_klass(identifier)
66
+ keys = [klass] + keys_matching_event_klass(klass)
67
+ [klass, keys]
68
+ end
69
+
70
+ def keys_matching_event_klass(_klass)
71
+ [:@all]
72
+ end
73
+
74
+ def collection_for(lookup_term, keys)
75
+ mappings = Hash[
76
+ keys.map do |key|
77
+ reg_map[key] ||= empty_registration
78
+ [key, reg_map[key]]
79
+ end
80
+ ]
81
+
82
+ RegistrationCollectionProxy.new(lookup_term, mappings)
83
+ end
84
+
85
+ def empty_registration
86
+ Set.new
87
+ end
88
+
89
+ def special_identifier?(identifier)
90
+ self.class.special_identifier?(identifier)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ require 'emittance/dispatcher/registration_map'
6
+
7
+ module Emittance
8
+ ##
9
+ # Abstract class for dispatchers. Subclasses must implement the following methods:
10
+ #
11
+ # - +._process_event+
12
+ # - +._register+
13
+ # - +._register_method_call+
14
+ #
15
+ # These methods can be private. These methods will have access to +.registrations_for+, which takes an identifier
16
+ # and returns an enumerable object with each object registered to that identifier. These objects can be anything
17
+ # you want, but typically represent the callback you would like to run whenever an event of a certain type is
18
+ # emitted.
19
+ #
20
+ class Dispatcher
21
+ class << self
22
+ # @private
23
+ def inherited(subklass)
24
+ subklass.instance_variable_set '@registrations', RegistrationMap.new
25
+ end
26
+
27
+ # Calls the subclass's +_process_event+ method.
28
+ def process_event(event)
29
+ _process_event(event)
30
+ end
31
+
32
+ # Calls the subclass's +_register+ method.
33
+ def register(identifier, &callback)
34
+ _register(identifier, &callback)
35
+ end
36
+
37
+ # Calls the subclass's +_register_method_call+ method.
38
+ def register_method_call(identifier, object, method_name)
39
+ _register_method_call(identifier, object, method_name)
40
+ end
41
+
42
+ # @param identifier the identifier the registrations for which you would like to look up
43
+ # @return [RegistrationCollectionProxy] an enumerable containing all registrations for a given identifier
44
+ def registrations_for(identifier)
45
+ registrations[identifier]
46
+ end
47
+
48
+ # @return [RegistrationMap] the registrations
49
+ def clear_registrations!
50
+ registrations.each_key { |key| clear_registrations_for! key }
51
+ registrations
52
+ end
53
+
54
+ # @param identifier the identifier the registrations for hwich you would like to clear
55
+ # @return [RegistrationCollectionProxy] the cleared registration proxy
56
+ def clear_registrations_for!(identifier)
57
+ registrations_for(identifier).clear
58
+ end
59
+
60
+ private
61
+
62
+ attr_reader :registrations
63
+
64
+ def _process_event(_event)
65
+ raise NotImplementedError
66
+ end
67
+
68
+ def _register(_identifier, &_callback)
69
+ raise NotImplementedError
70
+ end
71
+
72
+ def _register_method_call(_identifier, _object, _method_name)
73
+ raise NotImplementedError
74
+ end
75
+ end
76
+ end
77
+ end
@@ -5,76 +5,30 @@ module Emittance
5
5
  ##
6
6
  # The synchronous dispatcher. Runs callbacks one-by-one, in series.
7
7
  #
8
- class Dispatcher
9
- @registrations = {}
10
- @enabled = true
11
-
8
+ class Dispatcher < Emittance::Dispatcher
12
9
  class << self
13
- def process_event(event)
10
+ private
11
+
12
+ def _process_event(event)
14
13
  registrations_for(event).each do |registration|
15
14
  registration.call event
16
15
  end
17
16
  end
18
17
 
19
- def registrations_for(identifier)
20
- event_klass = find_event_klass identifier
21
- registrations[event_klass] ||= empty_registration
22
- registrations[event_klass]
23
- end
24
-
25
- def register(identifier, &callback)
26
- event_klass = find_event_klass identifier
27
- registrations[event_klass] ||= empty_registration
28
- registrations_for(event_klass) << Registration.new(event_klass, &callback)
29
-
18
+ def _register(identifier, &callback)
19
+ registrations = registrations_for identifier
20
+ registrations << callback
30
21
  callback
31
22
  end
32
23
 
33
- def register_method_call(identifier, object, method_name)
24
+ def _register_method_call(identifier, object, method_name)
34
25
  register identifier, &lambda_for_method_call(object, method_name)
35
26
  end
36
27
 
37
- def clear_registrations!
38
- registrations.each_key do |event_klass|
39
- clear_registrations_for! event_klass
40
- end
41
- end
42
-
43
- def clear_registrations_for!(identifier)
44
- event_klass = find_event_klass identifier
45
- registrations[event_klass].clear
46
- end
47
-
48
- private
49
-
50
- attr_accessor :registrations
51
-
52
- def empty_registration
53
- Set.new
54
- end
55
-
56
- def find_event_klass(event)
57
- Emittance::EventLookup.find_event_klass(event)
58
- end
59
-
60
28
  def lambda_for_method_call(object, method_name)
61
29
  ->(event) { object.send method_name, event }
62
30
  end
63
31
  end
64
-
65
- # @private
66
- class Registration
67
- attr_reader :event_klass
68
-
69
- def initialize(event_klass, &callback)
70
- @event_klass = event_klass
71
- @callback = callback
72
- end
73
-
74
- def call(event)
75
- @callback.call event
76
- end
77
- end
78
32
  end
79
33
  end
80
34
  end
@@ -114,7 +114,7 @@ module Emittance
114
114
  end
115
115
 
116
116
  def _method_patch_str(method_name, non_emitting_method, identifier)
117
- <<~RUBY
117
+ <<-RUBY
118
118
  def #{method_name}(*args, &blk)
119
119
  return_value = #{non_emitting_method}(*args, &blk)
120
120
  if #{!identifier.nil? ? true : false}
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Emittance
4
+ ##
5
+ # Like +Emittance::Action+, this is a convenience module that you can mix-in to any class that provides a shortuct
6
+ # for a common pattern. An object (usually, a class) that mixes in +Emittance::Notifier+ will watch for all events
7
+ # and call the method on that object with the same name as the event's identifier. For example:
8
+ #
9
+ # class MyNotifier
10
+ # extend Emittance::Notifier
11
+ #
12
+ # def self.something_happened(event)
13
+ # puts 'something definitely happened!'
14
+ # end
15
+ # end
16
+ #
17
+ # Whenever an event whose identifiers include +something_happened+ is emitted, +MyNotifier.something_happened+ will
18
+ # be invoked.
19
+ #
20
+ # foo.emit :something_happened
21
+ # # Prints:
22
+ # # something definitely happened!
23
+ #
24
+ # foo.emit :something_else_happened
25
+ # # (nothing)
26
+ #
27
+ # Notice that (1) +MyNotifier+ doesn't need to explicitly listen to `:something_happened`, and (2) no errors or
28
+ # anything occur when an event is emitted for which +MyNotifier+ doesn't have a method defined.
29
+ #
30
+ module Notifier
31
+ # @private
32
+ class << self
33
+ def extended(extender)
34
+ extender.extend Emittance::Watcher
35
+
36
+ extender.watch :@all, :_emittance_handle_event
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def _emittance_handle_event(event)
43
+ identifiers = event.identifiers
44
+ identifiers.each do |identifier|
45
+ formatted_identifier = _emittance_format_identifier(identifier)
46
+ send(formatted_identifier) if respond_to?(formatted_identifier)
47
+ end
48
+ end
49
+
50
+ def _emittance_format_identifier(identifier)
51
+ identifier.to_s.split('/').last
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Emittance
4
- VERSION = '0.0.6'
4
+ VERSION = '0.1.0'
5
5
  end
data/lib/emittance.rb CHANGED
@@ -6,11 +6,13 @@ require 'emittance/errors'
6
6
  require 'emittance/helpers/string_helpers'
7
7
  require 'emittance/helpers/constant_helpers'
8
8
  require 'emittance/event_lookup'
9
+ require 'emittance/dispatcher'
9
10
  require 'emittance/brokerage'
10
11
  require 'emittance/broker'
11
12
  require 'emittance/event'
12
13
  require 'emittance/emitter'
13
14
  require 'emittance/watcher'
15
+ require 'emittance/notifier'
14
16
  require 'emittance/action'
15
17
 
16
18
  ##
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emittance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Guillen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-15 00:00:00.000000000 Z
11
+ date: 2017-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -120,6 +120,9 @@ files:
120
120
  - lib/emittance/broker.rb
121
121
  - lib/emittance/brokerage.rb
122
122
  - lib/emittance/brokers/synchronous.rb
123
+ - lib/emittance/dispatcher.rb
124
+ - lib/emittance/dispatcher/registration_collection_proxy.rb
125
+ - lib/emittance/dispatcher/registration_map.rb
123
126
  - lib/emittance/dispatchers/synchronous.rb
124
127
  - lib/emittance/emitter.rb
125
128
  - lib/emittance/errors.rb
@@ -127,6 +130,7 @@ files:
127
130
  - lib/emittance/event_lookup.rb
128
131
  - lib/emittance/helpers/constant_helpers.rb
129
132
  - lib/emittance/helpers/string_helpers.rb
133
+ - lib/emittance/notifier.rb
130
134
  - lib/emittance/version.rb
131
135
  - lib/emittance/watcher.rb
132
136
  homepage: https://github.com/aastronautss/emittance