wave_box 0.4.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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in wavebox.gemspec
4
+ gemspec
5
+
6
+ gem 'redis'
7
+
8
+ group :development do
9
+ gem 'guard'
10
+ gem 'guard-minitest'
11
+ gem 'rb-inotify', :require => false
12
+ gem 'rb-fsevent', :require => false
13
+ gem 'rb-fchange', :require => false
14
+ gem 'growl'
15
+ gem 'mock_redis'
16
+ end
data/Guardfile ADDED
@@ -0,0 +1,14 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'minitest', :colour => true do
5
+ # with Minitest::Unit
6
+ watch(%r|^test/test_(.*)\.rb|)
7
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
8
+ watch(%r|^test/test_helper\.rb|) { "test" }
9
+
10
+ # with Minitest::Spec
11
+ watch(%r|^spec/(.*)_spec\.rb|)
12
+ watch(%r|^lib/(.*)\.rb|) { |m| "spec/#{m[1]}_spec.rb" }
13
+ watch(%r|^spec/spec_helper\.rb|) { "spec" }
14
+ end
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # WaveBox
2
+
3
+ A redis-based messaging system
4
+
5
+ inspired by [Tumblr Staircar](http://engineering.tumblr.com/post/7819252942/staircar-redis-powered-notifications)
6
+
7
+ ## Features
8
+
9
+ * Easy to use
10
+ * Works well with redis presharding
11
+ * Simple memory usage control
12
+ * Tested in production environment
13
+
14
+ ## Example
15
+
16
+ ```ruby
17
+ require 'wave_box'
18
+
19
+ class User
20
+ include ::WaveBox::GenerateWave
21
+ include ::WaveBox::ReceiveWave
22
+
23
+ can_generate_wave :name => "message",
24
+ :redis => :wave_redis_instance,
25
+ # waves with timestamp older than expire will be discarded
26
+ :expire => 60 * 60 * 24 * 7, # One week
27
+ # only store last 20 waves
28
+ :max_size => 20,
29
+ :id => :wave_box_id
30
+
31
+ can_receive_wave :name => "message",
32
+ :redis => :wave_redis_instance,
33
+ :expire => 60 * 60 * 24 * 7, # One week
34
+ :max_size => 20,
35
+ :id => :wave_box_id
36
+
37
+ def wave_redis_instance
38
+ Redis.new # return a redis instance
39
+ end
40
+
41
+ def wave_box_id
42
+ self.id
43
+ end
44
+ end
45
+
46
+ sender = User.new
47
+ # => #<User:0x007f85631b9a50>
48
+ receiver = User.new
49
+ # => #<User:0x007f85631cf940>
50
+
51
+ # Send a wave from sender to receiver
52
+ sender.generate_message "hi", receiver
53
+
54
+ # Find all message waves in sender's outbox
55
+ sender.generated_message_after(0)
56
+ # => ["hi"]
57
+
58
+ # Find all message waves in receiver's inbox
59
+ receiver.received_message_after(0)
60
+ # => ["hi"]
61
+ ```
62
+
63
+ ## Install
64
+
65
+ ```
66
+ gem install wave_box
67
+ ```
68
+
69
+ ## License
70
+
71
+ the [MIT License](http://www.opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,60 @@
1
+ module WaveBox
2
+ class Box
3
+ attr_reader :expire, :max_size
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ @expire = options[:expire]
8
+ @max_size = options[:max_size]
9
+ @redis = options[:redis]
10
+ @key = options[:key]
11
+ @encode = options[:encode]
12
+ end
13
+
14
+ def push(value, time = Time.now)
15
+ if @encode == false
16
+ v = value
17
+ else
18
+ v = encode(value)
19
+ end
20
+ @redis.zadd(@key, time.to_i, v)
21
+
22
+ truncate!
23
+ end
24
+
25
+ def size
26
+ @redis.zcard @key
27
+ end
28
+
29
+ def after(time)
30
+ items = @redis.zrangebyscore( @key, "#{time.to_i}", "+inf")
31
+
32
+ if @encode == false
33
+ items
34
+ else
35
+ items.map { |x| decode(x) }
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # TODO: Current encode/decode solution sucks,
42
+ # it create too much storage overhead
43
+ def encode(str)
44
+ "#{str}:#{Time.now.to_i}:#{box_counter}"
45
+ end
46
+
47
+ def decode(str)
48
+ str.split(':')[0..-3].join(':')
49
+ end
50
+
51
+ def box_counter
52
+ @redis.incr("#{@key}:counter")
53
+ end
54
+
55
+ def truncate!
56
+ @redis.zremrangebyscore( @key, 0, (Time.now - @expire).to_f ) if @expire
57
+ @redis.zremrangebyrank( @key, 0, -1*(@max_size + 1) ) if @max_size
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,86 @@
1
+ module WaveBox
2
+ module GenerateWave
3
+ def method_missing(method, *args, &block)
4
+ if method.to_s =~ /generated_(\w+)_after/
5
+ generated_after( $1, *args )
6
+ elsif method.to_s =~ /generate_(\w+)/
7
+ generate( $1, *args)
8
+ else
9
+ super
10
+ end
11
+ end
12
+
13
+ # method missing with good manner
14
+ def respond_to_missing?(method, *)
15
+ (method =~ /generated_(\w+)_after/) || (method =~ /generate_(\w+)/) || super
16
+ end
17
+
18
+ def generate(name, wave, receiver, time = Time.now, options = {})
19
+ send("#{name}_outbox").push wave, time unless options[:outbox] == false
20
+
21
+ if receiver.respond_to? :each
22
+ receiver.each do |rec|
23
+ rec.receive(name, wave, time)
24
+ end
25
+ else
26
+ receiver.receive(name, wave, time)
27
+ end
28
+ end
29
+
30
+ def generated_after(name, time)
31
+ send("#{name}_outbox").after(time)
32
+ end
33
+
34
+ module ClassMethods
35
+ def can_generate_wave(config)
36
+ raise ArgumentError, "Missing redis" unless config[:redis]
37
+ raise ArgumentError, "Missing id lambda" unless config[:id]
38
+ raise ArgumentError, "Missing wave name" unless config[:name]
39
+
40
+ name = config[:name]
41
+ [:redis, :expire, :max_size, :encode].each do |c|
42
+ define_method "#{name}_outbox_#{c}" do config[c] end
43
+ end
44
+
45
+ if config[:redis].is_a? Symbol
46
+ class_eval <<-RUBY
47
+ def #{name}_outbox_redis_instance
48
+ send( "#{config[:redis]}" )
49
+ end
50
+ RUBY
51
+ else
52
+ define_method "#{name}_outbox_redis_instance" do config[:redis] end
53
+ end
54
+
55
+ if config[:id].is_a? Symbol
56
+ class_eval <<-RUBY
57
+ def #{name}_outbox_id
58
+ send("#{config[:id]}")
59
+ end
60
+ RUBY
61
+ else
62
+ define_method "#{name}_outbox_id" do config[:redis] end
63
+ end
64
+
65
+ define_method "#{name}_outbox_key" do "wave:#{name}:outbox:#{send("#{name}_outbox_id")}" end
66
+
67
+ class_eval <<-RUBY
68
+ def #{name}_outbox
69
+ @#{name}_outbox ||= WaveBox::Box.new({
70
+ :encode => #{name}_outbox_encode,
71
+ :redis => #{name}_outbox_redis_instance,
72
+ :key => #{name}_outbox_key,
73
+ :expire => #{name}_outbox_expire,
74
+ :max_size => #{name}_outbox_max_size})
75
+ end
76
+ RUBY
77
+
78
+ end
79
+ end
80
+
81
+ def self.included(host)
82
+ host.extend ClassMethods
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,73 @@
1
+ module WaveBox
2
+ module ReceiveWave
3
+ def method_missing(method, *args, &block)
4
+ if method.to_s =~ /received_(\w+)_after/
5
+ received_after( $1, *args )
6
+ elsif method.to_s =~ /receive_(\w+)/
7
+ receive( $1, *args)
8
+ else
9
+ super
10
+ end
11
+ end
12
+
13
+ def receive(name, wave, time = Time.now)
14
+ send("#{name}_inbox").push(wave, time)
15
+ end
16
+
17
+ def received_after(name, time)
18
+ send("#{name}_inbox").after(time)
19
+ end
20
+
21
+ module ClassMethods
22
+ def can_receive_wave(config)
23
+ raise ArgumentError, "Missing redis config" unless config[:redis]
24
+ raise ArgumentError, "Missing id lambda" unless config[:id]
25
+ raise ArgumentError, "Missing wave name" unless config[:name]
26
+
27
+ name = config[:name]
28
+
29
+ [:expire, :max_size, :encode].each do |c|
30
+ define_method "#{name}_inbox_#{c}" do config[c] end
31
+ end
32
+
33
+ if config[:redis].is_a? Symbol
34
+ class_eval <<-RUBY
35
+ def #{name}_inbox_redis_instance
36
+ send("#{config[:redis]}")
37
+ end
38
+ RUBY
39
+ else
40
+ define_method "#{name}_inbox_redis_instance" do config[:redis] end
41
+ end
42
+
43
+ if config[:id].is_a? Symbol
44
+ class_eval <<-RUBY
45
+ def #{name}_inbox_id
46
+ send("#{config[:id]}")
47
+ end
48
+ RUBY
49
+ else
50
+ define_method "#{name}_inbox_id" do config[:redis] end
51
+ end
52
+
53
+ define_method "#{name}_inbox_key" do "wave:#{name}:inbox:#{send("#{name}_inbox_id")}" end
54
+
55
+ class_eval <<-RUBY
56
+ def #{name}_inbox
57
+ @#{name}_inbox ||= WaveBox::Box.new({
58
+ :redis => #{name}_inbox_redis_instance,
59
+ :key => #{name}_inbox_key,
60
+ :encode => #{name}_inbox_encode,
61
+ :expire => #{name}_inbox_expire,
62
+ :max_size => #{name}_inbox_max_size})
63
+ end
64
+ RUBY
65
+ end
66
+ end
67
+
68
+ def self.included(host)
69
+ host.extend ClassMethods
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module WaveBox
2
+ VERSION = "0.4.0"
3
+ end
File without changes
data/lib/wave_box.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'wave_box/receive_wave'
2
+ require "wave_box/generate_wave"
3
+ require "wave_box/box"
4
+
5
+ require "redis"
@@ -0,0 +1,6 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/spec'
3
+ require "minitest/mock"
4
+ require "wave_box"
5
+ require 'minitest/unit'
6
+ require 'minitest/pride'
@@ -0,0 +1,89 @@
1
+ require 'mock_redis'
2
+ require 'spec_helper'
3
+
4
+ describe WaveBox::Box do
5
+ describe "A box without limit" do
6
+ before do
7
+ @box = WaveBox::Box.new :redis => MockRedis.new,
8
+ :key => "test_key"
9
+ end
10
+
11
+ it "should save pushed item" do
12
+ @box.push(1)
13
+
14
+ @box.size.must_equal 1
15
+ end
16
+
17
+ it "should return pushed items based on a timestamp" do
18
+ @box.push("foo")
19
+
20
+ @box.after(0).size.must_equal 1
21
+ @box.after(0)[0].must_equal "foo"
22
+ end
23
+
24
+ it "should able to handle two identical items in a single box" do
25
+ @box.push("foo")
26
+ @box.push("foo")
27
+
28
+ @box.after(0).size.must_equal 2
29
+ @box.after(0).each { |x| x.must_equal "foo" }
30
+ end
31
+
32
+ it "should not truncate any item" do
33
+ 100.times { @box.push "foo" }
34
+
35
+ @box.size.must_equal 100
36
+
37
+ @box.push "bar", Time.now - 10000
38
+ @box.after(0)[0].must_equal "bar"
39
+ end
40
+ end
41
+
42
+ describe "A box with limit" do
43
+ before do
44
+ @max_size = 10
45
+ @expire = 10*60
46
+ @box_with_limit = WaveBox::Box.new({
47
+ :redis => MockRedis.new,
48
+ :key => "test_key",
49
+ :expire => @expire,
50
+ :max_size => @max_size })
51
+ end
52
+
53
+ it "should know its limit" do
54
+ @box_with_limit.max_size.must_equal @max_size
55
+ @box_with_limit.expire.must_equal @expire
56
+ end
57
+
58
+ it "should truncate items over max size limit" do
59
+ 20.times { @box_with_limit.push("foo") }
60
+
61
+ @box_with_limit.size.must_equal @max_size
62
+ end
63
+
64
+ it "should truncate items over expire time" do
65
+ @box_with_limit.push "foo", Time.now - (@expire + 10)
66
+
67
+ @box_with_limit.size.must_equal 0
68
+ end
69
+ end
70
+
71
+ describe "A box can be set to not encode items" do
72
+ before do
73
+ @box = WaveBox::Box.new({
74
+ :redis => MockRedis.new,
75
+ :key => "test_key",
76
+ :expire => 10*60,
77
+ :max_size => 10,
78
+ :encode => false})
79
+ end
80
+
81
+ it "should not be able to handle two identical items in a single box" do
82
+ @box.push("foo")
83
+ @box.push("foo")
84
+
85
+ @box.after(0).size.must_equal 1
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,278 @@
1
+ require 'spec_helper'
2
+ require "mock_redis"
3
+
4
+ describe WaveBox::GenerateWave do
5
+ it "should raise an ArgumentError if no wave name is given" do
6
+ lambda do
7
+ class A
8
+ include WaveBox::GenerateWave
9
+
10
+ can_generate_wave :id => :box_id,
11
+ :redis => MockRedis.new
12
+ end
13
+ end.must_raise ArgumentError
14
+ end
15
+
16
+ it "should raise an argument error if no redis config is given" do
17
+ lambda do
18
+ class A
19
+ include WaveBox::GenerateWave
20
+
21
+ can_generate_wave :id => :box_id,
22
+ :name => "message"
23
+ end
24
+ end.must_raise ArgumentError
25
+ end
26
+
27
+ it "should raise an ArgumentError if no box_id config is given" do
28
+ lambda do
29
+ class A
30
+ include WaveBox::GenerateWave
31
+
32
+ can_generate_wave :redis => MockRedis.new,
33
+ :name => "message"
34
+ end
35
+ end.must_raise ArgumentError
36
+ end
37
+
38
+ it "Can accept a symbol as redis parameter" do
39
+ class Sender
40
+ include WaveBox::GenerateWave
41
+
42
+ can_generate_wave :name => "message",
43
+ :redis => :dynamic_instance,
44
+ :expire => 60*10,
45
+ :max_size => 10,
46
+ # You have to specify a box id which
47
+ # is unique among all receiver
48
+ :id => :box_id
49
+
50
+ def dynamic_instance
51
+ return MockRedis.new
52
+ end
53
+
54
+ def box_id
55
+ object_id
56
+ end
57
+ end
58
+
59
+ class Receiver
60
+ include WaveBox::ReceiveWave
61
+
62
+ can_receive_wave :name => "message",
63
+ :redis => :dynamic_instance,
64
+ :expire => 60*10,
65
+ :max_size => 10,
66
+ # You have to specify a box id which
67
+ # is unique among all receiver
68
+ :id => :box_id
69
+ def dynamic_instance
70
+ return MockRedis.new
71
+ end
72
+
73
+ def box_id
74
+ object_id
75
+ end
76
+ end
77
+
78
+ s = Sender.new
79
+ r = Receiver.new
80
+
81
+ s.message_outbox.wont_be_nil
82
+ s.generate_message "foo", r
83
+
84
+ s.generated_message_after(0).size.must_equal 1
85
+ r.received_message_after(0).size.must_equal 1
86
+ end
87
+
88
+ describe "A normal generator usage" do
89
+ before do
90
+ class User
91
+ include WaveBox::GenerateWave
92
+
93
+ can_generate_wave :name => "message",
94
+ :redis => MockRedis.new,
95
+ :expire => 60*10,
96
+ :max_size => 10,
97
+ # You have to specify a box id which
98
+ # is unique among all receiver
99
+ :id => :box_id
100
+
101
+ def box_id
102
+ object_id
103
+ end
104
+ end
105
+
106
+ @user = User.new
107
+ end
108
+
109
+ it "should have an outbox with name" do
110
+ @user.message_outbox.wont_be_nil
111
+ end
112
+
113
+ it "should save the box id lambda and call it when needed" do
114
+ @user.message_outbox_id.must_equal @user.object_id
115
+ end
116
+
117
+ describe "Sending wave" do
118
+ before do
119
+ class Receiver
120
+ include WaveBox::ReceiveWave
121
+
122
+ can_receive_wave :name => "message",
123
+ :redis => MockRedis.new,
124
+ :expire => 60*10,
125
+ :max_size => 10,
126
+ # You have to specify a box id which
127
+ # is unique among all receiver
128
+ :id => :box_id
129
+
130
+ def box_id
131
+ object_id
132
+ end
133
+ end
134
+ @receiver = Receiver.new
135
+ @wave = "foo"
136
+ end
137
+
138
+ it "should be able to send wave to a receiver" do
139
+ @user.generate "message", @wave, @receiver
140
+
141
+ @user.message_outbox.size.must_equal 1
142
+ @user.message_outbox.after(0)[0].must_equal @wave
143
+
144
+ @receiver.message_inbox.size.must_equal 1
145
+ @receiver.message_inbox.after(0)[0].must_equal @wave
146
+ end
147
+
148
+ it "should be able to send multiple waves to a receiver and record them
149
+ in the outbox" do
150
+ n = 10
151
+ n.times do |i|
152
+ @user.generate "message", @wave, @receiver
153
+
154
+ @user.message_outbox.size.must_equal i+1
155
+ @receiver.message_inbox.size.must_equal i+1
156
+ end
157
+ end
158
+
159
+ it "should be able to save options in its outbox" do
160
+ @user.generate "message", @wave, @receiver, Time.now - 10000
161
+ @user.message_outbox.after(0).size.must_equal 0
162
+ end
163
+
164
+ it "should be able to save options in the receiver's inbox" do
165
+ @user.generate "message", @wave, @receiver, Time.now - 10000
166
+ # This wave will be truncated
167
+ @receiver.message_inbox.after(0).size.must_equal 0
168
+ end
169
+
170
+ it "should have a helper to retrieve outbox after..." do
171
+ @user.generated_after("message", 0).must_equal @user.message_outbox.after(0)
172
+ end
173
+
174
+ it "can be customized to not save a backup in its outbox in a sepcify call" do
175
+ @user.generate "message", @wave, @receiver, Time.now, :outbox => false
176
+
177
+ @user.message_outbox.after(0).size.must_equal 0
178
+ end
179
+
180
+ it "should utilize method_missing to provide some much better api" do
181
+ @user.generate_message @wave, @receiver
182
+
183
+ @user.generated_message_after(0).size.must_equal 1
184
+
185
+ @receiver.message_inbox.size.must_equal 1
186
+ @receiver.message_inbox.after(0)[0].must_equal @wave
187
+ end
188
+
189
+ it "should implement method missing politely" do
190
+ @user.respond_to?(:generate_message).must_equal true
191
+ @user.respond_to?(:generated_message_after).must_equal true
192
+ end
193
+ end
194
+
195
+ end
196
+
197
+ describe "USAGE: can generate multiple waves in a single class" do
198
+ before do
199
+ class MultipleSender
200
+ include WaveBox::GenerateWave
201
+
202
+ can_generate_wave :name => "message",
203
+ :redis => MockRedis.new,
204
+ :expire => 60*10,
205
+ :max_size => 10,
206
+ # You have to specify a box id which
207
+ # is unique among all receiver
208
+ :id => :box_id
209
+
210
+ can_generate_wave :name => "stone",
211
+ :redis => MockRedis.new,
212
+ :expire => 60*10,
213
+ :max_size => 10,
214
+ # You have to specify a box id which
215
+ # is unique among all receiver
216
+ :id => :box_id
217
+
218
+
219
+ def box_id
220
+ object_id
221
+ end
222
+ end
223
+
224
+ class MultipleReceiver
225
+ include WaveBox::ReceiveWave
226
+
227
+ can_receive_wave :name => "message",
228
+ :redis => MockRedis.new,
229
+ :expire => 60*10,
230
+ :max_size => 10,
231
+ # You have to specify a box id which
232
+ # is unique among all receiver
233
+ :id => :box_id
234
+
235
+ can_receive_wave :name => "stone",
236
+ :redis => MockRedis.new,
237
+ :expire => 60*10,
238
+ :max_size => 10,
239
+ # You have to specify a box id which
240
+ # is unique among all receiver
241
+ :id => :box_id
242
+
243
+
244
+ def box_id
245
+ object_id
246
+ end
247
+ end
248
+
249
+ @sender = MultipleSender.new
250
+ @receiver = MultipleReceiver.new
251
+ end
252
+
253
+ it "Should have multiple outbox" do
254
+ @sender.message_outbox.wont_be_nil
255
+ @sender.stone_outbox.wont_be_nil
256
+ end
257
+
258
+ it "Should have multiple outbox key" do
259
+ @sender.message_outbox_key.wont_equal @sender.stone_outbox_key
260
+ end
261
+
262
+ it "Should be able to send multiple type of waves without
263
+ conflicting each other" do
264
+ @sender.generate_message "foo", @receiver
265
+ @sender.generated_message_after(0).size.must_equal 1
266
+ @receiver.received_after("message", 0).size.must_equal 1
267
+
268
+ @sender.generate_stone "bar", @receiver
269
+
270
+ @sender.generated_message_after(0).size.must_equal 1
271
+ @sender.generated_stone_after(0).size.must_equal 1
272
+
273
+ @receiver.received_message_after(0).size.must_equal 1
274
+ @receiver.received_stone_after(0).size.must_equal 1
275
+ end
276
+ end
277
+ end
278
+
@@ -0,0 +1,75 @@
1
+ require "spec_helper"
2
+ require 'mock_redis'
3
+
4
+ describe WaveBox::ReceiveWave do
5
+ it "should raise an argument error if no name given" do
6
+ lambda do
7
+ class A
8
+ include WaveBox::ReceiveWave
9
+
10
+ can_receive_wave :id => :box_id,
11
+ :redis => MockRedis.new
12
+ end
13
+ end.must_raise ArgumentError
14
+ end
15
+
16
+ it "should raise an argument error if no redis config is given" do
17
+ lambda do
18
+ class A
19
+ include WaveBox::ReceiveWave
20
+
21
+ can_receive_wave :id => :box_id,
22
+ :name => "message"
23
+ end
24
+ end.must_raise ArgumentError
25
+ end
26
+
27
+ it "should raise an ArgumentError if no box_id config is given" do
28
+ lambda do
29
+ class A
30
+ include WaveBox::ReceiveWave
31
+
32
+ can_receive_wave :redis => :box_id,
33
+ :name => "message"
34
+ end
35
+ end.must_raise ArgumentError
36
+ end
37
+
38
+ describe "A normal receiver usage" do
39
+ before do
40
+ class User
41
+ include WaveBox::ReceiveWave
42
+
43
+ can_receive_wave :name => "message",
44
+ :redis => MockRedis.new,
45
+ :expire => 60*10,
46
+ :max_size => 10,
47
+ # You have to specify a box id which
48
+ # is unique among all receiver
49
+ :id => :box_id
50
+
51
+ def box_id
52
+ object_id
53
+ end
54
+ end
55
+
56
+ @user = User.new
57
+ @wave = "foo"
58
+ end
59
+
60
+ it "should have an inbox" do
61
+ @user.message_inbox.wont_be_nil
62
+ end
63
+
64
+ it "should be able to receive wave and save it to its inbox" do
65
+ @user.receive("message", @wave)
66
+
67
+ @user.message_inbox.size.must_equal 1
68
+ @user.message_inbox.after(0)[0].must_equal @wave
69
+ end
70
+
71
+ it "should have a helper to retrieve inbox after..." do
72
+ @user.received_message_after(0).must_equal @user.message_inbox.after(0)
73
+ end
74
+ end
75
+ end
data/wave_box.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "wave_box/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "wave_box"
7
+ s.version = WaveBox::VERSION
8
+ s.authors = ["Poga Po"]
9
+ s.email = ["poga.bahamut@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Redis-based Push-style messaging}
12
+ s.description = %q{A simple push style messaging based on redis}
13
+
14
+ s.rubyforge_project = "wavebox"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ s.licenses = "MIT"
21
+
22
+ # specify any dependencies here; for example:
23
+ # s.add_development_dependency "rspec"
24
+ s.add_runtime_dependency "redis"
25
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wave_box
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Poga Po
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: redis
16
+ requirement: &70280405090200 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70280405090200
25
+ description: A simple push style messaging based on redis
26
+ email:
27
+ - poga.bahamut@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - Guardfile
35
+ - README.md
36
+ - Rakefile
37
+ - lib/wave_box.rb
38
+ - lib/wave_box/box.rb
39
+ - lib/wave_box/generate_wave.rb
40
+ - lib/wave_box/receive_wave.rb
41
+ - lib/wave_box/version.rb
42
+ - lib/wave_box/wave.rb
43
+ - spec/spec_helper.rb
44
+ - spec/wave_box/box_spec.rb
45
+ - spec/wave_box/generate_wave_spec.rb
46
+ - spec/wave_box/receive_wave_spec.rb
47
+ - wave_box.gemspec
48
+ homepage: ''
49
+ licenses:
50
+ - MIT
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project: wavebox
69
+ rubygems_version: 1.8.10
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Redis-based Push-style messaging
73
+ test_files:
74
+ - spec/spec_helper.rb
75
+ - spec/wave_box/box_spec.rb
76
+ - spec/wave_box/generate_wave_spec.rb
77
+ - spec/wave_box/receive_wave_spec.rb
78
+ has_rdoc: