bud 0.9.1 → 0.9.2
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/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.
|