wave_box 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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: