brainguy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.yardopts +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.erb +345 -0
  7. data/README.markdown +579 -0
  8. data/Rakefile +21 -0
  9. data/brainguy.gemspec +28 -0
  10. data/examples/include_manifestly_observable.rb +22 -0
  11. data/examples/include_observable.rb +18 -0
  12. data/examples/include_observer.rb +36 -0
  13. data/examples/manual_observable.rb +22 -0
  14. data/examples/open_observer.rb +31 -0
  15. data/examples/proc_observer.rb +10 -0
  16. data/examples/scoped_subscription.rb +39 -0
  17. data/examples/synopsis.rb +56 -0
  18. data/lib/brainguy.rb +34 -0
  19. data/lib/brainguy/basic_notifier.rb +19 -0
  20. data/lib/brainguy/emitter.rb +110 -0
  21. data/lib/brainguy/error_collecting_notifier.rb +26 -0
  22. data/lib/brainguy/error_handling_notifier.rb +63 -0
  23. data/lib/brainguy/event.rb +13 -0
  24. data/lib/brainguy/fluent_emitter.rb +30 -0
  25. data/lib/brainguy/full_subscription.rb +8 -0
  26. data/lib/brainguy/idempotent_emitter.rb +40 -0
  27. data/lib/brainguy/manifest_emitter.rb +78 -0
  28. data/lib/brainguy/manifestly_observable.rb +62 -0
  29. data/lib/brainguy/observable.rb +33 -0
  30. data/lib/brainguy/observer.rb +71 -0
  31. data/lib/brainguy/open_observer.rb +65 -0
  32. data/lib/brainguy/single_event_subscription.rb +31 -0
  33. data/lib/brainguy/subscription.rb +59 -0
  34. data/lib/brainguy/subscription_scope.rb +62 -0
  35. data/lib/brainguy/version.rb +4 -0
  36. data/scripts/benchmark_listener_dispatch.rb +222 -0
  37. data/spec/brainguy/emitter_spec.rb +25 -0
  38. data/spec/brainguy/error_collecting_notifier_spec.rb +19 -0
  39. data/spec/brainguy/error_handling_notifier_spec.rb +63 -0
  40. data/spec/brainguy/manifest_emitter_spec.rb +68 -0
  41. data/spec/brainguy/manifestly_observable_spec.rb +43 -0
  42. data/spec/brainguy/observable_spec.rb +9 -0
  43. data/spec/brainguy/observer_spec.rb +72 -0
  44. data/spec/brainguy/open_observer_spec.rb +57 -0
  45. data/spec/brainguy/single_event_subscription_spec.rb +16 -0
  46. data/spec/brainguy/subscription_scope_spec.rb +72 -0
  47. data/spec/brainguy/subscription_spec.rb +46 -0
  48. data/spec/features/basics_spec.rb +153 -0
  49. data/spec/features/idempotent_events_spec.rb +69 -0
  50. data/spec/features/method_scoped_events_spec.rb +90 -0
  51. data/spec/support/shared_examples_for_eventful_modules.rb +36 -0
  52. metadata +196 -0
