tavern 0.0.1 → 1.0.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.
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Tavern
2
2
 
3
- TODO: Write a gem description
3
+ Tavern is a simple implementation of Pub / Sub for Ruby applications, allowing one
4
+ to subscribe to topics (named by a:b:c) and to then publish events. It's designed
5
+ to have a minimal surface area for the api to make it simple to integrate into other
6
+ systems (e.g. so you can publish events over a network).
4
7
 
5
8
  ## Installation
6
9
 
@@ -18,7 +21,27 @@ Or install it yourself as:
18
21
 
19
22
  ## Usage
20
23
 
21
- TODO: Write usage instructions here
24
+
25
+ The core of Tavern is a `Tavern::Hub`, a default one which can be accessed at `Tavern.hub`.
26
+
27
+ The core methods on this object (and any new Taver Hub) are:
28
+
29
+ * `hub.subscribe(topic, callable = nil, &block)` - Creates a subscription for the given topic
30
+ using either a callable object or a block. Will return the instance of the subscription. Note
31
+ that this will also match any child notifications - e.g. publishing `a:b:c` will match subscriptions
32
+ for `a:b` and `a`. The callable should take one argument which includes an environment merged with
33
+ some extra details.
34
+ * `hub.publish(topic, context = {})` - Publishes an event with a given name, including the specified
35
+ context optionally passed into the callable. Topics should be of the form `a:b:c` with no limit on items.
36
+ Will return the full published metadata.
37
+ * `hub.unsubscribe(subscription)` - Given a return from `hub.subscribe`, will unsubscribe it and prevent
38
+ it from receiving any new messages.
39
+
40
+ The idea behind this decoupled architecture is that it doesn't matter how the middle layer is implemented,
41
+ you can just publish and receive messages with no worries. At the moment, subscriptions happen in app.
42
+
43
+ For conveinience sake, we also proxy `subscribe` and `publish` on the `Tavern` object to the default hub
44
+ at `Tavern.hub`.
22
45
 
23
46
  ## Contributing
24
47
 
@@ -2,6 +2,7 @@ require 'tavern/subscription'
2
2
  require 'tavern/subscriptions'
3
3
  require 'active_support/core_ext/module/delegation'
4
4
  require 'active_support/core_ext/object/blank'
5
+ require 'active_support/lazy_load_hooks'
5
6
 
6
7
  module Tavern
7
8
 
@@ -93,9 +94,9 @@ module Tavern
93
94
 
94
95
  def primary=(value)
95
96
  value = !!value
96
- if value != @value
97
- @value = value
98
- ActiveSupport.run_load_hooks :smeg_head_hub, self
97
+ if value != @primary
98
+ @primary = value
99
+ ActiveSupport.run_load_hooks :tavern_hub, self if @primary
99
100
  end
100
101
  end
101
102
 
@@ -1,3 +1,3 @@
1
1
  module Tavern
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -15,6 +15,10 @@ describe Tavern::Hub do
15
15
  published << ctx
16
16
  end
17
17
 
18
+ def times_called
19
+ published.size
20
+ end
21
+
18
22
  end
19
23
  end
20
24
 
@@ -26,43 +30,125 @@ describe Tavern::Hub do
26
30
 
27
31
  describe 'the primary hub' do
28
32
 
29
- it 'should let you query if something is the primary hub'
33
+ after :each do
34
+ # Force a final reset
35
+ Tavern.hub = nil
36
+ end
30
37
 
31
- it 'should run the load hook when the hub is changed'
38
+ it 'should let you query if something is the primary hub' do
39
+ hub.should respond_to(:primary?)
40
+ hub.should_not be_primary
41
+ Tavern.hub.should_not == hub
42
+ Tavern.hub.should be_primary
43
+ end
32
44
 
33
- it 'should unset it when changing the hub'
45
+ it 'should run the load hook when the hub is changed' do
46
+ Tavern.hub # Force it to have loaded before hand.
47
+ called = 0
48
+ found_hub = nil
49
+ ActiveSupport.on_load(:tavern_hub) do |hub|
50
+ called += 1
51
+ found_hub = hub
52
+ end
53
+ called = 0
54
+ Tavern.hub = hub
55
+ called.should == 1
56
+ found_hub.should == hub
57
+ end
34
58
 
35
- it 'should set it to primary when setting it to the hub value'
59
+ it 'should unset it when changing the hub' do
60
+ hub = Tavern.hub
61
+ hub.should be_primary
62
+ Tavern.hub = Tavern::Hub.new
63
+ hub.should_not be_primary
64
+ end
36
65
 
37
- it 'always set the default to be primary'
66
+ it 'should set it to primary when setting it to the hub value' do
67
+ hub = Tavern::Hub.new
68
+ hub.should_not be_primary
69
+ Tavern.hub = hub
70
+ hub.should be_primary
71
+ end
72
+
73
+ it 'always set the default to be primary' do
74
+ # Force a recet to nil
75
+ Tavern.hub = nil
76
+ Tavern.hub.should be_primary
77
+ end
38
78
 
39
79
  end
40
80
 
41
81
  describe '#subscribe' do
42
82
 
43
- it 'should let you subscribe to a top level item'
83
+ let(:tracker) { Struct.new(:called).new(0) }
84
+ let(:callback) { lambda { |e| tracker.called += 1 } }
44
85
 
45
- it 'should let you subscribe to a nested item'
46
-
47
- it 'should let you pass an object'
86
+ it 'should let you subscribe to a top level item' do
87
+ hub.subscribe('x', &callback)
88
+ expect { hub.publish('x') }.to change tracker, :called
89
+ expect { hub.publish('x:y') }.to change tracker, :called
90
+ expect { hub.publish('x:y:z') }.to change tracker, :called
91
+ end
48
92
 
49
- it 'should let you pass a block'
93
+ it 'should let you subscribe to a nested item' do
94
+ hub.subscribe('x:y:z', &callback)
95
+ expect { hub.publish('x:y:z') }.to change tracker, :called
96
+ expect { hub.publish('x:y') }.to_not change tracker, :called
97
+ expect { hub.publish('x') }.to_not change tracker, :called
98
+ end
99
+
100
+ it 'should let you pass an object' do
101
+ callback = Struct.new(:tracker).new(tracker)
102
+ def callback.call(e); tracker.called += 1; end
103
+ hub.subscribe('x', callback)
104
+ expect { hub.publish('x') }.to change tracker, :called
105
+ end
50
106
 
51
- it 'should return a subscription'
107
+ it 'should let you pass a block' do
108
+ hub.subscribe('x') { |e| tracker.called += 1 }
109
+ expect { hub.publish('x') }.to change tracker, :called
110
+ end
52
111
 
53
- it 'should automatically subscribe to lower level nested events'
112
+ it 'should return a subscription' do
113
+ subscription = hub.subscribe('x', &callback)
114
+ subscription.should be_present
115
+ subscription.should be_a Tavern::Subscription
116
+ end
54
117
 
55
- it 'should raise an error when subscribing with an object that does not provide call'
118
+ it 'should raise an error when subscribing with an object that does not provide call' do
119
+ expect do
120
+ hub.subscribe 'test', Object.new
121
+ end.to raise_error ArgumentError
122
+ end
56
123
 
57
124
  end
58
125
 
59
126
  describe '#unsubscribe' do
60
127
 
61
- it 'should remove an object from the subscription pool'
128
+ let(:tracker) { Struct.new(:count, :calls).new(0, []) }
62
129
 
63
- it 'should return the subscription'
130
+ let!(:subscription) do
131
+ t = tracker
132
+ hub.subscribe 'test' do |e|
133
+ t.count += 1
134
+ t.calls << e
135
+ end
136
+ end
64
137
 
65
- it 'should do nothing with a blank item'
138
+ it 'should remove an object from the subscription pool' do
139
+ expect { hub.publish 'test' }.to change tracker, :count
140
+ hub.unsubscribe subscription
141
+ expect { hub.publish 'test' }.to_not change tracker, :count
142
+ end
143
+
144
+ it 'should return the subscription' do
145
+ hub.unsubscribe(subscription).should == subscription
146
+ end
147
+
148
+ it 'should do nothing with a blank item' do
149
+ hub.unsubscribe(nil).should be_nil
150
+ hub.unsubscribe('').should be_nil
151
+ end
66
152
 
67
153
  end
68
154
 
@@ -104,11 +190,12 @@ describe Tavern::Hub do
104
190
  hub.publish 'hello:world', {}
105
191
  end
106
192
 
107
- it 'should notify all subscriptions under the path'
108
-
109
- it 'should not notify unmatched subscriptions on a simple case'
110
-
111
- it 'should not notify unmatched subscriptions on a nested case'
193
+ it 'should notify all subscriptions under the path' do
194
+ expect { hub.publish 'hello:world' }.to change top_level_a, :times_called
195
+ expect { hub.publish 'hello:world' }.to change nested_a, :times_called
196
+ expect { hub.publish 'foo' }.to change top_level_b, :times_called
197
+ expect { hub.publish 'foo' }.to_not change nested_b, :times_called
198
+ end
112
199
 
113
200
  end
114
201
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tavern
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: