jsvd-blackboard 0.2.3

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/ChangeLog ADDED
@@ -0,0 +1,41 @@
1
+ == 0.2.3 / 2009-01-16
2
+
3
+ * Fixed subsubfolders
4
+
5
+ == 0.2.2 / 2009-01-15
6
+
7
+ * Removed overriden Folder#keys. Now Hash#keys is called.
8
+
9
+ == 0.2.1 / 2009-01-15
10
+
11
+ * Fixed Folder#_update
12
+
13
+ == 0.2.0 / 2009-01-15
14
+
15
+ * New fluent interface
16
+
17
+ == 0.1.4 / 2008-12-15
18
+
19
+ * Imposed upper bound on ttl to #seconds in 30 days
20
+
21
+ == 0.1.3 / 2008-12-12
22
+
23
+ * Blackboard will only replace Data objects if new is..newer
24
+
25
+ == 0.1.2 / 2008-12-11
26
+
27
+ * TTL now configured per-folder (or defaults to BB's generic ttl)
28
+
29
+ == 0.1.1 / 2008-12-09
30
+
31
+ * Improved get method error handling
32
+
33
+ == 0.1.0 / 2008-12-09
34
+
35
+ * Added expiration times
36
+ * Added folders and data objects
37
+ * Added one memcache instance per folder
38
+
39
+ == 0.0.1 / 2008-11-28
40
+
41
+ * initial release
data/README ADDED
@@ -0,0 +1,62 @@
1
+
2
+ = blackboard
3
+
4
+
5
+ == Description
6
+
7
+ BlackBoard provides a folder-layer to memcache-client. A BlackBoard is created with a static structure of folders and items.
8
+
9
+ bb = Pulso::BlackBoard.new :ttl => 2 do
10
+ folder :folder1, [:name1] do
11
+ folder :folder1, [:name1, :name2]
12
+ folder :folder2, [:name2]
13
+ folder :folder3, [:name2]
14
+ end
15
+
16
+ It is aimed at quickly writing and reading, usually attached to EventMachine, for example.
17
+ Objects written to the blackboard must answer to :timestamp, for they will expire.
18
+
19
+ class TestObject
20
+ attr_reader :timestamp
21
+ def initialize; @timestamp = Time.now; end
22
+ end
23
+
24
+ obj = TestObject.new
25
+
26
+ To write an item from a folder:
27
+
28
+ bb.folder1.folder1.name1 = obj
29
+
30
+ To retrieve an item from a folder
31
+
32
+ obj = bb.folder1.folder1.name1
33
+
34
+ To retrive all items in a folder:
35
+
36
+ items = bb.folder1
37
+ obj = items[:folder1][:name1]
38
+
39
+ == Installation
40
+
41
+ === Archive Installation
42
+
43
+ rake install
44
+
45
+ === Gem Installation
46
+
47
+ gem install blackboard
48
+
49
+
50
+ == Features/Problems
51
+
52
+ Must include Pulso module to use.
53
+ Fully specced.
54
+
55
+ == Synopsis
56
+
57
+
58
+ == Copyright
59
+
60
+ Author:: João Duarte <jsvduarte@gmail.com>
61
+ Copyright:: Copyright (c) 2008 jsvd
62
+ License::
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'rake/contrib/sshpublisher'
10
+ require 'spec/rake/spectask'
11
+ require 'fileutils'
12
+ require 'metric_fu'
13
+ include FileUtils
14
+
15
+ MetricFu::CHURN_OPTIONS = {:scm => :git}
16
+ MetricFu::DIRECTORIES_TO_FLOG = ['lib']
17
+ MetricFu::SAIKURO_OPTIONS = {"--input_directory" => 'lib'}
18
+
19
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
20
+ task :default => [:test]
21
+ #task :package => [:clean]
22
+
23
+ Rake::TestTask.new("test") do |t|
24
+ t.libs << "test"
25
+ t.pattern = "test/**/*_test.rb"
26
+ t.verbose = true
27
+ end
28
+
29
+
30
+ desc "Run all examples with RCov"
31
+ Spec::Rake::SpecTask.new('examples_with_rcov') do |t|
32
+ t.spec_files = FileList['spec/**/*.rb']
33
+ t.rcov = true
34
+ t.rcov_opts = ['--exclude', 'examples']
35
+ end
36
+
37
+ task :cruise => [ "metrics:flog", "metrics:churn", "metrics:coverage", "metrics:saikuro" ]
@@ -0,0 +1,30 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = "blackboard"
3
+ s.version = "0.2.3"
4
+ s.platform = Gem::Platform::RUBY
5
+ s.has_rdoc = false
6
+ s.summary = ""
7
+ s.description = ""
8
+ s.author = "João Duarte"
9
+ s.email = "jsvduarte@gmail.com"
10
+ s.executables = %w( )
11
+ s.bindir = "bin"
12
+ s.require_path = "lib"
13
+
14
+ s.add_dependency('memcache-client', '>=1.4.0')
15
+ s.required_ruby_version = '>= 1.8.5'
16
+
17
+ s.files = %w(
18
+ test
19
+ test/test_helper.rb
20
+ test/blackboard_test.rb
21
+ lib
22
+ lib/blackboard.rb
23
+ README
24
+ spec
25
+ spec/blackboard_spec.rb
26
+ ChangeLog
27
+ Rakefile
28
+ blackboard.gemspec)
29
+
30
+ end
data/lib/blackboard.rb ADDED
@@ -0,0 +1,143 @@
1
+ # vim: expandtab : tabstop=2 : shiftwidth=2 : softtabstop=2
2
+
3
+ module Pulso
4
+
5
+ class Folder < Hash
6
+
7
+ attr_reader :name, :ttl
8
+
9
+ def initialize name, children, args = {}, &block
10
+ @name = name
11
+
12
+ @items = {}
13
+ @folders = []
14
+ @ttl = args[:ttl]
15
+ @cache = args[:cache]
16
+
17
+ raise ArgumentError, "Pulso::Folder.new should receive name, keys, cache and ttl" if @ttl.nil? || args[:cache].nil?
18
+ raise ArgumentError, "Pulso::Folder.new should not receive ttl bigger than #seconds in 30 days" if @ttl > 2592000
19
+
20
+ create_children children
21
+
22
+ instance_eval(&block) unless block.nil?
23
+
24
+ end
25
+
26
+ def method_missing folder
27
+ raise BlackBoardError, "Folder #{folder} not found"
28
+ end
29
+
30
+ def _update
31
+ @items.keys.each do |k|
32
+ self[k] = get k
33
+ end
34
+ @folders.each {|f| self[f]._update }
35
+ end
36
+
37
+ private
38
+ def folder name, keys, args = {}, &block
39
+ raise BlackBoardError, "Folder #{name} already exists" if self.has_key?(name)
40
+ ttl = args[:ttl]
41
+ ttl ||= @ttl
42
+ @folders << name
43
+ self[name] = Pulso::Folder.new "#{@name}.#{name}", keys, :cache => @cache, :ttl => ttl, &block
44
+ instance_eval %Q{def #{name}; self[:#{name}]._update ;self[:#{name}]; end}
45
+
46
+ end
47
+
48
+ def create_children children
49
+ children.each do |child|
50
+ self[child] = nil
51
+ instance_eval %Q{
52
+ def #{child}=(object); add :#{child}, object; end
53
+ def #{child}; self[:#{child}] = get :#{child}; end}
54
+ @items[child] = Time.at 0
55
+ end
56
+ end
57
+
58
+ def add name, object
59
+ obj_ttl = (@ttl - (Time.now - object.timestamp)).round
60
+ return unless obj_ttl > 0
61
+ return if object.timestamp < @items[name]
62
+
63
+ @items[name] = object.timestamp
64
+ obj = Pulso::Data.new(name, object)
65
+ @cache.set "#{@name}.#{name}", obj, obj_ttl
66
+ end
67
+
68
+ def get obj_name
69
+ raise BlackBoardError, "Key #{obj_name} doesn't exist in folder #{@name}." unless @items.has_key?(obj_name)
70
+ ret = @cache["#{@name}.#{obj_name}"]
71
+ return if ret.nil?
72
+ ret.data
73
+ end
74
+
75
+ end
76
+
77
+ class Data
78
+
79
+ attr_reader :name, :data, :timestamp
80
+
81
+ def initialize name, object
82
+ @name = name
83
+ raise BlackBoardError, "Object does not have timestamp" unless object.respond_to?(:timestamp)
84
+ @data = object
85
+ @timestamp = Time.now
86
+ end
87
+
88
+ end
89
+
90
+ class BlackBoard
91
+
92
+ require 'rubygems'
93
+ require 'memcache'
94
+
95
+ @cache = nil
96
+
97
+ attr_reader :folders
98
+
99
+ def initialize opts = {}, &block
100
+ @folders = {}
101
+ @ttl = opts[:ttl] || 60
102
+ raise ArgumentError, "Pulso::BlackBoard.new should not receive ttl bigger than #seconds in 30 days" if @ttl > 2592000
103
+ @servers = opts[:servers]
104
+ @servers ||= "127.0.0.1:11411"
105
+ @cache = MemCache.new(@servers, :namespace => 'blackboard')
106
+ instance_eval(&block) unless block.nil?
107
+ end
108
+
109
+ def active?
110
+ @cache.active?
111
+ end
112
+
113
+ def has_folders?
114
+ !@folders.empty?
115
+ end
116
+
117
+ def empty?
118
+ @cache.stats.inject(0) {|sum, server| sum + server.last["curr_items"]} == 0
119
+ end
120
+
121
+ def folder name, keys, args = {}, &block
122
+ raise BlackBoardError, "Folder #{name} already exists" if @folders.has_key?(name)
123
+ ttl = args[:ttl]
124
+ ttl ||= @ttl
125
+ instance_eval %Q{def #{name}; @folders[:#{name}]._update; @folders[:#{name}]; end}
126
+ @folders[name] = Pulso::Folder.new name, keys, :cache => @cache, :ttl => ttl, &block
127
+ end
128
+
129
+ def clean
130
+ @cache.flush_all
131
+ end
132
+
133
+ def method_missing folder
134
+ raise BlackBoardError, "Folder #{folder} not found"
135
+ end
136
+
137
+ end
138
+
139
+ class BlackBoardError < RuntimeError
140
+
141
+ end
142
+
143
+ end
@@ -0,0 +1,374 @@
1
+ require 'spec'
2
+ require 'lib/blackboard'
3
+
4
+ class TestObject
5
+
6
+ def initialize
7
+ @timestamp = Time.now
8
+ end
9
+
10
+ attr_accessor :color
11
+ attr_reader :timestamp
12
+ end
13
+
14
+ describe Pulso::Folder do
15
+
16
+ before :each do
17
+ @cache = MemCache.new("127.0.0.1:11411", :namespace => 'blackboard')
18
+ end
19
+
20
+ it "should be created with a name, servers and ttl" do
21
+ f = nil
22
+ lambda { f = Pulso::Folder.new }.should raise_error ArgumentError
23
+ lambda { f = Pulso::Folder.new :folder1, [], :cache => @cache }.should raise_error ArgumentError
24
+ lambda { f = Pulso::Folder.new :folder1, [], :ttl => 20 }.should raise_error ArgumentError
25
+ lambda { f = Pulso::Folder.new :folder1, [], :cache => @cache, :ttl => 20 }.should_not raise_error ArgumentError
26
+ f.name.should == :folder1
27
+ end
28
+
29
+ it "should complain if ttl is bigger than seconds in 30 days" do
30
+ lambda { Pulso::Folder.new :folder1, [], :cache => @cache, :ttl => 30*24*3600+1 }.should raise_error ArgumentError
31
+ lambda { Pulso::Folder.new :folder1, [], :cache => @cache, :ttl => 30*24*3600 }.should_not raise_error ArgumentError
32
+ end
33
+
34
+ it "should not complain when creating subfolders" do
35
+ lambda {
36
+ Pulso::Folder.new :folder1, [:name1, :name2], :cache => @cache, :ttl => 30*24*3600 do
37
+ folder :folder2, [:name4, :name5], :ttl => 30*24*3600
38
+ end
39
+ }.should_not raise_error ArgumentError
40
+ end
41
+
42
+ it "should return a kind of Hash" do
43
+ f = Pulso::Folder.new :folder1, [:name1], :cache => @cache, :ttl => 20
44
+ f.should be_a_kind_of Hash
45
+ f.should == { :name1 => nil }
46
+ end
47
+
48
+ it "should respond to folder name method" do
49
+ `memcached -d -p 11411 -P /tmp/memcached-test.pid`
50
+ k = Pulso::Folder.new :folder1, [:name1, :name2], :cache => @cache, :ttl => 30*24*3600 do
51
+ folder :folder2, [:name1]
52
+ end
53
+ lambda { k.folder2 }.should_not raise_error
54
+ k.folder2.should == { :name1 => nil }
55
+ `killall memcached`
56
+ end
57
+
58
+ end
59
+
60
+ describe Pulso::Data do
61
+
62
+ it "should be initialized with a name and an object that responds to :timestamp" do
63
+ lambda { Pulso::Data.new }.should raise_error
64
+ lambda { Pulso::Data.new :name1, Object.new }.should raise_error Pulso::BlackBoardError
65
+ obj = TestObject.new
66
+ data = nil
67
+ lambda { data = Pulso::Data.new :name1, obj }.should_not raise_error Pulso::BlackBoardError
68
+ data.name.should == :name1
69
+ data.data.should == obj
70
+ end
71
+
72
+ it "should have a timestamp" do
73
+ Pulso::Data.new(:name1, TestObject.new).timestamp.should be_close Time.now,1
74
+ end
75
+
76
+ end
77
+
78
+ describe Pulso::BlackBoard do
79
+
80
+ before :all do
81
+ `memcached -d -p 11411 -P /tmp/memcached-test.pid`
82
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
83
+ folder :folder1, [:name1, :name2]
84
+ end
85
+ end
86
+
87
+ describe "(default)" do
88
+
89
+ it "should be active?" do
90
+ @blackboard.should be_active
91
+ end
92
+
93
+ it "should have folders" do
94
+ @blackboard.should have_folders
95
+ end
96
+
97
+ it "should complain if ttl is bigger than seconds in 30 days" do
98
+ lambda { Pulso::BlackBoard.new :ttl => 30*24*3600+1 }.should raise_error ArgumentError
99
+ lambda { Pulso::BlackBoard.new :ttl => 30*24*3600 }.should_not raise_error ArgumentError
100
+ end
101
+
102
+ end
103
+
104
+ describe "(empty)" do
105
+
106
+ it { @blackboard.should be_empty }
107
+
108
+ it "should have folders after adding one" do
109
+ bb = Pulso::BlackBoard.new do
110
+ folder :folder1, [:name1, :name2]
111
+ end
112
+ bb.should have_folders
113
+ bb.folders.keys.should include(:folder1)
114
+ end
115
+
116
+ # TODO improve by regexp matching
117
+ it "should complain when retrieving from inexistant folder" do
118
+ lambda { @blackboard.folder2.name1 }.should raise_error Pulso::BlackBoardError
119
+ end
120
+
121
+ it "should return nil when retrieving known data key from folder" do
122
+ @blackboard.folder1.name2.should be_nil
123
+ end
124
+
125
+ it "should complain when retrieving unknown data key from folder" do
126
+ lambda { @blackboard.folder1.name5 }.should raise_error Pulso::BlackBoardError
127
+ end
128
+
129
+ end
130
+
131
+ describe "(non-empty)" do
132
+
133
+ before :all do
134
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
135
+ folder :folder1, [:name1, :name2, :name3]
136
+ folder :folder2, [:name4, :name5, :name6]
137
+ end
138
+ @blackboard.folders.keys.should include(:folder1)
139
+ end
140
+
141
+ before :each do
142
+ @obj = TestObject.new
143
+ @obj.color = :green
144
+ @blackboard.folder1.name2 = @obj
145
+ @obj = TestObject.new
146
+ @obj.color = :black
147
+ @blackboard.folder1.name3 = @obj
148
+ @obj = TestObject.new
149
+ @obj.color = :blue
150
+ @blackboard.folder1.name1 = @obj
151
+ end
152
+
153
+ it "should not be empty" do
154
+ @blackboard.should have_folders
155
+ obj = TestObject.new
156
+ obj.color = :green
157
+ @blackboard.folder1.name2 = obj
158
+ @blackboard.should_not be_empty
159
+ end
160
+
161
+ it "should be able to retrieve object from a folder" do
162
+ obj = @blackboard.folder1.name1
163
+ obj.color.should == :blue
164
+ end
165
+
166
+ it "should be empty after cleaning" do
167
+ @blackboard.clean
168
+ @blackboard.should be_empty
169
+ end
170
+
171
+ it "should not return nil when retrieving object whose time-to-live was not exceeded" do
172
+ `sleep 1`
173
+ @blackboard.folder1.name1.should_not be_nil
174
+ end
175
+
176
+ it "should return nil when retrieving object whose time-to-live was exceeded" do
177
+ @blackboard.folder1.name1.should_not be_nil
178
+ `sleep 2`
179
+ @blackboard.folder1.name1.should be_nil
180
+ @blackboard.folder1.name1 = @obj # already expired
181
+ @blackboard.folder1.name1.should be_nil
182
+ end
183
+
184
+ it "should be possible to retrieve all data from a folder" do
185
+ ret = @blackboard.folder1
186
+ ret.name1.color.should == :blue
187
+ ret.name2.color.should == :green
188
+ ret.name3.color.should == :black
189
+ end
190
+
191
+ it "should timestamp the BlackBoard::Data object with current time when adding" do
192
+ obj = TestObject.new
193
+ obj.color = :blue
194
+ @blackboard.folder1.name1 = obj
195
+ @blackboard.folder1.name1.timestamp.should be_close Time.now, 0.2
196
+ end
197
+
198
+ it "should keep a Data object if new one is older" do
199
+ obj1 = TestObject.new
200
+ obj1.color = :blue
201
+ `sleep 1`
202
+ obj2 = TestObject.new
203
+ obj2.color = :green
204
+ @blackboard.folder2.name5 = obj2
205
+ @blackboard.folder2.name5 = obj1
206
+ obj = @blackboard.folder2.name5
207
+ obj.color.should == :green
208
+ end
209
+
210
+ it "should replace a Data object if new one is newer" do
211
+ obj1 = TestObject.new
212
+ obj1.color = :blue
213
+ `sleep 1`
214
+ obj2 = TestObject.new
215
+ obj2.color = :green
216
+
217
+ @blackboard.folder1.name2 = obj1
218
+ obj = @blackboard.folder1.name2
219
+ obj.color.should == :blue
220
+
221
+ @blackboard.folder1.name2 = obj2
222
+ obj = @blackboard.folder1.name2
223
+ obj.color.should == :green
224
+ end
225
+
226
+ after :each do
227
+ @blackboard.clean
228
+ end
229
+ end
230
+
231
+ describe "(with subfolders)" do
232
+
233
+ it "should allow subfolders" do
234
+
235
+ lambda {
236
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
237
+ folder :folder1, [:name1, :name2, :name3] do
238
+ folder :folder2, [:name4, :name5]
239
+ end
240
+ end
241
+ }.should_not raise_error
242
+
243
+ @blackboard.folder1.should == { :name1 => nil, :name2 => nil, :name3 => nil, :folder2 => { :name4 => nil, :name5 => nil } }
244
+
245
+ end
246
+
247
+ it "should be possible to write to a subfolder" do
248
+
249
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
250
+ folder :folder1, [:name1, :name2, :name3] do
251
+ folder :folder2, [:name4, :name5]
252
+ end
253
+ end
254
+
255
+ obj = TestObject.new
256
+ obj.color = :green
257
+
258
+ lambda { @blackboard.folder1.folder2.name5 = obj }.should_not raise_error
259
+
260
+ ret = @blackboard.folder1.folder2.name5
261
+ ret.color.should == :green
262
+
263
+ ret = @blackboard.folder1.folder2
264
+ ret[:name4].should be_nil
265
+ ret[:name5].color.should == :green
266
+
267
+ lambda { @blackboard.folder1.folder2.name5 = obj }.should_not raise_error
268
+
269
+ end
270
+
271
+ it "should allow different ttl for subfolders" do
272
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
273
+ folder :folder1, [:name1], :ttl => 1
274
+ folder :folder2, [:name2], :ttl => 2
275
+ end
276
+ obj = TestObject.new
277
+ obj.color = :green
278
+ @blackboard.folder1.name1 = obj
279
+ @blackboard.folder2.name2 = obj
280
+ @blackboard.folder1.name1.should_not be_nil
281
+ @blackboard.folder2.name2.should_not be_nil
282
+ `sleep 1`
283
+ @blackboard.folder1.name1.should be_nil
284
+ @blackboard.folder2.name2.should_not be_nil
285
+ `sleep 1`
286
+ @blackboard.folder1.name1.should be_nil
287
+ @blackboard.folder2.name2.should be_nil
288
+ end
289
+
290
+ it "should allow different ttl between folder and subfolder" do
291
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
292
+ folder :folder1, [:name1], :ttl => 1 do
293
+ folder :folder2, [:name2], :ttl => 2
294
+ end
295
+ end
296
+ obj = TestObject.new
297
+ obj.color = :green
298
+ @blackboard.folder1.name1 = obj
299
+ @blackboard.folder1.folder2.name2 = obj
300
+
301
+ @blackboard.folder1.name1.should_not be_nil
302
+ @blackboard.folder1.folder2.name2.should_not be_nil
303
+ `sleep 1`
304
+ @blackboard.folder1.name1.should be_nil
305
+ @blackboard.folder1.folder2.name2.should_not be_nil
306
+ `sleep 1`
307
+ @blackboard.folder1.name1.should be_nil
308
+ @blackboard.folder1.folder2.name2.should be_nil
309
+ end
310
+
311
+ it "should propagate tll to subfolders " do
312
+ @blackboard = Pulso::BlackBoard.new :ttl => 2 do
313
+ folder :folder1, [:name1], :ttl => 1 do
314
+ folder :folder2, [:name2]
315
+ end
316
+ end
317
+ obj = TestObject.new
318
+ obj.color = :green
319
+ @blackboard.folder1.name1 = obj
320
+ @blackboard.folder1.folder2.name2 = obj
321
+
322
+ @blackboard.folder1.name1.should_not be_nil
323
+ @blackboard.folder1.folder2.name2.should_not be_nil
324
+ `sleep 1`
325
+ @blackboard.folder1.name1.should be_nil
326
+ @blackboard.folder1.folder2.name2.should be_nil
327
+ `sleep 1`
328
+ @blackboard.folder1.name1.should be_nil
329
+ @blackboard.folder1.folder2.name2.should be_nil
330
+ end
331
+
332
+ it "should support writing to two elements with same name on different folders" do
333
+ @blackboard = Pulso::BlackBoard.new :ttl => 10 do
334
+ folder :folder1, [:name1]
335
+ folder :folder2, [:name1]
336
+ end
337
+ obj = TestObject.new
338
+ obj.color = :green
339
+ @blackboard.folder1.name1 = obj
340
+ obj = TestObject.new
341
+ obj.color = :blue
342
+ @blackboard.folder2.name1 = obj
343
+
344
+ @blackboard.folder1.name1.color.should == :green
345
+ @blackboard.folder2.name1.color.should == :blue
346
+ end
347
+
348
+ it "should not complain when creating sub sub folders" do
349
+ lambda { @blackboard = Pulso::BlackBoard.new :ttl => 10 do
350
+ folder :folder1, [:name1] do
351
+ folder :folder1, [:name1] do
352
+ folder :folder1, [:name1] do
353
+ folder :folder1, [:name1] do
354
+ folder :folder1, [:name1] do
355
+ folder :folder1, [:name1]
356
+ end
357
+ end
358
+ end
359
+ end
360
+ end
361
+ end }.should_not raise_error
362
+ obj = TestObject.new
363
+ obj.color = :green
364
+ @blackboard.folder1.folder1.folder1.folder1.folder1.folder1.name1 = obj
365
+ @blackboard.folder1.folder1.folder1.folder1.folder1.folder1.name1.color.should == :green
366
+ end
367
+
368
+ end
369
+
370
+ after :all do
371
+ `killall memcached`
372
+ end
373
+
374
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ require "test/unit"
4
+ class BlackboardTest < Test::Unit::TestCase
5
+ def test_nothing
6
+ true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/blackboard'
3
+
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsvd-blackboard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ platform: ruby
6
+ authors:
7
+ - "Jo\xC3\xA3o Duarte"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-11 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: memcache-client
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.4.0
23
+ version:
24
+ description: ""
25
+ email: jsvduarte@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - test
34
+ - test/test_helper.rb
35
+ - test/blackboard_test.rb
36
+ - lib
37
+ - lib/blackboard.rb
38
+ - README
39
+ - spec
40
+ - spec/blackboard_spec.rb
41
+ - ChangeLog
42
+ - Rakefile
43
+ - blackboard.gemspec
44
+ has_rdoc: false
45
+ homepage:
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 1.8.5
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.2.0
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: ""
70
+ test_files: []
71
+