drip 0.0.2 → 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 029a7c4fb43e4852aca41b6f1a2ba481062cec47
4
+ data.tar.gz: d1c6ca3d3291e2cf73171e345125bfb11e06b8dc
5
+ SHA512:
6
+ metadata.gz: 4c0c2bf53465abe23f7b56b51172d0a107477882f037ecb2dddc75bd18d1f94e34797983fd51bf3b99495175b464fb6699f924f15955b7a5645d83e3780071ef
7
+ data.tar.gz: 9e057c27351793c8f95efc022c64baa52faca161cfec6048dca62c37f14ad574ffcd722497a6afad4b89e05f4b19fb92980357048506c613a4c7e4213d559aba
@@ -5,135 +5,16 @@ require 'enumerator'
5
5
 
6
6
  class Drip
7
7
  include DRbUndumped
8
- def inspect; to_s; end
9
-
10
- class ImmutableDrip
11
- class Generator
12
- def initialize
13
- @pool = []
14
- @tag = []
15
- @shared = Hash.new {|h, k| h[k] = k; k}
16
- end
17
-
18
- def add(key, value, *tag)
19
- @pool << [key, value]
20
- idx = @pool.size - 1
21
- tag.uniq.each do |t|
22
- @tag << [[@shared[t], key], idx]
23
- end
24
- end
25
-
26
- def generate
27
- tag = @tag.sort
28
- tag.inject(nil) do |last, kv|
29
- k = kv[0]
30
- k[0] = last if k[0] == last
31
- k[0]
32
- end
33
- ImmutableDrip.new(@pool.sort, tag)
34
- end
35
- end
36
-
37
- INF = 1.0/0
38
-
39
- def initialize(pool=[], tag=[])
40
- @pool = pool
41
- @tag = tag
42
- end
43
-
44
- def fetch(key)
45
- idx = lower_boundary(@pool, key)
46
- k, v = @pool[idx]
47
- k == key ? v.to_a : nil
48
- end
49
-
50
- def read(key, n=1)
51
- idx = lower_boundary(@pool, key + 1)
52
- return [] unless idx
53
- @pool[idx, n].collect {|kv|
54
- [kv[0], *kv[1].to_a]
55
- }
56
- end
57
-
58
- def read_tag(key, tag, n=1)
59
- idx = lower_boundary(@tag, [tag, key + 1])
60
- return [] unless idx
61
- @tag[idx, n].find_all {|kv| kv[0][0] == tag}.collect {|kv|
62
- [kv[0][1], *@pool[kv[1]][1].to_a]
63
- }
64
- end
65
-
66
- def head_tag(n, tag)
67
- lower = lower_boundary(@tag, [tag, 0])
68
- upper = upper_boundary(@tag, [tag, INF])
69
- lower = [lower, upper - n].max
70
- @tag[lower ... upper].collect {|kv|
71
- [kv[0][1], *@pool[kv[1]][1].to_a]
72
- }
73
- end
74
-
75
- def head(n=1, tag=nil)
76
- return head_tag(n, tag) if tag
77
- n = @pool.size < n ? @pool.size : n
78
- @pool[-n, n].collect {|kv|
79
- [kv[0], *kv[1].to_a]
80
- }
81
- end
82
-
83
- def older_tag(key, tag)
84
- idx = upper_boundary(@tag, [tag, key-1])
85
- k, v = @tag[idx - 1]
86
- k && k[0] == tag ? [k[1], *@pool[v][1].to_a] : nil
87
- end
88
-
89
- def older(key, tag=nil)
90
- key = @pool[-1][0] + 1 unless key
91
- return older_tag(key, tag) if tag
92
- idx = upper_boundary(@pool, key - 1)
93
- k, v = @pool[idx - 1]
94
- k && k < key ? [k, *v.to_a] : nil
95
- end
96
-
97
- def newer(key, tag=nil)
98
- return read(key, 1)[0] unless tag
99
- read_tag(key, tag, 1)[0]
100
- end
101
-
102
- def lower_boundary(ary, key)
103
- lower = -1
104
- upper = ary.size
105
- while lower + 1 != upper
106
- mid = (lower + upper).div(2)
107
- if (ary[mid][0] <=> key) < 0
108
- lower = mid
109
- else
110
- upper = mid
111
- end
112
- end
113
- return upper
114
- end
115
-
116
- def upper_boundary(ary, key)
117
- lower = -1
118
- upper = ary.size
119
- while lower + 1 != upper
120
- mid = (lower + upper).div(2)
121
- if (ary[mid][0] <=> key) <= 0
122
- lower = mid
123
- else
124
- upper = mid
125
- end
126
- end
127
- return lower + 1
128
- end
129
- end
8
+ INF = 1.0/0.0
130
9
 
10
+ def inspect; to_s; end
131
11
  def initialize(dir, option={})
132
- @pool = RBTree.new
12
+ @past = prepare_store(dir, option)
13
+ @fence = (@past.head[0][0] rescue 0) || 0
14
+ @pool = Drip::SortedArray.new([])
133
15
  @tag = RBTree.new
134
16
  @event = Rinda::TupleSpace.new(5)
135
- @event.write([:last, 0])
136
- prepare_store(dir, option)
17
+ @event.write([:last, @fence])
137
18
  end
138
19
 
139
20
  def write(obj, *tags)
@@ -143,19 +24,30 @@ class Drip
143
24
  def write_after(at, *value)
144
25
  make_key(at) do |key|
145
26
  value = do_write(key, value)
146
- @pool[key] = @store.write(key, value)
27
+ @pool.push([key, @store.write(key, value)])
147
28
  end
148
29
  end
149
30
 
150
31
  def write_at(at, *value)
151
32
  make_key_at(at) do |key|
152
33
  value = do_write(key, value)
153
- @pool[key] = @store.write(key, value)
34
+ @pool.push([key, @store.write(key, value)])
35
+ end
36
+ end
37
+
38
+ def write_if_latest(cond, *value)
39
+ make_key(Time.now) do |key|
40
+ cond.each {|it|
41
+ return nil unless latest?(it[1], it[0])
42
+ }
43
+ value = do_write(key, value)
44
+ @pool.push([key, @store.write(key, value)])
154
45
  end
155
46
  end
156
47
 
157
48
  def fetch(key)
158
- @pool[key].to_a
49
+ return @past.fetch(key) if @fence >= key
50
+ @pool.fetch(key)
159
51
  end
160
52
  alias [] fetch
161
53
 
@@ -171,6 +63,52 @@ class Drip
171
63
  end
172
64
 
173
65
  def read(key, n=1, at_least=1, timeout=nil)
66
+ return curr_read(key, n, at_least, timeout) if key > @fence
67
+ ary = @past.read(key, n)
68
+ return ary if ary.size >= n
69
+ ary + curr_read(key, n - ary.size, at_least - ary.size, timeout)
70
+ end
71
+
72
+ def read_tag(key, tag, n=1, at_least=1, timeout=nil)
73
+ return curr_read_tag(key, tag, n, at_least, timeout) if key > @fence
74
+ ary = @past.read_tag(key, tag, n)
75
+ return ary if ary.size >= n
76
+ ary + curr_read_tag(key, tag, n - ary.size, at_least - ary.size, timeout)
77
+ end
78
+
79
+ def head(n=1, tag=nil)
80
+ unless tag
81
+ ary = @pool.head(n)
82
+ return @past.head(n - ary.size) + ary
83
+ end
84
+ ary = curr_head(n, tag)
85
+ return ary if ary.size == n
86
+ @past.head(n - ary.size, tag) + ary
87
+ end
88
+
89
+ def latest?(key, tag=nil)
90
+ now = time_to_key(Time.now)
91
+ if tag
92
+ it ,= @tag.upper_bound([tag, now])
93
+ if it && it[0] == tag
94
+ return true if it[1] == key
95
+ return false if it[1] > key
96
+ end
97
+ else
98
+ return true if @pool.latest?(key)
99
+ end
100
+ @past.latest?(key, tag)
101
+ end
102
+
103
+ def older(key, tag=nil)
104
+ curr_older(key, tag) || @past.older(key, tag)
105
+ end
106
+
107
+ def newer(key, tag=nil)
108
+ @past.newer(key, tag) || curr_newer(key, tag)
109
+ end
110
+
111
+ def curr_read(key, n=1, at_least=1, timeout=nil)
174
112
  renewer = make_renewer(timeout)
175
113
  key = time_to_key(Time.now) unless key
176
114
  ary = []
@@ -180,14 +118,14 @@ class Drip
180
118
  rescue Rinda::RequestExpiredError
181
119
  return ary
182
120
  end
183
- key, value = @pool.lower_bound(key + 1)
121
+ key, value, *tags = @pool.read(key)[0]
184
122
  return ary unless key
185
- ary << [key] + value.to_a
123
+ ary << [key] + [value, *tags]
186
124
  end
187
125
  ary
188
126
  end
189
127
 
190
- def read_tag(key, tag, n=1, at_least=1, timeout=nil)
128
+ def curr_read_tag(key, tag, n=1, at_least=1, timeout=nil)
191
129
  renewer = make_renewer(timeout)
192
130
  key = time_to_key(Time.now) unless key
193
131
  ary = []
@@ -205,10 +143,10 @@ class Drip
205
143
  ary
206
144
  end
207
145
 
208
- def head(n=1, tag=nil)
146
+ def curr_head(n=1, tag=nil)
209
147
  ary = []
210
148
  key = nil
211
- while it = older(key, tag)
149
+ while it = curr_older(key, tag)
212
150
  break if n <= 0
213
151
  ary.unshift(it)
214
152
  key = it[0]
@@ -217,27 +155,29 @@ class Drip
217
155
  ary
218
156
  end
219
157
 
220
- def older(key, tag=nil)
158
+ def curr_older(key, tag=nil)
221
159
  key = time_to_key(Time.now) unless key
222
- unless tag
223
- k, v = @pool.upper_bound(key - 1)
224
- return k ? [k] + v.to_a : nil
225
- end
160
+
161
+ return @pool.older(key) unless tag
226
162
 
227
163
  it ,= @tag.upper_bound([tag, key - 1])
228
164
  return nil unless it && it[0] == tag
229
165
  [it[1]] + fetch(it[1])
230
166
  end
231
167
 
232
- def newer(key, tag=nil)
168
+ def curr_newer(key, tag=nil)
233
169
  return read(key, 1, 0)[0] unless tag
234
170
  read_tag(key, tag, 1, 0)[0]
235
171
  end
236
172
 
237
- def time_to_key(time)
173
+ def self.time_to_key(time)
238
174
  time.tv_sec * 1000000 + time.tv_usec
239
175
  end
240
176
 
177
+ def time_to_key(time)
178
+ self.class.time_to_key(time)
179
+ end
180
+
241
181
  def key_to_time(key)
242
182
  Time.at(*key.divmod(1000000))
243
183
  end
@@ -314,7 +254,7 @@ class Drip
314
254
  def prepare_store(dir, option={})
315
255
  if dir.nil?
316
256
  @store = SimpleStore.new(nil, option)
317
- return
257
+ return ImmutableDrip.new
318
258
  end
319
259
 
320
260
  Dir.mkdir(dir) rescue nil
@@ -322,26 +262,31 @@ class Drip
322
262
  File.basename(fn).to_i(36)
323
263
  end
324
264
  if dump
325
- @pool, @tag, last = File.open(dump, 'rb') {|fp| Marshal.load(fp)}
326
- @event.take([:last, nil])
327
- @event.write([:last, last])
265
+ pool, tag, _ = File.open(dump, 'rb') {|fp| Marshal.load(fp)}
328
266
  File.unlink(dump)
267
+ else
268
+ pool = []
269
+ tag = []
329
270
  end
271
+ gen = ImmutableDrip::Generator.new(pool, tag)
330
272
  loaded = dump ? File.basename(dump).to_i(36) : 0
331
273
  Dir.glob(File.join(dir, '*.log')) do |fn|
332
274
  next if loaded > File.basename(fn).to_i(36)
333
275
  begin
334
- store = SimpleStore.reader(fn)
335
- restore(store)
276
+ SimpleStore.reader(fn).each do |k, v, attic|
277
+ obj, *tags = v
278
+ attic.forget
279
+ gen.add(k, attic, *tags)
280
+ end
336
281
  rescue
337
282
  end
338
283
  end
339
- name = time_to_key(Time.now).to_s(36)
340
- _, last = @event.read([:last, nil])
284
+ name = Drip.time_to_key(Time.now).to_s(36)
341
285
  File.open(File.join(dir, name + '.dump'), 'wb') {|fp|
342
- Marshal.dump([@pool, @tag, last], fp)
286
+ Marshal.dump([gen.pool, gen.tag], fp)
343
287
  }
344
288
  @store = SimpleStore.new(File.join(dir, name + '.log'))
289
+ return gen.generate
345
290
  end
346
291
 
347
292
  def shared_text(str)
@@ -361,7 +306,8 @@ class Drip
361
306
  tag = shared_text(k)
362
307
  @tag[[tag, key]] = key
363
308
  end
364
- @pool[key] = [obj] + tags
309
+ # @pool[key] = [obj] + tags
310
+ [obj] + tags
365
311
  end
366
312
 
367
313
  def restore(store)
@@ -400,7 +346,6 @@ class Drip
400
346
  @event.write([:last, last])
401
347
  end
402
348
 
403
- INF = 1.0/0.0
404
349
  def wait(key, renewer)
405
350
  @event.read([:last, key+1 .. INF], renewer)[1]
406
351
  end
@@ -425,6 +370,223 @@ class Drip
425
370
  end
426
371
  end
427
372
 
373
+ class Drip
374
+ module ArrayBsearch
375
+ module_function
376
+ def lower_boundary(ary, key)
377
+ lower = -1
378
+ upper = ary.size
379
+ while lower + 1 != upper
380
+ mid = (lower + upper).div(2)
381
+ if (ary[mid][0] <=> key) < 0
382
+ lower = mid
383
+ else
384
+ upper = mid
385
+ end
386
+ end
387
+ return upper
388
+ end
389
+
390
+ def upper_boundary(ary, key)
391
+ lower = -1
392
+ upper = ary.size
393
+ while lower + 1 != upper
394
+ mid = (lower + upper).div(2)
395
+ if (ary[mid][0] <=> key) <= 0
396
+ lower = mid
397
+ else
398
+ upper = mid
399
+ end
400
+ end
401
+ return lower + 1
402
+ end
403
+ end
404
+ end
405
+
406
+ class Drip
407
+ class FakeRBTree
408
+ include Drip::ArrayBsearch
409
+
410
+ def initialize
411
+ @tree = Hash.new {|h, k| h[k] = Array.new}
412
+ end
413
+
414
+ def upper_bound(pair)
415
+ tag, now = pair
416
+ return nil unless @tree.include?(tag)
417
+ ary = @tree[tag]
418
+ idx = upper_boundary(ary, now)
419
+ [tag, ary[tag][idx]]
420
+ end
421
+
422
+ def lower_bound(pair)
423
+ end
424
+ end
425
+ end
426
+
427
+
428
+
429
+ class Drip
430
+ class SortedArray
431
+ include Drip::ArrayBsearch
432
+
433
+ def initialize(ary)
434
+ @ary = ary
435
+ @last_key = ary.empty? ? 0 : ary[-1][0]
436
+ end
437
+
438
+ def push(obj)
439
+ raise 'InvalidTimeError' if obj[0] <= @last_key
440
+ @last_key = obj[0]
441
+ @ary << obj
442
+ end
443
+
444
+ def fetch(key)
445
+ idx = lower_boundary(@ary, key)
446
+ k, v = @ary[idx]
447
+ k == key ? v.to_a : nil
448
+ end
449
+
450
+ def read(key, n=1)
451
+ idx = lower_boundary(@ary, key + 1)
452
+ return [] unless idx
453
+ @ary[idx, n].collect {|kv|
454
+ [kv[0], *kv[1].to_a]
455
+ }
456
+ end
457
+
458
+ def empty?
459
+ @ary.empty?
460
+ end
461
+
462
+ def latest?(key)
463
+ @last_key == key
464
+ end
465
+
466
+ def head(n)
467
+ n = @ary.size < n ? @ary.size : n
468
+ @ary[-n, n].collect {|kv|
469
+ [kv[0], *kv[1].to_a]
470
+ }
471
+ end
472
+
473
+ def older(key)
474
+ return nil if @ary.empty?
475
+ key = @ary[-1][0] + 1 unless key
476
+ idx = upper_boundary(@ary, key - 1)
477
+ k, v = @ary[idx - 1]
478
+ k && k < key ? [k, *v.to_a] : nil
479
+ end
480
+
481
+ def last
482
+ @ary[-1]
483
+ end
484
+
485
+ def last_key
486
+ @ary.empty? ? 0 : last[0]
487
+ end
488
+ end
489
+ end
490
+
491
+ class Drip
492
+ class ImmutableDrip
493
+ include Drip::ArrayBsearch
494
+
495
+ def initialize(pool=[], tag=[])
496
+ @pool = Drip::SortedArray.new(pool)
497
+ @tag = tag
498
+ end
499
+
500
+ def fetch(key)
501
+ @pool.fetch(key)
502
+ end
503
+
504
+ def read(key, n=1)
505
+ @pool.read(key, n)
506
+ end
507
+
508
+ def read_tag(key, tag, n=1)
509
+ idx = lower_boundary(@tag, [tag, key + 1])
510
+ return [] unless idx
511
+ @tag[idx, n].find_all {|kv| kv[0][0] == tag}.collect {|kv|
512
+ [kv[0][1], *fetch(kv[0][1])]
513
+ }
514
+ end
515
+
516
+ def latest?(key, tag)
517
+ return false if @pool.empty?
518
+ return @pool.latest?(key) unless tag
519
+
520
+ lower = lower_boundary(@tag, [tag, key])
521
+ upper = upper_boundary(@tag, [tag, INF])
522
+ return lower == upper - 1
523
+ end
524
+
525
+ def head_tag(n, tag)
526
+ lower = lower_boundary(@tag, [tag, 0])
527
+ upper = upper_boundary(@tag, [tag, INF])
528
+ lower = [lower, upper - n].max
529
+ @tag[lower ... upper].collect {|kv|
530
+ [kv[0][1], *fetch(kv[0][1])]
531
+ }
532
+ end
533
+
534
+ def head(n=1, tag=nil)
535
+ tag ? head_tag(n, tag) : @pool.head(n)
536
+ end
537
+
538
+ def older_tag(key, tag)
539
+ idx = upper_boundary(@tag, [tag, key-1])
540
+ k, v = @tag[idx - 1]
541
+ k && k[0] == tag ? [k[1], *fetch(k[1])] : nil
542
+ end
543
+
544
+ def older(key, tag=nil)
545
+ return nil if @pool.empty?
546
+ key = @pool.last_key + 1 unless key
547
+ return older_tag(key, tag) if tag
548
+ @pool.older(key)
549
+ end
550
+
551
+ def newer(key, tag=nil)
552
+ return read(key, 1)[0] unless tag
553
+ read_tag(key, tag, 1)[0]
554
+ end
555
+ end
556
+ end
557
+
558
+ class Drip
559
+ class ImmutableDrip
560
+ class Generator
561
+ def initialize(pool=[], tag=[])
562
+ @pool = pool
563
+ @tag = tag
564
+ @shared = Hash.new {|h, k| h[k] = k; k}
565
+ @tag.each {|pair| @shared[pair[0]]}
566
+ end
567
+ attr_reader :pool, :tag
568
+
569
+ def add(key, value, *tag)
570
+ @pool << [key, value]
571
+ idx = @pool.size - 1
572
+ tag.uniq.each do |t|
573
+ @tag << [[@shared[t], key]]
574
+ end
575
+ end
576
+
577
+ def generate
578
+ tag = @tag.sort
579
+ tag.inject(nil) do |last, kv|
580
+ k = kv[0]
581
+ k[0] = last if k[0] == last
582
+ k[0]
583
+ end
584
+ ImmutableDrip.new(@pool.sort, tag)
585
+ end
586
+ end
587
+ end
588
+ end
589
+
428
590
  if __FILE__ == $0
429
591
  require 'my_drip'
430
592
  MyDrip.invoke
@@ -1,3 +1,3 @@
1
- module Drip
2
- VERSION = "0.0.2"
1
+ class Drip
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  require 'simple-oauth'
2
3
  require 'drb'
3
4
  require 'pp'
@@ -36,6 +37,40 @@ class DripFiber
36
37
  end
37
38
  end
38
39
 
40
+ class DripThread
41
+ def initialize(app)
42
+ @app = app
43
+ @queue = Queue.new
44
+ Thread.new do
45
+ story
46
+ end
47
+ end
48
+
49
+ def story
50
+ event = @queue.pop
51
+ pending = []
52
+ while event['id_str'].nil?
53
+ pending << event
54
+ event = @queue.pop
55
+ end
56
+
57
+ @app.fill_timeline(event['id_str'])
58
+
59
+ while event = pending.shift
60
+ @app.write(event)
61
+ end
62
+
63
+ while true
64
+ event = @queue.pop
65
+ @app.write(event)
66
+ end
67
+ end
68
+
69
+ def push(event)
70
+ @queue.push(event)
71
+ end
72
+ end
73
+
39
74
  class JSONStream
40
75
  def initialize(drip)
41
76
  @buf = ''
@@ -49,8 +84,10 @@ class JSONStream
49
84
  @buf.sub!(line,"")
50
85
  line.strip!
51
86
  event = JSON.parse(line)
52
- rescue
53
- break
87
+ rescue JSON::ParserError
88
+ pp $line if $DEBUG
89
+ pp $! if $DEBUG
90
+ next
54
91
  end
55
92
  pp event if $DEBUG
56
93
  @drip.push(event)
@@ -147,15 +184,16 @@ class DripDemo
147
184
  end
148
185
 
149
186
  def home_timeline(since_id, max_id)
150
- url = "http://api.twitter.com/1/statuses/home_timeline.json?count=200&include_entities=true"
187
+ url = "https://api.twitter.com/1.1/statuses/home_timeline.json?count=200&include_entities=true"
151
188
  url += "&since_id=#{since_id}" if since_id
152
189
  url += "&max_id=#{max_id}" if max_id
153
190
  r = oauth.request(:GET, url)
154
- JSON.parse(r.body)
191
+ body = r.body
192
+ JSON.parse(body)
155
193
  end
156
194
 
157
195
  def user_timeline(since_id, max_id)
158
- url = "http://api.twitter.com/1/statuses/user_timeline.json?count=200&include_entities=true&trim_user=t"
196
+ url = "http://api.twitter.com/1.1/statuses/user_timeline.json?count=200&include_entities=true&trim_user=t"
159
197
  url += "&since_id=#{since_id}" if since_id
160
198
  url += "&max_id=#{max_id}" if max_id
161
199
  r = oauth.request(:GET, url)
@@ -225,13 +263,13 @@ class DripDemo
225
263
  def update(str, in_reply_to=nil)
226
264
  hash = { :status => str }
227
265
  hash[:in_reply_to_status_id] = in_reply_to if in_reply_to