@@ -0,0 +1,69 @@
1
+ require "rspec"
2
+ require "brainguy"
3
+
4
+ module Brainguy
5
+ class WebRequest
6
+ attr_reader :events
7
+
8
+ def initialize
9
+ @events = Brainguy::IdempotentEmitter.new(self)
10
+ end
11
+
12
+ def successful_response
13
+ events.emit(:data, "Hello, ")
14
+ events.emit(:data, "World!")
15
+ events.emit(:success)
16
+ end
17
+ end
18
+
19
+ RSpec.describe "idempotent events" do
20
+ it "replays events when a listener subscribes late" do
21
+ r = WebRequest.new
22
+ r.successful_response
23
+ listener = spy("listener")
24
+ r.events.attach(listener)
25
+ expect(listener).to have_received(:call)
26
+ .with(Event[:data, r, ["Hello, "]])
27
+ .ordered
28
+ expect(listener).to have_received(:call)
29
+ .with(Event[:data, r, ["World!"]])
30
+ .ordered
31
+ expect(listener).to have_received(:call)
32
+ .with(Event[:success, r])
33
+ .ordered
34
+ end
35
+
36
+ it "replays events when a single-event handler subscribes late" do
37
+ r = WebRequest.new
38
+ r.successful_response
39
+ expect do |b|
40
+ r.events.on(:data, &b)
41
+ end.to yield_successive_args("Hello, ", "World!")
42
+ end
43
+
44
+ it "passes events on to existing listeners immediately" do
45
+ r = WebRequest.new
46
+ listener = spy("listener")
47
+ r.events.attach(listener)
48
+ r.successful_response
49
+ expect(listener).to have_received(:call)
50
+ .with(Event[:data, r, ["Hello, "]])
51
+ .ordered
52
+ expect(listener).to have_received(:call)
53
+ .with(Event[:data, r, ["World!"]])
54
+ .ordered
55
+ expect(listener).to have_received(:call)
56
+ .with(Event[:success, r])
57
+ .ordered
58
+ end
59
+
60
+ it "does not repeat events to preexisting listeners" do
61
+ r = WebRequest.new
62
+ listener = spy("listener")
63
+ r.events.attach(listener)
64
+ r.successful_response
65
+ r.events.attach(spy("new listener"))
66
+ expect(listener).to have_received(:call).exactly(3).times
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,90 @@
1
+ require "rspec"
2
+
3
+ require "brainguy"
4
+
5
+ describe "method-scoped subscription set" do
6
+ class Kitten
7
+ def play(&block)
8
+ Brainguy.with_subscription_scope(self, block) do |events|
9
+ events.emit(:mew)
10
+ events.emit(:mew)
11
+ events.emit(:pounce)
12
+ events.emit(:hiss)
13
+ events.emit(:purr)
14
+ end
15
+ end
16
+ end
17
+
18
+ it "executes handlers hooked up inside a passed block" do
19
+ kitten = Kitten.new
20
+ event_log = []
21
+ kitten.play do |events|
22
+ events.on(:hiss) do
23
+ event_log << :hiss
24
+ end
25
+ events.on(:pounce) do
26
+ event_log << :pounce
27
+ end
28
+ events.on(:mew) do
29
+ event_log << :mew
30
+ end
31
+ end
32
+ expect(event_log).to eq([:mew, :mew, :pounce, :hiss])
33
+ end
34
+
35
+ it "executes handlers chained onto the method return value" do
36
+ kitten = Kitten.new
37
+ event_log = []
38
+ listener = spy("listener")
39
+ kitten.play.on(:purr) do
40
+ event_log << :purr
41
+ end.on(:pounce) do
42
+ event_log << :pounce
43
+ end.on(:mew) do
44
+ event_log << :mew
45
+ end.attach(listener)
46
+ expect(event_log).to eq([:purr, :pounce, :mew, :mew])
47
+ expect(listener).to have_received(:call).with(Brainguy::Event[:mew, kitten]).twice
48
+ expect(listener).to have_received(:call).with(Brainguy::Event[:pounce, kitten])
49
+ expect(listener).to have_received(:call).with(Brainguy::Event[:hiss, kitten])
50
+ expect(listener).to have_received(:call).with(Brainguy::Event[:purr, kitten])
51
+ end
52
+
53
+ it "returns nil when passed a block" do
54
+ kitten = Kitten.new
55
+ result = kitten.play do
56
+ end
57
+ expect(result).to be_nil
58
+ end
59
+
60
+ class Dog
61
+ include Brainguy::Observable
62
+
63
+ def play_fetch
64
+ emit(:chase_stick)
65
+ end
66
+
67
+ def play(&block)
68
+ with_subscription_scope(block) do |events|
69
+ emit(:bark)
70
+ play_fetch
71
+ emit(:pant)
72
+ end
73
+ end
74
+ end
75
+
76
+ it "can be used in conjunction with an Observable object" do
77
+ dog = Dog.new
78
+ lifetime_listener = spy("lifetime listener")
79
+ scoped_listener = spy("scoped listener")
80
+ dog.events.attach(lifetime_listener)
81
+ dog.play do |events|
82
+ events.attach(scoped_listener)
83
+ end
84
+ dog.play_fetch
85
+ expect(lifetime_listener)
86
+ .to have_received(:call).with(Brainguy::Event[:chase_stick, dog]).twice
87
+ expect(scoped_listener)
88
+ .to have_received(:call).with(Brainguy::Event[:chase_stick, dog]).once
89
+ end
90
+ end
@@ -0,0 +1,36 @@
1
+ module Brainguy
2
+ RSpec.shared_examples "an eventful module" do |the_module|
3
+ let(:coffee_maker_class) {
4
+ Class.new do
5
+
6
+ include the_module
7
+
8
+ def make_coffee
9
+ emit(:heat)
10
+ emit(:drip)
11
+ emit(:done)
12
+ end
13
+ end
14
+ }
15
+
16
+ it "adds an #events attribute" do
17
+ cm = coffee_maker_class.new
18
+ cm.respond_to?(:events)
19
+ end
20
+
21
+ it "adds an #on method for attaching listeners" do
22
+ cm = coffee_maker_class.new
23
+ probe = spy
24
+ cm.on(:done) do
25
+ probe.coffee_done
26
+ end
27
+ cm.make_coffee
28
+ expect(probe).to have_received(:coffee_done)
29
+ end
30
+
31
+ it "provides the #emit helper privately" do
32
+ cm = coffee_maker_class.new
33
+ expect { cm.emit(:foo) }.to raise_error(NoMethodError)
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: brainguy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Avdi Grimm
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: benchmark-ips
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.8.7
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.8.7
83
+ - !ruby/object:Gem::Dependency
84
+ name: seeing_is_believing
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.2'
97
+ description: |-
98
+ A somewhat fancy observer pattern library with
99
+ features like named events and scoped subscriptions.
100
+ email:
101
+ - avdi@avdi.org
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".yardopts"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.erb
111
+ - README.markdown
112
+ - Rakefile
113
+ - brainguy.gemspec
114
+ - examples/include_manifestly_observable.rb
115
+ - examples/include_observable.rb
116
+ - examples/include_observer.rb
117
+ - examples/manual_observable.rb
118
+ - examples/open_observer.rb
119
+ - examples/proc_observer.rb
120
+ - examples/scoped_subscription.rb
121
+ - examples/synopsis.rb
122
+ - lib/brainguy.rb
123
+ - lib/brainguy/basic_notifier.rb
124
+ - lib/brainguy/emitter.rb
125
+ - lib/brainguy/error_collecting_notifier.rb
126
+ - lib/brainguy/error_handling_notifier.rb
127
+ - lib/brainguy/event.rb
128
+ - lib/brainguy/fluent_emitter.rb
129
+ - lib/brainguy/full_subscription.rb
130
+ - lib/brainguy/idempotent_emitter.rb
131
+ - lib/brainguy/manifest_emitter.rb
132
+ - lib/brainguy/manifestly_observable.rb
133
+ - lib/brainguy/observable.rb
134
+ - lib/brainguy/observer.rb
135
+ - lib/brainguy/open_observer.rb
136
+ - lib/brainguy/single_event_subscription.rb
137
+ - lib/brainguy/subscription.rb
138
+ - lib/brainguy/subscription_scope.rb
139
+ - lib/brainguy/version.rb
140
+ - scripts/benchmark_listener_dispatch.rb
141
+ - spec/brainguy/emitter_spec.rb
142
+ - spec/brainguy/error_collecting_notifier_spec.rb
143
+ - spec/brainguy/error_handling_notifier_spec.rb
144
+ - spec/brainguy/manifest_emitter_spec.rb
145
+ - spec/brainguy/manifestly_observable_spec.rb
146
+ - spec/brainguy/observable_spec.rb
147
+ - spec/brainguy/observer_spec.rb
148
+ - spec/brainguy/open_observer_spec.rb
149
+ - spec/brainguy/single_event_subscription_spec.rb
150
+ - spec/brainguy/subscription_scope_spec.rb
151
+ - spec/brainguy/subscription_spec.rb
152
+ - spec/features/basics_spec.rb
153
+ - spec/features/idempotent_events_spec.rb
154
+ - spec/features/method_scoped_events_spec.rb
155
+ - spec/support/shared_examples_for_eventful_modules.rb
156
+ homepage: https://github.com/avdi/brainguy
157
+ licenses:
158
+ - MIT
159
+ metadata: {}
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubyforge_project:
176
+ rubygems_version: 2.2.2
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: An Observer pattern library
180
+ test_files:
181
+ - spec/brainguy/emitter_spec.rb
182
+ - spec/brainguy/error_collecting_notifier_spec.rb
183
+ - spec/brainguy/error_handling_notifier_spec.rb
184
+ - spec/brainguy/manifest_emitter_spec.rb
185
+ - spec/brainguy/manifestly_observable_spec.rb
186
+ - spec/brainguy/observable_spec.rb
187
+ - spec/brainguy/observer_spec.rb
188
+ - spec/brainguy/open_observer_spec.rb
189
+ - spec/brainguy/single_event_subscription_spec.rb
190
+ - spec/brainguy/subscription_scope_spec.rb
191
+ - spec/brainguy/subscription_spec.rb
192
+ - spec/features/basics_spec.rb
193
+ - spec/features/idempotent_events_spec.rb
194
+ - spec/features/method_scoped_events_spec.rb
195
+ - spec/support/shared_examples_for_eventful_modules.rb
196
+ has_rdoc: