bud 0.9.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +11 -0
- data/docs/cheat.md +1 -1
- data/lib/bud/aggs.rb +28 -0
- data/lib/bud/collections.rb +2 -4
- data/lib/bud/executor/elements.rb +13 -6
- data/lib/bud/executor/group.rb +5 -10
- data/lib/bud/executor/join.rb +112 -79
- data/lib/bud/graphs.rb +7 -5
- data/lib/bud/rebl.rb +1 -1
- data/lib/bud/rewrite.rb +25 -1
- data/lib/bud/viz.rb +2 -1
- data/lib/bud/viz_util.rb +20 -13
- metadata +87 -27
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 0.9.2 / ???
|
2
|
+
|
3
|
+
* Add new aggregate functions: bool_and() and bool_or()
|
4
|
+
* Fix bugs in notin() stratification and implementation (#271)
|
5
|
+
* Fix a bug in processing multi-way joins defined inside modules
|
6
|
+
* Fix two bugs in reduce() operator
|
7
|
+
* Incorrect default value was sometimes returned
|
8
|
+
* Didn't handle reduce() outputs that aren't tuples with two fields
|
9
|
+
* Improve reduce() operator error reporting
|
10
|
+
* Improve MRI 1.9 compatibility
|
11
|
+
|
1
12
|
== 0.9.1 / 2012-04-10
|
2
13
|
|
3
14
|
* Reject attempts to insert a tuple into a collection with more fields than are
|
data/docs/cheat.md
CHANGED
@@ -237,7 +237,7 @@ Finally, we output every tuple of `bc` that does *not* appear in `t`.
|
|
237
237
|
## SQL-style grouping/aggregation (and then some) ##
|
238
238
|
|
239
239
|
* `bc.group([:col1, :col2], min(:col3))`. *akin to min(col3) GROUP BY col1,col2*
|
240
|
-
* exemplary aggs: `min`, `max`, `choose`
|
240
|
+
* exemplary aggs: `min`, `max`, `bool_and`, `bool_or`, `choose`
|
241
241
|
* summary aggs: `sum`, `avg`, `count`
|
242
242
|
* structural aggs: `accum`
|
243
243
|
* `bc.argmax([:attr1], :attr2)` *returns the bc items per attr1 that have highest attr2*
|
data/lib/bud/aggs.rb
CHANGED
@@ -70,6 +70,34 @@ module Bud
|
|
70
70
|
[Max.new, x]
|
71
71
|
end
|
72
72
|
|
73
|
+
class BooleanAnd < ArgExemplary #:nodoc: all
|
74
|
+
def trans(the_state, val)
|
75
|
+
if val == false
|
76
|
+
return val, :replace
|
77
|
+
else
|
78
|
+
return the_state, :ignore
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def bool_and(x)
|
84
|
+
[BooleanAnd.new, x]
|
85
|
+
end
|
86
|
+
|
87
|
+
class BooleanOr < ArgExemplary #:nodoc: all
|
88
|
+
def trans(the_state, val)
|
89
|
+
if val == true
|
90
|
+
return val, :replace
|
91
|
+
else
|
92
|
+
return the_state, :ignore
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def bool_or(x)
|
98
|
+
[BooleanOr.new, x]
|
99
|
+
end
|
100
|
+
|
73
101
|
class Choose < ArgExemplary #:nodoc: all
|
74
102
|
def trans(the_state, val)
|
75
103
|
if the_state.nil?
|
data/lib/bud/collections.rb
CHANGED
@@ -680,16 +680,14 @@ module Bud
|
|
680
680
|
public
|
681
681
|
def *(collection)
|
682
682
|
elem1 = to_push_elem
|
683
|
-
|
684
|
-
return j
|
683
|
+
return elem1.join(collection)
|
685
684
|
end
|
686
685
|
|
687
686
|
def group(key_cols, *aggpairs, &blk)
|
688
687
|
elem = to_push_elem
|
689
688
|
key_cols = key_cols.map{|k| canonicalize_col(k)} unless key_cols.nil?
|
690
689
|
aggpairs = aggpairs.map{|ap| [ap[0], canonicalize_col(ap[1])].compact} unless aggpairs.nil?
|
691
|
-
|
692
|
-
return g
|
690
|
+
return elem.group(key_cols, *aggpairs, &blk)
|
693
691
|
end
|
694
692
|
|
695
693
|
def notin(collection, *preds, &blk)
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'bud/collections'
|
3
3
|
|
4
|
-
ELEMENT_BUFSIZE = 1
|
5
|
-
|
6
4
|
module Bud
|
7
5
|
# Usage example:
|
8
6
|
# p = PushElement.new(:r) do |inp|
|
@@ -520,8 +518,9 @@ module Bud
|
|
520
518
|
class PushReduce < PushStatefulElement
|
521
519
|
def initialize(elem_name, bud_instance, collection_name,
|
522
520
|
schema_in, initial, &blk)
|
523
|
-
@
|
521
|
+
@initial = initial
|
524
522
|
@blk = blk
|
523
|
+
reset_memo
|
525
524
|
super(elem_name, bud_instance, collection_name, schema)
|
526
525
|
end
|
527
526
|
|
@@ -530,13 +529,21 @@ module Bud
|
|
530
529
|
end
|
531
530
|
|
532
531
|
def invalidate_cache
|
533
|
-
|
532
|
+
puts "#{self.class}/#{self.tabname} invalidated" if $BUD_DEBUG
|
533
|
+
reset_memo
|
534
|
+
end
|
535
|
+
|
536
|
+
def reset_memo
|
537
|
+
@memo = Marshal.load(Marshal.dump(@initial))
|
534
538
|
end
|
535
539
|
|
536
540
|
public
|
537
541
|
def flush
|
538
|
-
@memo.
|
539
|
-
|
542
|
+
unless @memo.kind_of? Enumerable
|
543
|
+
raise Bud::TypeError, "output of reduce must be Enumerable: #{@memo.inspect}"
|
544
|
+
end
|
545
|
+
@memo.each do |t|
|
546
|
+
push_out(t, false)
|
540
547
|
end
|
541
548
|
end
|
542
549
|
end
|
data/lib/bud/executor/group.rb
CHANGED
@@ -21,7 +21,6 @@ module Bud
|
|
21
21
|
agg = (@groups[key].nil? or @groups[key][agg_ix].nil?) ? ap[0].send(:init, agg_input) : ap[0].send(:trans, @groups[key][agg_ix], agg_input)[0]
|
22
22
|
@groups[key] ||= Array.new(@aggpairs.length)
|
23
23
|
@groups[key][agg_ix] = agg
|
24
|
-
push_out(nil)
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
@@ -40,7 +39,6 @@ module Bud
|
|
40
39
|
(1..grp.length-1).each {|i| outval << grp[i]}
|
41
40
|
push_out(outval)
|
42
41
|
end
|
43
|
-
#@groups = {}
|
44
42
|
end
|
45
43
|
end
|
46
44
|
|
@@ -82,23 +80,20 @@ module Bud
|
|
82
80
|
@winners[key].delete t unless @winners[key].empty?
|
83
81
|
end
|
84
82
|
else
|
85
|
-
raise "strange result from argagg finalizer"
|
83
|
+
raise Bud::Error, "strange result from argagg finalizer"
|
86
84
|
end
|
87
85
|
end
|
88
86
|
@groups[key] ||= Array.new(@aggpairs.length)
|
89
87
|
@groups[key][agg_ix] = agg
|
90
|
-
#push_out(nil)
|
91
88
|
end
|
92
89
|
end
|
93
90
|
|
94
91
|
def flush
|
95
|
-
@groups.
|
96
|
-
@winners[g].each
|
92
|
+
@groups.each_key do |g|
|
93
|
+
@winners[g].each do |t|
|
97
94
|
push_out(t, false)
|
98
|
-
|
99
|
-
|
100
|
-
#@groups = {}
|
101
|
-
#@winners = {}
|
95
|
+
end
|
96
|
+
end
|
102
97
|
end
|
103
98
|
end
|
104
99
|
end
|
data/lib/bud/executor/join.rb
CHANGED
@@ -14,7 +14,6 @@ module Bud
|
|
14
14
|
@origpreds = preds
|
15
15
|
@localpreds = nil
|
16
16
|
@selfjoins = []
|
17
|
-
@input_bufs = [[],[]]
|
18
17
|
@missing_keys = Set.new
|
19
18
|
|
20
19
|
# if any elements on rellist are PushSHJoins, suck up their contents
|
@@ -265,20 +264,6 @@ module Bud
|
|
265
264
|
return retval
|
266
265
|
end
|
267
266
|
|
268
|
-
# given a * expression over 2 collections, form all combos of items that
|
269
|
-
# satisfy +preds+, and for any item from the 1st collection that has no
|
270
|
-
# matches in the 2nd, nil-pad it and include it in the output.
|
271
|
-
public
|
272
|
-
def join(elem2, &blk)
|
273
|
-
elem2 = elem2.to_push_elem unless elem2.class <= PushElement
|
274
|
-
# This constructs a left-deep tree!
|
275
|
-
join = Bud::PushSHJoin.new([self,elem2], @bud_instance, [])
|
276
|
-
@bud_instance.push_joins[@bud_instance.this_stratum] << join
|
277
|
-
elem2.wire_to(join)
|
278
|
-
self.wire_to(join)
|
279
|
-
return join
|
280
|
-
end
|
281
|
-
|
282
267
|
undef do_insert
|
283
268
|
|
284
269
|
public
|
@@ -296,11 +281,7 @@ module Bud
|
|
296
281
|
end
|
297
282
|
raise Bud::Error, "item #{item.inspect} inserted into join from unknown source #{source.elem_name}" if offsets == $EMPTY
|
298
283
|
offsets.each do |offset|
|
299
|
-
|
300
|
-
buf << item
|
301
|
-
if buf.length >= ELEMENT_BUFSIZE
|
302
|
-
flush_buf(buf, offset)
|
303
|
-
end
|
284
|
+
insert_item(item, offset)
|
304
285
|
end
|
305
286
|
end
|
306
287
|
|
@@ -395,25 +376,6 @@ module Bud
|
|
395
376
|
end
|
396
377
|
end
|
397
378
|
|
398
|
-
def flush_buf(buf, offset)
|
399
|
-
buf.each do |item|
|
400
|
-
insert_item(item, offset)
|
401
|
-
end
|
402
|
-
@input_bufs[offset] = []
|
403
|
-
end
|
404
|
-
|
405
|
-
public
|
406
|
-
def flush
|
407
|
-
@input_bufs.each_with_index do |buf, offset|
|
408
|
-
flush_buf(buf, offset) if buf.length > 0
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
|
-
public
|
413
|
-
def stratum_end
|
414
|
-
flush
|
415
|
-
end
|
416
|
-
|
417
379
|
####
|
418
380
|
# and now, the Bloom-facing methods
|
419
381
|
# given a * expression over n collections, form all combinations of items
|
@@ -573,23 +535,66 @@ module Bud
|
|
573
535
|
end
|
574
536
|
end
|
575
537
|
|
576
|
-
|
538
|
+
|
539
|
+
# Consider "u <= s.notin(t, s.a => t.b)". notin is a non-monotonic operator, where u depends positively on s,
|
540
|
+
# but negatively on t. Stratification ensures that t is fully computed in a lower stratum, which means that we
|
541
|
+
# can expect multiple iterators on s's side only. If t's scanner were to push its elemends down first, every
|
542
|
+
# insert of s merely needs to be cross checked with the cached elements of 't', and pushed down to the next
|
543
|
+
# element if s notin t. However, if s's scanner were to fire first, we have to wait until the first flush, at which
|
544
|
+
# point we are sure to have seen all the t-side tuples in this tick.
|
545
|
+
class PushNotIn < PushStatefulElement
|
577
546
|
def initialize(rellist, bud_instance, preds=nil, &blk) # :nodoc: all
|
578
|
-
|
579
|
-
|
547
|
+
@lhs, @rhs = rellist
|
548
|
+
@lhs_keycols = nil
|
549
|
+
@rhs_keycols = nil
|
550
|
+
name_in = "#{@lhs.tabname}_notin_#{@rhs.tabname}"
|
551
|
+
super(name_in, bud_instance)
|
552
|
+
setup_preds(preds) unless preds.empty?
|
553
|
+
@rhs_rcvd = false
|
554
|
+
@hash_tables = [{},{}]
|
555
|
+
@rhs_rcvd = false
|
556
|
+
if @lhs_keycols.nil? and blk.nil?
|
557
|
+
# pointwise comparison. Could use zip, but it creates an array for each field pair
|
558
|
+
blk = lambda {|lhs, rhs|
|
559
|
+
lhs.to_a == rhs.to_a
|
560
|
+
}
|
580
561
|
end
|
581
|
-
super(rellist, bud_instance, preds)
|
582
562
|
set_block(&blk)
|
583
|
-
@cols = rellist[0].cols
|
584
|
-
@exclude = Set.new
|
585
563
|
end
|
586
564
|
|
587
|
-
def
|
588
|
-
#
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
565
|
+
def setup_preds(preds)
|
566
|
+
# This is simpler than PushSHJoin's setup_preds, because notin is a binary operator where both lhs and rhs are
|
567
|
+
# collections.
|
568
|
+
# preds an array of hash_pairs. For now assume that the attributes are in the same order as the tables.
|
569
|
+
@lhs_keycols, @rhs_keycols = preds.reduce([[], []]) do |memo, item|
|
570
|
+
# each item is a hash
|
571
|
+
l = item.keys[0]
|
572
|
+
r = item.values[0]
|
573
|
+
memo[0] << find_col(l, @lhs)
|
574
|
+
memo[1] << find_col(r, @rhs)
|
575
|
+
memo
|
576
|
+
end
|
577
|
+
end
|
578
|
+
def find_col(colspec, rel)
|
579
|
+
if colspec.is_a? Symbol
|
580
|
+
col_desc = rel.send(colspec)
|
581
|
+
raise "Unknown column #{rel} in #{@rel.tabname}" if col_desc.nil?
|
582
|
+
elsif colspec.is_a? Array
|
583
|
+
col_desc = colspec
|
584
|
+
else
|
585
|
+
raise "Symbol or column spec expected. Got #{colspec}"
|
586
|
+
end
|
587
|
+
col_desc[1] # col_desc is of the form [tabname, colnum, colname]
|
588
|
+
end
|
589
|
+
|
590
|
+
def get_key(item, offset)
|
591
|
+
keycols = offset == 0 ? @lhs_keycols : @rhs_keycols
|
592
|
+
keycols.nil? ? $EMPTY : keycols.map{|col| item[col]}
|
593
|
+
end
|
594
|
+
|
595
|
+
public
|
596
|
+
def invalidate_at_tick
|
597
|
+
true
|
593
598
|
end
|
594
599
|
|
595
600
|
public
|
@@ -597,40 +602,68 @@ module Bud
|
|
597
602
|
true
|
598
603
|
end
|
599
604
|
|
600
|
-
def
|
601
|
-
|
602
|
-
|
603
|
-
#puts "#{item}
|
604
|
-
@
|
605
|
+
def insert(item, source)
|
606
|
+
offset = source == @lhs ? 0 : 1
|
607
|
+
key = get_key(item, offset)
|
608
|
+
#puts "#{key}, #{item}, #{offset}"
|
609
|
+
(@hash_tables[offset][key] ||= Set.new).add item
|
610
|
+
if @rhs_rcvd and offset == 0
|
611
|
+
push_lhs(key, item)
|
612
|
+
end
|
605
613
|
end
|
606
614
|
|
607
|
-
|
608
|
-
|
609
|
-
|
615
|
+
def flush
|
616
|
+
# When flush is called the first time, both lhs and rhs scanners have been invoked, and because of stratification
|
617
|
+
# we know that the rhs is not growing any more, until the next tick.
|
618
|
+
unless @rhs_rcvd
|
619
|
+
@rhs_rcvd = true
|
620
|
+
@hash_tables[0].map{|key,values|
|
621
|
+
values.each{|item|
|
622
|
+
push_lhs(key, item)
|
623
|
+
}
|
624
|
+
}
|
625
|
+
end
|
610
626
|
end
|
611
627
|
|
612
|
-
def
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
628
|
+
def push_lhs(key, lhs_item)
|
629
|
+
rhs_values = @hash_tables[1][key]
|
630
|
+
process_match(lhs_item, rhs_values)
|
631
|
+
end
|
632
|
+
|
633
|
+
def process_match(lhs_item, rhs_values)
|
634
|
+
exclude = true
|
635
|
+
if rhs_values.nil?
|
636
|
+
# no corresponding rhs. Include in output
|
637
|
+
exclude = false
|
638
|
+
elsif not @blk.nil?
|
639
|
+
# for any lhs * rhs pair, if block returns true, do not push lhs. lhs is pushed
|
640
|
+
# only if there is no match (anti-join)
|
641
|
+
exclude = rhs_values.any?{|rhs_item| @blk.call(lhs_item, rhs_item)}
|
642
|
+
end
|
643
|
+
unless exclude
|
644
|
+
push_out(lhs_item)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
public
|
649
|
+
def push_out(item)
|
650
|
+
@outputs.each do |ou|
|
651
|
+
if ou.class <= Bud::PushElement
|
652
|
+
ou.insert(item, self)
|
653
|
+
elsif ou.class <= Bud::BudCollection
|
654
|
+
ou.do_insert(item, ou.new_delta)
|
655
|
+
else
|
656
|
+
raise Bud::Error, "expected either a PushElement or a BudCollection"
|
632
657
|
end
|
633
658
|
end
|
659
|
+
# for all the following, o is a BudCollection
|
660
|
+
@deletes.each{|o| o.pending_delete([item])}
|
661
|
+
@delete_keys.each{|o| o.pending_delete_keys([item])}
|
662
|
+
@pendings.each{|o| o.pending_merge([item])}
|
634
663
|
end
|
635
664
|
end
|
665
|
+
def stratum_end
|
666
|
+
@hash_tables = [{},{}]
|
667
|
+
@rhs_rcvd = false
|
668
|
+
end
|
636
669
|
end
|
data/lib/bud/graphs.rb
CHANGED
@@ -74,8 +74,10 @@ class GraphGen #:nodoc: all
|
|
74
74
|
# bottom if the predicate is not in a NEG/+ cycle. otherwise,
|
75
75
|
# its name is "CYC" + concat(sort(predicate names))
|
76
76
|
depends.each do |d|
|
77
|
-
|
78
|
-
body = d.
|
77
|
+
# b/c bud_obj was pruned before serialization...
|
78
|
+
(bud_obj, rule_id, lhs, op, body, nm) = d.to_a
|
79
|
+
head = lhs
|
80
|
+
body = body
|
79
81
|
|
80
82
|
if @builtin_tables.has_key?(head.to_sym) or @builtin_tables.has_key?(body.to_sym)
|
81
83
|
next
|
@@ -83,9 +85,9 @@ class GraphGen #:nodoc: all
|
|
83
85
|
|
84
86
|
head = name_of(head)
|
85
87
|
body = name_of(body)
|
86
|
-
addonce(head, (head !=
|
87
|
-
addonce(body, (body !=
|
88
|
-
addedge(body, head,
|
88
|
+
addonce(head, (head != lhs), true)
|
89
|
+
addonce(body, (body != body))
|
90
|
+
addedge(body, head, op, nm, (head != lhs), rule_id)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
data/lib/bud/rebl.rb
CHANGED
@@ -175,7 +175,7 @@ class ReblShell
|
|
175
175
|
def self.do_exit
|
176
176
|
begin
|
177
177
|
lines = Readline::HISTORY.to_a.reverse.uniq.reverse
|
178
|
-
lines = lines[-@@maxhistsize, @@maxhistsize] if lines.
|
178
|
+
lines = lines[-@@maxhistsize, @@maxhistsize] if lines.size > @@maxhistsize
|
179
179
|
File::open(@@histfile, File::WRONLY|File::CREAT|File::TRUNC) do |io|
|
180
180
|
io.puts lines.join("\n")
|
181
181
|
end
|
data/lib/bud/rewrite.rb
CHANGED
@@ -53,16 +53,40 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
53
53
|
ty
|
54
54
|
end
|
55
55
|
|
56
|
+
def call_to_id(exp)
|
57
|
+
# convert a series of nested calls, a sexp of the form
|
58
|
+
# s(:call,
|
59
|
+
# s(:call, s(:call, nil, :a, s(:arglist)), :b, s(:arglist)),
|
60
|
+
# :bar ,
|
61
|
+
# s(:arglist)))
|
62
|
+
# to the string "a.b.bar"
|
63
|
+
raise "Malformed exp: #{exp}" unless (exp[0] == :call)
|
64
|
+
_, recv, op, args = exp
|
65
|
+
return recv.nil? ? op.to_s : call_to_id(recv) + "." + op.to_s
|
66
|
+
end
|
67
|
+
|
56
68
|
def process_call(exp)
|
57
69
|
recv, op, args = exp
|
58
70
|
if OP_LIST.include?(op) and @context[1] == :block and @context.length == 4
|
59
71
|
# NB: context.length is 4 when see a method call at the top-level of a
|
60
72
|
# :defn block -- this is where we expect Bloom statements to appear
|
61
73
|
do_rule(exp)
|
74
|
+
elsif op == :notin
|
75
|
+
# special case. In the rule "z <= x.notin(y)", z depends positively on x, but negatively on y
|
76
|
+
# See further explanation in the "else" section for why this is a special case.
|
77
|
+
notintab = call_to_id(args[1]) # args expected to be of the form (:arglist (:call nil :y ...))
|
78
|
+
@tables[notintab.to_s] = true # "true" denotes non-monotonic dependency.
|
79
|
+
super
|
62
80
|
else
|
81
|
+
# Parse a call of the form a.b.c.foo.
|
82
|
+
# In the most general case, a.b is a nested module, a.b.c is a collection in that module, and
|
83
|
+
# a.b.c.foo is either a method or a field. If it is a method, and non-monotonic at that, we
|
84
|
+
# register a dependency between lhs and the table a.b.c.
|
85
|
+
# Note that notin is treated differently because in a.b.c.notin(d.e.f), we register a non-monotonic
|
86
|
+
# dependency of lhs on "d.e.f", not with "a.b.c"
|
63
87
|
ty, qn, _ = exp_id_type(recv, op, args) # qn = qualified name
|
64
88
|
if ty == :collection
|
65
|
-
@tables[qn] = @nm if @collect
|
89
|
+
(@tables[qn] = @nm if @collect) unless @tables[qn]
|
66
90
|
#elsif ty == :import .. do nothing
|
67
91
|
elsif ty == :not_coll_id
|
68
92
|
# check if receiver is a collection, and further if the current exp
|
data/lib/bud/viz.rb
CHANGED
@@ -4,6 +4,7 @@ require 'gchart'
|
|
4
4
|
require 'bud/state'
|
5
5
|
|
6
6
|
class VizOnline #:nodoc: all
|
7
|
+
attr_reader :logtab
|
7
8
|
def initialize(bud_instance)
|
8
9
|
@bud_instance = bud_instance
|
9
10
|
@meta_tables = {'t_rules' => 1, 't_depends' => 1, 't_table_info' => 1, 't_cycle' => 1, 't_stratum' => 1, 't_depends_tc' => 1, 't_table_schema' => 1, 't_provides' => 1}
|
@@ -62,7 +63,7 @@ class VizOnline #:nodoc: all
|
|
62
63
|
# bud instances cannot/must not be serialized.
|
63
64
|
if row[0].class <= Bud
|
64
65
|
row = row.to_a if row.class != Array
|
65
|
-
row = row[1..-1] if row[0].class <= Bud
|
66
|
+
row = [row[0].class.to_s] + row[1..-1] if row[0].class <= Bud
|
66
67
|
end
|
67
68
|
newrow = [tab, @bud_instance.budtime, row]
|
68
69
|
begin
|
data/lib/bud/viz_util.rb
CHANGED
@@ -31,7 +31,7 @@ class VizHelper
|
|
31
31
|
|
32
32
|
def summarize(dir, schema)
|
33
33
|
table_io = {}
|
34
|
-
cardinalities.sort{|a, b| a[0] <=> b[0]}.each do |card|
|
34
|
+
cardinalities.to_a.sort{|a, b| a[0] <=> b[0]}.each do |card|
|
35
35
|
table_io["#{card.table}_#{card.bud_time}"] = start_table(dir, card.table, card.bud_time, schema[card.table])
|
36
36
|
end
|
37
37
|
|
@@ -44,7 +44,7 @@ class VizHelper
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# fix: nested loops
|
47
|
-
times.sort.each do |time|
|
47
|
+
times.to_a.sort.each do |time|
|
48
48
|
card_info = {}
|
49
49
|
cardinalities.each do |card|
|
50
50
|
if card.bud_time == time.bud_time
|
@@ -178,14 +178,16 @@ module VizUtil #:nodoc: all
|
|
178
178
|
rules = {}
|
179
179
|
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
|
180
180
|
shredded_rules.each do |s|
|
181
|
-
|
181
|
+
# b/c accessors don't make it through serialization anymore
|
182
|
+
bud_obj, rule_id, lhs, op, src, orig_src, nm_funcs_called = s.to_a
|
183
|
+
fout = File.new("#{output_base}/#{rule_id}.html", "w+")
|
182
184
|
fout.puts header
|
183
|
-
fout.puts "<h1>Rule #{
|
185
|
+
fout.puts "<h1>Rule #{rule_id}</h1><br>"
|
184
186
|
|
185
|
-
c = convertor.convert(
|
187
|
+
c = convertor.convert(orig_src)
|
186
188
|
c.sub!(/^<pre>/, "<pre class=\"code\" style='font-size:20px'>\n")
|
187
189
|
fout.puts c
|
188
|
-
rules[
|
190
|
+
rules[rule_id] = [lhs, orig_src]
|
189
191
|
fout.close
|
190
192
|
end
|
191
193
|
|
@@ -299,14 +301,13 @@ END_JS
|
|
299
301
|
key = MessagePack.unpack(k)
|
300
302
|
tab = key.shift
|
301
303
|
time = key.shift
|
302
|
-
# paa
|
304
|
+
# paa: after switch to 1.9, v appears to always be empty
|
303
305
|
tup = key[0]
|
304
306
|
MessagePack.unpack(v).each {|val| tup << val}
|
305
307
|
if meta_tabs[tab]
|
306
308
|
raise "non-zero budtime.(tab=#{tab}, time=#{time}) sure this is metadata?" if time != 0 #and strict
|
307
309
|
meta[meta_tabs[tab]] ||= []
|
308
310
|
meta[meta_tabs[tab]] << tup
|
309
|
-
#ret << tup
|
310
311
|
else
|
311
312
|
data << [time, tab, tup]
|
312
313
|
end
|
@@ -322,11 +323,15 @@ END_JS
|
|
322
323
|
unless meta[:schminf][tab]
|
323
324
|
meta[:schminf][tab] = []
|
324
325
|
end
|
325
|
-
meta[:schminf][tab][ts[2]] = ts[1]
|
326
|
+
meta[:schminf][tab][ts[2]] = ts[1] if ts[2]
|
326
327
|
end
|
327
328
|
return meta, data
|
328
329
|
end
|
329
330
|
|
331
|
+
def mapstr(list)
|
332
|
+
list.map{|s| "<th> #{s} </th>"}.join(" ")
|
333
|
+
end
|
334
|
+
|
330
335
|
def start_table(dir, tab, time, schema)
|
331
336
|
str = "#{dir}/#{tab}_#{time}.html"
|
332
337
|
fout = File.new(str, "w")
|
@@ -334,12 +339,14 @@ END_JS
|
|
334
339
|
fout.puts "<table border=1>"
|
335
340
|
# issue with _snd schemas
|
336
341
|
if !schema.nil? and schema[0] == "c_bud_time"
|
337
|
-
fout.puts "<tr>"
|
342
|
+
fout.puts "<tr>"
|
338
343
|
if schema[1].length == 2 and schema[1][0].class == Array and schema[1][1].class == Array
|
339
|
-
fout.puts schema[1][0]
|
340
|
-
fout.puts schema[1][1]
|
344
|
+
fout.puts mapstr(schema[1][0])
|
345
|
+
fout.puts mapstr(schema[1][1])
|
346
|
+
elsif schema[1].class == String
|
347
|
+
fout.puts mapstr(schema[1..-1])
|
341
348
|
else
|
342
|
-
fout.puts schema[1]
|
349
|
+
fout.puts mapstr(schema[1])
|
343
350
|
end
|
344
351
|
fout.puts "<tr>"
|
345
352
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bud
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,11 +13,11 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2012-
|
16
|
+
date: 2012-05-20 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: eventmachine
|
20
|
-
requirement:
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
21
|
none: false
|
22
22
|
requirements:
|
23
23
|
- - ! '>='
|
@@ -25,10 +25,15 @@ dependencies:
|
|
25
25
|
version: '0'
|
26
26
|
type: :runtime
|
27
27
|
prerelease: false
|
28
|
-
version_requirements:
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
29
34
|
- !ruby/object:Gem::Dependency
|
30
35
|
name: fastercsv
|
31
|
-
requirement:
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
32
37
|
none: false
|
33
38
|
requirements:
|
34
39
|
- - ! '>='
|
@@ -36,10 +41,15 @@ dependencies:
|
|
36
41
|
version: '0'
|
37
42
|
type: :runtime
|
38
43
|
prerelease: false
|
39
|
-
version_requirements:
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
40
50
|
- !ruby/object:Gem::Dependency
|
41
51
|
name: gchart
|
42
|
-
requirement:
|
52
|
+
requirement: !ruby/object:Gem::Requirement
|
43
53
|
none: false
|
44
54
|
requirements:
|
45
55
|
- - ! '>='
|
@@ -47,10 +57,15 @@ dependencies:
|
|
47
57
|
version: '0'
|
48
58
|
type: :runtime
|
49
59
|
prerelease: false
|
50
|
-
version_requirements:
|
60
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
51
66
|
- !ruby/object:Gem::Dependency
|
52
67
|
name: getopt
|
53
|
-
requirement:
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
54
69
|
none: false
|
55
70
|
requirements:
|
56
71
|
- - ! '>='
|
@@ -58,10 +73,15 @@ dependencies:
|
|
58
73
|
version: '0'
|
59
74
|
type: :runtime
|
60
75
|
prerelease: false
|
61
|
-
version_requirements:
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
62
82
|
- !ruby/object:Gem::Dependency
|
63
83
|
name: msgpack
|
64
|
-
requirement:
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
65
85
|
none: false
|
66
86
|
requirements:
|
67
87
|
- - ! '>='
|
@@ -69,10 +89,15 @@ dependencies:
|
|
69
89
|
version: '0'
|
70
90
|
type: :runtime
|
71
91
|
prerelease: false
|
72
|
-
version_requirements:
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
73
98
|
- !ruby/object:Gem::Dependency
|
74
99
|
name: ruby-graphviz
|
75
|
-
requirement:
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
76
101
|
none: false
|
77
102
|
requirements:
|
78
103
|
- - ! '>='
|
@@ -80,10 +105,15 @@ dependencies:
|
|
80
105
|
version: '0'
|
81
106
|
type: :runtime
|
82
107
|
prerelease: false
|
83
|
-
version_requirements:
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
84
114
|
- !ruby/object:Gem::Dependency
|
85
115
|
name: ruby2ruby
|
86
|
-
requirement:
|
116
|
+
requirement: !ruby/object:Gem::Requirement
|
87
117
|
none: false
|
88
118
|
requirements:
|
89
119
|
- - <
|
@@ -91,10 +121,15 @@ dependencies:
|
|
91
121
|
version: 1.3.1
|
92
122
|
type: :runtime
|
93
123
|
prerelease: false
|
94
|
-
version_requirements:
|
124
|
+
version_requirements: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - <
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: 1.3.1
|
95
130
|
- !ruby/object:Gem::Dependency
|
96
131
|
name: ruby_parser
|
97
|
-
requirement:
|
132
|
+
requirement: !ruby/object:Gem::Requirement
|
98
133
|
none: false
|
99
134
|
requirements:
|
100
135
|
- - ! '>='
|
@@ -102,10 +137,15 @@ dependencies:
|
|
102
137
|
version: '0'
|
103
138
|
type: :runtime
|
104
139
|
prerelease: false
|
105
|
-
version_requirements:
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
106
146
|
- !ruby/object:Gem::Dependency
|
107
147
|
name: superators19
|
108
|
-
requirement:
|
148
|
+
requirement: !ruby/object:Gem::Requirement
|
109
149
|
none: false
|
110
150
|
requirements:
|
111
151
|
- - ! '>='
|
@@ -113,10 +153,15 @@ dependencies:
|
|
113
153
|
version: '0'
|
114
154
|
type: :runtime
|
115
155
|
prerelease: false
|
116
|
-
version_requirements:
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ! '>='
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
117
162
|
- !ruby/object:Gem::Dependency
|
118
163
|
name: syntax
|
119
|
-
requirement:
|
164
|
+
requirement: !ruby/object:Gem::Requirement
|
120
165
|
none: false
|
121
166
|
requirements:
|
122
167
|
- - ! '>='
|
@@ -124,10 +169,15 @@ dependencies:
|
|
124
169
|
version: '0'
|
125
170
|
type: :runtime
|
126
171
|
prerelease: false
|
127
|
-
version_requirements:
|
172
|
+
version_requirements: !ruby/object:Gem::Requirement
|
173
|
+
none: false
|
174
|
+
requirements:
|
175
|
+
- - ! '>='
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
128
178
|
- !ruby/object:Gem::Dependency
|
129
179
|
name: uuid
|
130
|
-
requirement:
|
180
|
+
requirement: !ruby/object:Gem::Requirement
|
131
181
|
none: false
|
132
182
|
requirements:
|
133
183
|
- - ! '>='
|
@@ -135,10 +185,15 @@ dependencies:
|
|
135
185
|
version: '0'
|
136
186
|
type: :runtime
|
137
187
|
prerelease: false
|
138
|
-
version_requirements:
|
188
|
+
version_requirements: !ruby/object:Gem::Requirement
|
189
|
+
none: false
|
190
|
+
requirements:
|
191
|
+
- - ! '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
139
194
|
- !ruby/object:Gem::Dependency
|
140
195
|
name: minitest
|
141
|
-
requirement:
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
142
197
|
none: false
|
143
198
|
requirements:
|
144
199
|
- - ! '>='
|
@@ -146,7 +201,12 @@ dependencies:
|
|
146
201
|
version: '0'
|
147
202
|
type: :development
|
148
203
|
prerelease: false
|
149
|
-
version_requirements:
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
none: false
|
206
|
+
requirements:
|
207
|
+
- - ! '>='
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0'
|
150
210
|
description: A prototype of the Bloom distributed programming language as a Ruby DSL.
|
151
211
|
email:
|
152
212
|
- bloomdevs@gmail.com
|
@@ -228,7 +288,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
228
288
|
version: '0'
|
229
289
|
requirements: []
|
230
290
|
rubyforge_project: bloom-lang
|
231
|
-
rubygems_version: 1.8.
|
291
|
+
rubygems_version: 1.8.24
|
232
292
|
signing_key:
|
233
293
|
specification_version: 3
|
234
294
|
summary: A prototype Bloom DSL for distributed programming.
|