228
- r = oauth.post('http://api.twitter.com/1/statuses/update.xml',
266
+ r = oauth.post('http://api.twitter.com/1.1/statuses/update.xml',
229
267
  hash)
230
268
  pp r.body if $DEBUG
231
269
  end
232
270
 
233
271
  def test
234
- r = oauth.post('http://api.twitter.com/1/statuses/update.xml',
272
+ r = oauth.post('http://api.twitter.com/1.1/statuses/update.xml',
235
273
  {:status => 'test'})
236
274
  pp r.body if $DEBUG
237
275
  end
@@ -124,6 +124,36 @@ class TestDrip < Test::Unit::TestCase
124
124
  oid = @drip.write('dup', 'hello', 'hello', 'hello')
125
125
  assert_equal(@drip[oid], ['dup', 'hello'])
126
126
  end
127
+
128
+ def test_latest?
129
+ key = @drip.write(:start)
130
+ 10.times do |n|
131
+ @drip.write(n)
132
+ end
133
+ assert_equal(@drip.latest?(key), false)
134
+ key = @drip.write(:stop)
135
+ assert_equal(@drip.latest?(key), true)
136
+
137
+ key = @drip.write(:tag_start, 'tag')
138
+ @drip.write(:tag, 'ignore tag')
139
+ assert_equal(@drip.latest?(key, 'tag'), true)
140
+ @drip.write(:tag, 'tag')
141
+ assert_equal(@drip.latest?(key, 'tag'), false)
142
+ end
143
+
144
+ def test_write_if_latest
145
+ t1 = @drip.write('t1', 't1')
146
+ t2 = @drip.write('t2', 't2')
147
+ t3 = @drip.write('t3', 't3')
148
+ assert_equal(@drip.latest?(t1, 't1'), true)
149
+ assert(@drip.write_if_latest([['t1', t1],
150
+ ['t2', t2],
151
+ ['t3', t3]], 'hello', 't1'))
152
+ assert_equal(@drip.latest?(t1, 't1'), false)
153
+ assert_equal(@drip.write_if_latest([['t1', t1],
154
+ ['t2', t2],
155
+ ['t3', t3]], 'hello', 't1'), nil)
156
+ end
127
157
  end
128
158
 
129
159
  class TestDripUsingStorage < TestDrip
@@ -139,13 +169,36 @@ class TestDripUsingStorage < TestDrip
139
169
  def teardown
140
170
  remove_drip
141
171
  end
172
+
173
+ def test_twice_latest?
174
+ assert_equal(@drip.latest?(1), false)
175
+ tag1 = @drip.write('tag1', 'tag1')
176
+ assert_equal(@drip.latest?(tag1), true)
177
+ @drip.write('nop', 'tag1')
178
+ @drip.write('nop', 'tag1')
179
+ tag2 = @drip.write('tag2', 'tag1')
180
+ assert_equal(@drip.latest?(1), false)
181
+ drip = Drip.new('test_db')
182
+ assert_equal(drip.latest?(1), false)
183
+ assert_equal(drip.latest?(tag1, 'tag1'), false)
184
+ assert_equal(drip.latest?(tag2, 'tag1'), true)
185
+ assert_equal(drip.latest?(tag2, 'tag0'), false)
186
+ end
142
187
 
143
188
  def test_twice
144
189
  11.times do |n|
145
190
  @drip.write("n=#{n}" => 'x' * n, n => n, "n" => n, :symbol => n)
146
191
  end
147
-
192
+
148
193
  drip = Drip.new('test_db')
194
+ ary = drip.head(3)
195
+ assert_equal(ary.size, 3)
196
+ assert_equal(ary[0][1]['n'], 8)
197
+ assert_equal(ary[1][1]['n'], 9)
198
+ assert_equal(ary[2][1]['n'], 10)
199
+ ary = drip.head(1)
200
+ assert_equal(ary.size, 1)
201
+ assert_equal(ary[0][1]['n'], 10)
149
202
  ary = drip.read(0, 3)
150
203
  assert_equal(ary.size, 3)
151
204
  assert_equal(ary[0][1]['n'], 0)
@@ -175,30 +228,30 @@ end
175
228
 
176
229
  class TestImmutableDrip < Test::Unit::TestCase
177
230
  def test_bsearch
178
- im = Drip::ImmutableDrip.new
231
+ ab = Drip::ArrayBsearch
179
232
 
180
- assert_equal(0, im.lower_boundary([], 'c'))
181
- assert_equal(0, im.upper_boundary([], 'c'))
233
+ assert_equal(0, ab.lower_boundary([], 'c'))
234
+ assert_equal(0, ab.upper_boundary([], 'c'))
182
235
 
183
236
  ary = %w(a b c c c d e f).collect {|x| [x]}
184
237
 
185
- assert_equal(0, im.lower_boundary(ary, ''))
186
- assert_equal(0, im.lower_boundary(ary, 'a'))
187
- assert_equal(1, im.lower_boundary(ary, 'b'))
188
- assert_equal(2, im.lower_boundary(ary, 'c'))
189
- assert_equal(5, im.lower_boundary(ary, 'd'))
190
- assert_equal(6, im.lower_boundary(ary, 'e'))
191
- assert_equal(7, im.lower_boundary(ary, 'f'))
192
- assert_equal(8, im.lower_boundary(ary, 'g'))
238
+ assert_equal(0, ab.lower_boundary(ary, ''))
239
+ assert_equal(0, ab.lower_boundary(ary, 'a'))
240
+ assert_equal(1, ab.lower_boundary(ary, 'b'))
241
+ assert_equal(2, ab.lower_boundary(ary, 'c'))
242
+ assert_equal(5, ab.lower_boundary(ary, 'd'))
243
+ assert_equal(6, ab.lower_boundary(ary, 'e'))
244
+ assert_equal(7, ab.lower_boundary(ary, 'f'))
245
+ assert_equal(8, ab.lower_boundary(ary, 'g'))
193
246
 
194
- assert_equal(0, im.upper_boundary(ary, ''))
195
- assert_equal(1, im.upper_boundary(ary, 'a'))
196
- assert_equal(2, im.upper_boundary(ary, 'b'))
197
- assert_equal(5, im.upper_boundary(ary, 'c'))
198
- assert_equal(6, im.upper_boundary(ary, 'd'))
199
- assert_equal(7, im.upper_boundary(ary, 'e'))
200
- assert_equal(8, im.upper_boundary(ary, 'f'))
201
- assert_equal(8, im.upper_boundary(ary, 'g'))
247
+ assert_equal(0, ab.upper_boundary(ary, ''))
248
+ assert_equal(1, ab.upper_boundary(ary, 'a'))
249
+ assert_equal(2, ab.upper_boundary(ary, 'b'))
250
+ assert_equal(5, ab.upper_boundary(ary, 'c'))
251
+ assert_equal(6, ab.upper_boundary(ary, 'd'))
252
+ assert_equal(7, ab.upper_boundary(ary, 'e'))
253
+ assert_equal(8, ab.upper_boundary(ary, 'f'))
254
+ assert_equal(8, ab.upper_boundary(ary, 'g'))
202
255
  end
203
256
 
204
257
  def add_to_gen(gen, key, value, *tag)
metadata CHANGED
@@ -1,38 +1,36 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: drip
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.0.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
6
5
  platform: ruby
7
- authors:
6
+ authors:
8
7
  - Masatoshi Seki
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
-
13
- date: 2011-11-16 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
11
+ date: 2015-12-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
16
14
  name: rbtree
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
21
17
  - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
24
20
  type: :runtime
25
- version_requirements: *id001
26
- description: ""
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: ''
27
28
  email:
28
29
  executables: []
29
-
30
30
  extensions: []
31
-
32
31
  extra_rdoc_files: []
33
-
34
- files:
35
- - .gitignore
32
+ files:
33
+ - ".gitignore"
36
34
  - Gemfile
37
35
  - README
38
36
  - Rakefile
@@ -58,30 +56,26 @@ files:
58
56
  - test/basic.rb
59
57
  homepage: https://github.com/seki/Drip
60
58
  licenses: []
61
-
59
+ metadata: {}
62
60
  post_install_message:
63
61
  rdoc_options: []
64
-
65
- require_paths:
62
+ require_paths:
66
63
  - lib
67
- required_ruby_version: !ruby/object:Gem::Requirement
68
- none: false
69
- requirements:
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
70
66
  - - ">="
71
- - !ruby/object:Gem::Version
72
- version: "0"
73
- required_rubygems_version: !ruby/object:Gem::Requirement
74
- none: false
75
- requirements:
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
76
71
  - - ">="
77
- - !ruby/object:Gem::Version
78
- version: "0"
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
79
74
  requirements: []
80
-
81
75
  rubyforge_project: drip
82
- rubygems_version: 1.8.10
76
+ rubygems_version: 2.5.1
83
77
  signing_key:
84
- specification_version: 3
78
+ specification_version: 4
85
79
  summary: Simple RD-Stream for Rinda::TupleSpace lovers.
86
- test_files:
80
+ test_files:
87
81
  - test/basic.rb