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 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?
@@ -680,16 +680,14 @@ module Bud
680
680
  public
681
681
  def *(collection)
682
682
  elem1 = to_push_elem
683
- j = elem1.join(collection)
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
- g = elem.group(key_cols, *aggpairs, &blk)
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
- @memo = initial
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
- @memo.clear
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.each do |k,v|
539
- push_out([k,v], false)
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
@@ -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.keys.each {|g|
96
- @winners[g].each{|t|
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
@@ -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
- buf = @input_bufs[offset]
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
- class PushNotIn < PushSHJoin
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
- if preds.nil? or preds.empty?
579
- preds = positionwise_preds(bud_instance, rellist)
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 positionwise_preds(bud_instance, rels)
588
- # pairwise colnames, for the minimum number of columns from either
589
- return [] if rels[0].cols.length != rels[1].cols.length
590
- pairs = rels[0].cols.zip(rels[1].cols)
591
- # make a hash of each pair, and return an array of hashes as expected by setup_pred
592
- [pairs.reduce(Hash.new) {|h, it| h[it[0]]=it[1]; h}]
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 push_out(item) # item is a two element array, a tuple from rels[0] and rels[1]
601
- # called from PushSHJoin::process_matches, but we don't push the item downstream until stratum end
602
- do_exclude = @blk.nil? ? true : @blk.call(item)
603
- #puts "#{item} ===> #{do_exclude}"
604
- @exclude << item[0] if do_exclude
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
- public
608
- def invalidate_cache
609
- @exclude.clear
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 stratum_end
613
- flush
614
- # Scan through all the cached left rel values, and push out those that are
615
- # not in exclude
616
- @hash_tables[0].each_value do |s|
617
- s.each do |item|
618
- next if @exclude.member? item
619
- @outputs.each do |ou|
620
- if ou.class <= Bud::PushElement
621
- ou.insert(item, self)
622
- elsif ou.class <= Bud::BudCollection
623
- ou.do_insert(item, ou.new_delta)
624
- else
625
- raise Bud::Error, "expected either a PushElement or a BudCollection"
626
- end
627
- end
628
- # for all the following, o is a BudCollection
629
- @deletes.each{|o| o.pending_delete([item])}
630
- @delete_keys.each{|o| o.pending_delete_keys([item])}
631
- @pendings.each{|o| o.pending_merge([item])}
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
- head = d.lhs
78
- body = d.body
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 != d.lhs), true)
87
- addonce(body, (body != d.body))
88
- addedge(body, head, d.op, d.nm, (head != d.lhs), d.rule_id)
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.nitems>@@maxhistsize
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
- fout = File.new("#{output_base}/#{s.rule_id}.html", "w+")
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 #{s.rule_id}</h1><br>"
185
+ fout.puts "<h1>Rule #{rule_id}</h1><br>"
184
186
 
185
- c = convertor.convert(s.orig_src)
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[s.rule_id] = [s.lhs, s.orig_src]
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].map{|s| "<th> #{s} </th>"}.join(" ")
340
- fout.puts schema[1][1].map{|s| "<th> #{s} </th>"}.join(" ")
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].map{|s| "<th> #{s} </th>"}.join(" ")
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.1
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-04-10 00:00:00.000000000 Z
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: &70136220748940 !ruby/object:Gem::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: *70136220748940
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: &70136220747220 !ruby/object:Gem::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: *70136220747220
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: &70136220763100 !ruby/object:Gem::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: *70136220763100
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: &70136220762540 !ruby/object:Gem::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: *70136220762540
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: &70136220761500 !ruby/object:Gem::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: *70136220761500
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: &70136220760140 !ruby/object:Gem::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: *70136220760140
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: &70136220759200 !ruby/object:Gem::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: *70136220759200
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: &70136220758700 !ruby/object:Gem::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: *70136220758700
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: &70136220758040 !ruby/object:Gem::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: *70136220758040
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: &70136220757320 !ruby/object:Gem::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: *70136220757320
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: &70136220756700 !ruby/object:Gem::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: *70136220756700
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: &70136220756180 !ruby/object:Gem::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: *70136220756180
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.17
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.