bud 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/budplot +97 -8
- data/bin/budvis +1 -2
- data/docs/cheat.md +1 -1
- data/lib/bud/aggs.rb +2 -1
- data/lib/bud/bud_meta.rb +8 -7
- data/lib/bud/collections.rb +36 -48
- data/lib/bud/graphs.rb +48 -21
- data/lib/bud/joins.rb +1 -1
- data/lib/bud/meta_algebra.rb +168 -0
- data/lib/bud/monkeypatch.rb +32 -5
- data/lib/bud/rewrite.rb +53 -14
- data/lib/bud/server.rb +25 -4
- data/lib/bud/state.rb +13 -14
- data/lib/bud/storage/dbm.rb +19 -8
- data/lib/bud/storage/tokyocabinet.rb +18 -8
- data/lib/bud/viz.rb +7 -5
- data/lib/bud/viz_util.rb +93 -11
- data/lib/bud.rb +30 -16
- metadata +4 -3
data/bin/budplot
CHANGED
@@ -4,7 +4,9 @@ require 'bud'
|
|
4
4
|
require 'bud/bud_meta'
|
5
5
|
require 'bud/depanalysis'
|
6
6
|
require 'bud/graphs'
|
7
|
+
require 'bud/meta_algebra'
|
7
8
|
require 'bud/viz_util'
|
9
|
+
require 'getopt/std'
|
8
10
|
|
9
11
|
include VizUtil
|
10
12
|
|
@@ -42,12 +44,34 @@ def make_instance(mods)
|
|
42
44
|
|
43
45
|
def_lines = ["class FooBar",
|
44
46
|
"include Bud",
|
47
|
+
"include MetaAlgebra",
|
48
|
+
"include MetaReports",
|
45
49
|
mods.map {|m| "include #{m}"},
|
46
50
|
"end"
|
47
51
|
]
|
48
52
|
class_def = def_lines.flatten.join("\n")
|
49
53
|
eval(class_def)
|
50
|
-
FooBar.new
|
54
|
+
f =FooBar.new
|
55
|
+
3.times{ f.tick }
|
56
|
+
f
|
57
|
+
end
|
58
|
+
|
59
|
+
def trace_counts(begins)
|
60
|
+
complexity = {:data => {}, :coord => {}}
|
61
|
+
if !begins[:start].nil?
|
62
|
+
begins[:start].each_pair do |k, v|
|
63
|
+
if @data and @data[k]
|
64
|
+
complexity[:data][k] = @data[k].length
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
begins[:finish].each_pair do |k, v|
|
69
|
+
if @data and @data[k]
|
70
|
+
complexity[:coord][k] = @data[k].length
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
complexity
|
51
75
|
end
|
52
76
|
|
53
77
|
def process(mods)
|
@@ -79,12 +103,44 @@ def process(mods)
|
|
79
103
|
end
|
80
104
|
|
81
105
|
viz_name = "bud_doc/" + mods.join("_") + "_viz"
|
82
|
-
|
83
|
-
graph_from_instance(d, "#{viz_name}
|
84
|
-
graph_from_instance(d, "#{viz_name}
|
106
|
+
graph_from_instance(d, "#{viz_name}_collapsed", "bud_doc", true, nil, @data)
|
107
|
+
graph_from_instance(d, "#{viz_name}_expanded", "bud_doc", false, nil, @data)
|
108
|
+
begins = graph_from_instance(d, "#{viz_name}_expanded_dot", "bud_doc", false, "dot", @data)
|
109
|
+
|
110
|
+
|
111
|
+
complexity = trace_counts(begins)
|
112
|
+
# try to figure out the degree of the async edges
|
113
|
+
deg = find_degrees(d, @data)
|
114
|
+
unless deg.nil?
|
115
|
+
deg.each_pair do |k, v|
|
116
|
+
puts "DEGREE: #{k} = #{v.keys.length}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
write_index(inp, outp, priv, viz_name, complexity)
|
85
121
|
end
|
86
122
|
|
87
|
-
def
|
123
|
+
def find_degrees(inst, data)
|
124
|
+
degree = {}
|
125
|
+
return if data.nil?
|
126
|
+
data.each_pair do |k, v|
|
127
|
+
tab = inst.tables[k.gsub("_snd", "").to_sym]
|
128
|
+
if !tab.nil?
|
129
|
+
if tab.class == Bud::BudChannel
|
130
|
+
v.each_pair do |k2, v2|
|
131
|
+
v2.each do |row|
|
132
|
+
loc = row[tab.locspec_idx]
|
133
|
+
degree[k] ||= {}
|
134
|
+
degree[k][loc] = true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
return degree
|
141
|
+
end
|
142
|
+
|
143
|
+
def write_index(inp, outp, priv, viz_name, cx)
|
88
144
|
f = File.open("bud_doc/index.html", "w")
|
89
145
|
f.puts "<html>"
|
90
146
|
f.puts "<embed src=\"#{ENV['PWD']}/#{viz_name}_collapsed.svg\" width=\"100%\" height=\"60%\" type=\"image/svg+xml\" pluginspage=\"http://www.adobe.com/svg/viewer/install/\" />"
|
@@ -97,14 +153,24 @@ def write_index(inp, outp, priv, viz_name)
|
|
97
153
|
f.puts "<h2>Output Interfaces</h2>"
|
98
154
|
do_table(f, outp)
|
99
155
|
f.puts "</td><td>"
|
100
|
-
f.puts "<h2>
|
101
|
-
|
102
|
-
f
|
156
|
+
f.puts "<h2>Trace Analysis Results</h2>"
|
157
|
+
f.puts "<h3>Data Complexity</h3>"
|
158
|
+
do_cx(f, cx[:data])
|
159
|
+
f.puts "<h3>Coordination Complexity</h3>"
|
160
|
+
do_cx(f, cx[:coord])
|
103
161
|
f.puts "</tr></table>"
|
104
162
|
f.puts "</html>"
|
105
163
|
f.close
|
106
164
|
end
|
107
165
|
|
166
|
+
def do_cx(f, cx)
|
167
|
+
f.puts "<table border='1'>"
|
168
|
+
cx.each_pair do |k, v|
|
169
|
+
f.puts "<tr><td>#{k}</td><td>#{v.inspect}</td></tr>"
|
170
|
+
end
|
171
|
+
f.puts "</table>"
|
172
|
+
end
|
173
|
+
|
108
174
|
def do_table(f, info)
|
109
175
|
f.puts "<table border='1'>"
|
110
176
|
info.sort{|a, b| a[0].to_s <=> b[0].to_s}.each do |tbl_name, tbl_impl|
|
@@ -117,11 +183,34 @@ def do_table(f, info)
|
|
117
183
|
f.puts "</table>"
|
118
184
|
end
|
119
185
|
|
186
|
+
def get_trace_data
|
187
|
+
data = nil
|
188
|
+
|
189
|
+
if @opts["t"]
|
190
|
+
data = {}
|
191
|
+
traces = @opts['t'].class == String ? [@opts['t']] : @opts['t']
|
192
|
+
traces.each do |t|
|
193
|
+
meta, da = get_meta2(t)
|
194
|
+
da.each do |d|
|
195
|
+
data[d[1]] ||= {}
|
196
|
+
data[d[1]][d[0]] ||= []
|
197
|
+
data[d[1]][d[0]] << d[2]
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
data
|
202
|
+
end
|
203
|
+
|
120
204
|
if ARGV.length < 2
|
121
205
|
puts "Usage: budplot LIST_OF_FILES LIST_OF_MODULES_OR_CLASSES"
|
122
206
|
exit
|
123
207
|
end
|
124
208
|
|
209
|
+
@opts = Getopt::Std.getopts("t:")
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
@data = get_trace_data
|
125
214
|
`mkdir bud_doc`
|
126
215
|
|
127
216
|
modules = []
|
data/bin/budvis
CHANGED
@@ -28,10 +28,9 @@ usage unless ARGV[0]
|
|
28
28
|
usage if ARGV[0] == '--help'
|
29
29
|
|
30
30
|
meta, data = get_meta2(BUD_DBM_DIR)
|
31
|
-
vh = VizHelper.new(meta[:tabinf], meta[:cycle], meta[:depends], meta[:rules], ARGV[0])
|
31
|
+
vh = VizHelper.new(meta[:tabinf], meta[:cycle], meta[:depends], meta[:rules], ARGV[0], meta[:provides])
|
32
32
|
data.each do |d|
|
33
33
|
vh.full_info << d
|
34
34
|
end
|
35
|
-
|
36
35
|
vh.tick
|
37
36
|
vh.summarize(ARGV[0], meta[:schminf])
|
data/docs/cheat.md
CHANGED
@@ -196,7 +196,7 @@ implicit map:
|
|
196
196
|
end
|
197
197
|
|
198
198
|
## BudCollection-Specific Methods ##
|
199
|
-
`bc.schema`: returns the schema of `bc` (Hash of key column names => non-key column names)<br>
|
199
|
+
`bc.schema`: returns the schema of `bc` (Hash of key column names => non-key column names). Note that for channels, this omits the location specifier (<tt>@</tt>).<br>
|
200
200
|
|
201
201
|
`bc.cols`: returns the column names in `bc` as an Array<br>
|
202
202
|
|
data/lib/bud/aggs.rb
CHANGED
@@ -181,7 +181,8 @@ module Bud
|
|
181
181
|
end
|
182
182
|
|
183
183
|
# aggregate method to be used in Bud::BudCollection.group.
|
184
|
-
# accumulates all x inputs into an array
|
184
|
+
# accumulates all x inputs into an array. note that the order of the elements
|
185
|
+
# in the resulting array is undefined.
|
185
186
|
def accum(x)
|
186
187
|
[Accum.new, x]
|
187
188
|
end
|
data/lib/bud/bud_meta.rb
CHANGED
@@ -49,7 +49,7 @@ class BudMeta #:nodoc: all
|
|
49
49
|
@bud_instance.sinks[s.first] = true
|
50
50
|
end
|
51
51
|
|
52
|
-
dump_rewrite(
|
52
|
+
dump_rewrite(no_attr_rewrite_strata) if @bud_instance.options[:dump_rewrite]
|
53
53
|
|
54
54
|
return rewritten_strata, no_attr_rewrite_strata
|
55
55
|
end
|
@@ -97,13 +97,13 @@ class BudMeta #:nodoc: all
|
|
97
97
|
unless rv.nil?
|
98
98
|
if rv.class <= Sexp
|
99
99
|
error_pt = rv
|
100
|
-
error_msg = "
|
100
|
+
error_msg = "parse error"
|
101
101
|
else
|
102
102
|
error_pt, error_msg = rv
|
103
103
|
end
|
104
104
|
|
105
|
-
# try to
|
106
|
-
#
|
105
|
+
# try to dump the source code associated with the problematic block, so as
|
106
|
+
# to produce a more meaningful error message.
|
107
107
|
begin
|
108
108
|
code = Ruby2Ruby.new.process(Marshal.load(Marshal.dump(error_pt)))
|
109
109
|
src_msg = "\nCode: #{code}"
|
@@ -139,7 +139,7 @@ class BudMeta #:nodoc: all
|
|
139
139
|
|
140
140
|
# Check for a common case
|
141
141
|
if n.sexp_type == :lasgn
|
142
|
-
return [n, "
|
142
|
+
return [n, "illegal operator: '='"]
|
143
143
|
end
|
144
144
|
return pt unless n.sexp_type == :call and n.length == 4
|
145
145
|
|
@@ -150,10 +150,10 @@ class BudMeta #:nodoc: all
|
|
150
150
|
return n if lhs.nil? or lhs.sexp_type != :call
|
151
151
|
lhs_name = lhs[2].to_sym
|
152
152
|
unless @bud_instance.tables.has_key? lhs_name
|
153
|
-
return [n, "
|
153
|
+
return [n, "collection does not exist: '#{lhs_name}'"]
|
154
154
|
end
|
155
155
|
|
156
|
-
return [n, "
|
156
|
+
return [n, "illegal operator: '#{op}'"] unless [:<, :<=].include? op
|
157
157
|
|
158
158
|
# Check superator invocation. A superator that begins with "<" is parsed
|
159
159
|
# as a call to the binary :< operator. The right operand to :< is a :call
|
@@ -195,6 +195,7 @@ class BudMeta #:nodoc: all
|
|
195
195
|
else
|
196
196
|
top = 1
|
197
197
|
end
|
198
|
+
|
198
199
|
return top
|
199
200
|
end
|
200
201
|
|
data/lib/bud/collections.rb
CHANGED
@@ -149,7 +149,7 @@ module Bud
|
|
149
149
|
# project the collection to its key attributes
|
150
150
|
public
|
151
151
|
def keys
|
152
|
-
self.map{|t|
|
152
|
+
self.map{|t| get_key_vals(t)}
|
153
153
|
end
|
154
154
|
|
155
155
|
# project the collection to its non-key attributes
|
@@ -255,6 +255,7 @@ module Bud
|
|
255
255
|
def [](k)
|
256
256
|
# assumes that key is in storage or delta, but not both
|
257
257
|
# is this enforced in do_insert?
|
258
|
+
check_enumerable(k)
|
258
259
|
t = @storage[k]
|
259
260
|
return t.nil? ? @delta[k] : t
|
260
261
|
end
|
@@ -264,7 +265,7 @@ module Bud
|
|
264
265
|
def include?(item)
|
265
266
|
return true if key_cols.nil? or (key_cols.empty? and length > 0)
|
266
267
|
return false if item.nil? or item.empty?
|
267
|
-
key =
|
268
|
+
key = get_key_vals(item)
|
268
269
|
return (item == self[key])
|
269
270
|
end
|
270
271
|
|
@@ -282,8 +283,8 @@ module Bud
|
|
282
283
|
|
283
284
|
private
|
284
285
|
def raise_pk_error(new_guy, old)
|
285
|
-
|
286
|
-
raise KeyConstraintError, "key conflict inserting #{new_guy.inspect} into \"#{tabname}\": existing tuple #{old.inspect},
|
286
|
+
key = get_key_vals(old)
|
287
|
+
raise KeyConstraintError, "key conflict inserting #{new_guy.inspect} into \"#{tabname}\": existing tuple #{old.inspect}, key = #{key.inspect}"
|
287
288
|
end
|
288
289
|
|
289
290
|
private
|
@@ -308,15 +309,22 @@ module Bud
|
|
308
309
|
return o
|
309
310
|
end
|
310
311
|
|
312
|
+
private
|
313
|
+
def get_key_vals(t)
|
314
|
+
@key_colnums.map do |i|
|
315
|
+
t[i]
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
311
319
|
private
|
312
320
|
def do_insert(o, store)
|
313
321
|
return if o.nil? # silently ignore nils resulting from map predicates failing
|
314
322
|
o = prep_tuple(o)
|
315
|
-
|
323
|
+
key = get_key_vals(o)
|
316
324
|
|
317
|
-
old = store[
|
325
|
+
old = store[key]
|
318
326
|
if old.nil?
|
319
|
-
store[
|
327
|
+
store[key] = tuple_accessors(o)
|
320
328
|
else
|
321
329
|
raise_pk_error(o, old) unless old == o
|
322
330
|
end
|
@@ -374,10 +382,10 @@ module Bud
|
|
374
382
|
end
|
375
383
|
|
376
384
|
private
|
377
|
-
def include_any_buf?(t,
|
385
|
+
def include_any_buf?(t, key)
|
378
386
|
bufs = [self, @delta, @new_delta]
|
379
387
|
bufs.each do |b|
|
380
|
-
old = b[
|
388
|
+
old = b[key]
|
381
389
|
next if old.nil?
|
382
390
|
if old != t
|
383
391
|
raise_pk_error(t, old)
|
@@ -391,16 +399,15 @@ module Bud
|
|
391
399
|
public
|
392
400
|
def merge(o, buf=@new_delta) # :nodoc: all
|
393
401
|
unless o.nil?
|
394
|
-
o = o.uniq if o.respond_to?(:uniq)
|
395
402
|
check_enumerable(o)
|
396
403
|
establish_schema(o) if @cols.nil?
|
397
404
|
|
398
|
-
# it's a pity that we are massaging
|
405
|
+
# it's a pity that we are massaging tuples that may be dups
|
399
406
|
o.each do |t|
|
400
407
|
next if t.nil? or t == []
|
401
408
|
t = prep_tuple(t)
|
402
|
-
|
403
|
-
buf[
|
409
|
+
key = get_key_vals(t)
|
410
|
+
buf[key] = tuple_accessors(t) unless include_any_buf?(t, key)
|
404
411
|
end
|
405
412
|
end
|
406
413
|
return self
|
@@ -432,7 +439,7 @@ module Bud
|
|
432
439
|
self <+ o
|
433
440
|
self <- o.map do |t|
|
434
441
|
unless t.nil?
|
435
|
-
self[
|
442
|
+
self[get_key_vals(t)]
|
436
443
|
end
|
437
444
|
end
|
438
445
|
end
|
@@ -461,9 +468,14 @@ module Bud
|
|
461
468
|
@new_delta = {}
|
462
469
|
end
|
463
470
|
|
464
|
-
|
465
|
-
def
|
466
|
-
@storage.
|
471
|
+
public
|
472
|
+
def length
|
473
|
+
@storage.length
|
474
|
+
end
|
475
|
+
|
476
|
+
public
|
477
|
+
def empty?
|
478
|
+
@storage.empty?
|
467
479
|
end
|
468
480
|
|
469
481
|
######## aggs
|
@@ -480,7 +492,6 @@ module Bud
|
|
480
492
|
end
|
481
493
|
end
|
482
494
|
|
483
|
-
|
484
495
|
# a generalization of argmin/argmax to arbitrary exemplary aggregates.
|
485
496
|
# for each distinct value of the grouping key columns, return the items in that group
|
486
497
|
# that have the value of the exemplary aggregate +aggname+
|
@@ -592,7 +603,7 @@ module Bud
|
|
592
603
|
# Attributes can be referenced as symbols, or as +collection_name.attribute_name+
|
593
604
|
public
|
594
605
|
def group(key_cols, *aggpairs)
|
595
|
-
key_cols
|
606
|
+
key_cols ||= []
|
596
607
|
keynames = key_cols.map do |k|
|
597
608
|
if k.class == Symbol
|
598
609
|
k
|
@@ -892,15 +903,15 @@ module Bud
|
|
892
903
|
public
|
893
904
|
def tick #:nodoc: all
|
894
905
|
@to_delete.each do |tuple|
|
895
|
-
|
896
|
-
if @storage[
|
897
|
-
@storage.delete
|
906
|
+
key = get_key_vals(tuple)
|
907
|
+
if @storage[key] == tuple
|
908
|
+
@storage.delete key
|
898
909
|
end
|
899
910
|
end
|
900
|
-
@pending.each do |
|
901
|
-
old = @storage[
|
911
|
+
@pending.each do |key, tuple|
|
912
|
+
old = @storage[key]
|
902
913
|
if old.nil?
|
903
|
-
@storage[
|
914
|
+
@storage[key] = tuple
|
904
915
|
else
|
905
916
|
raise_pk_error(tuple, old) unless tuple == old
|
906
917
|
end
|
@@ -957,26 +968,3 @@ module Bud
|
|
957
968
|
end
|
958
969
|
end
|
959
970
|
end
|
960
|
-
|
961
|
-
module Enumerable
|
962
|
-
public
|
963
|
-
# monkeypatch to Enumerable to rename collections and their schemas
|
964
|
-
def rename(new_tabname, new_schema=nil)
|
965
|
-
budi = (respond_to?(:bud_instance)) ? bud_instance : nil
|
966
|
-
if new_schema.nil? and respond_to?(:schema)
|
967
|
-
new_schema = schema
|
968
|
-
end
|
969
|
-
scr = Bud::BudScratch.new(new_tabname.to_s, budi, new_schema)
|
970
|
-
scr.uniquify_tabname
|
971
|
-
scr.merge(self, scr.storage)
|
972
|
-
scr
|
973
|
-
end
|
974
|
-
|
975
|
-
public
|
976
|
-
# We rewrite "map" calls in Bloom blocks to invoke the "pro" method
|
977
|
-
# instead. This is fine when applied to a BudCollection; when applied to a
|
978
|
-
# normal Enumerable, just treat pro as an alias for map.
|
979
|
-
def pro(&blk)
|
980
|
-
map(&blk)
|
981
|
-
end
|
982
|
-
end
|
data/lib/bud/graphs.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'digest/md5'
|
3
2
|
require 'graphviz'
|
4
3
|
|
5
4
|
class GraphGen #:nodoc: all
|
6
5
|
attr_reader :nodes
|
7
6
|
|
8
|
-
def initialize(tableinfo, builtin_tables, cycle, name, budtime, collapse=false, cardinalities={})
|
7
|
+
def initialize(tableinfo, builtin_tables, cycle, name, budtime, collapse=false, cardinalities={}, pathsto={}, begins={})
|
9
8
|
@graph = GraphViz.new(:G, :type => :digraph, :label => "")
|
9
|
+
#@graph.dim = 2
|
10
10
|
@graph.node[:fontname] = "Times-Roman"
|
11
11
|
@graph.node[:fontsize] = 18
|
12
12
|
@graph.edge[:fontname] = "Times-Roman"
|
@@ -16,6 +16,8 @@ class GraphGen #:nodoc: all
|
|
16
16
|
@collapse = collapse
|
17
17
|
@budtime = budtime
|
18
18
|
@builtin_tables = builtin_tables
|
19
|
+
@pathsto = pathsto
|
20
|
+
@begins = begins
|
19
21
|
|
20
22
|
# map: table name -> type
|
21
23
|
@tabinf = {}
|
@@ -87,20 +89,46 @@ class GraphGen #:nodoc: all
|
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
92
|
+
def color_node(paths)
|
93
|
+
return "" if paths.nil?
|
94
|
+
|
95
|
+
case paths[0][:val]
|
96
|
+
when :A, :N
|
97
|
+
"yellow"
|
98
|
+
when :D, :G
|
99
|
+
"red"
|
100
|
+
else
|
101
|
+
puts "UNKNOWN tag #{paths[0][:val]} class #{paths[0][:val].class}"
|
102
|
+
"black"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
90
106
|
def addonce(node, negcluster, inhead=false)
|
91
107
|
if !@nodes[node]
|
92
|
-
@nodes[node] = @graph.
|
108
|
+
@nodes[node] = @graph.add_nodes(node)
|
109
|
+
node_p = @nodes[node]
|
110
|
+
node_p.label = node
|
111
|
+
if @begins[:finish] and @begins[:finish][node]
|
112
|
+
# point of divergence.
|
113
|
+
node_p.penwidth = 4
|
114
|
+
end
|
115
|
+
|
93
116
|
if @cards and @cards[node]
|
94
|
-
|
117
|
+
node_p.label = "#{node}\n (#{@cards[node].to_s})"
|
118
|
+
node_p.color = "green"
|
95
119
|
else
|
96
|
-
@
|
120
|
+
p = @pathsto[node].nil? ? "" : "\n(#{@pathsto[node][0][:val]})"
|
121
|
+
node_p.label = node + p
|
122
|
+
node_p.color = color_node(@pathsto[node])
|
97
123
|
end
|
124
|
+
else
|
125
|
+
node_p = @nodes[node]
|
98
126
|
end
|
99
127
|
|
100
128
|
if @budtime == -1
|
101
|
-
|
129
|
+
node_p.URL = "#{node}.html" if inhead
|
102
130
|
else
|
103
|
-
|
131
|
+
node_p.URL = "javascript:openWin(\"#{node}\", #{@budtime})"
|
104
132
|
end
|
105
133
|
|
106
134
|
if negcluster
|
@@ -116,13 +144,13 @@ class GraphGen #:nodoc: all
|
|
116
144
|
res = res + ", " + p
|
117
145
|
end
|
118
146
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
147
|
+
node_p.label = res
|
148
|
+
node_p.color = "red"
|
149
|
+
node_p.shape = "octagon"
|
150
|
+
node_p.penwidth = 3
|
151
|
+
node_p.URL = "#{File.basename(@name).gsub(".staging", "").gsub("collapsed", "expanded")}.svg"
|
124
152
|
elsif @tabinf[node] and (@tabinf[node] == "Bud::BudTable")
|
125
|
-
|
153
|
+
node_p.shape = "rect"
|
126
154
|
end
|
127
155
|
end
|
128
156
|
|
@@ -134,9 +162,10 @@ class GraphGen #:nodoc: all
|
|
134
162
|
|
135
163
|
ekey = body + head
|
136
164
|
if !@edges[ekey]
|
137
|
-
@edges[ekey] = @graph.
|
165
|
+
@edges[ekey] = @graph.add_edges(@nodes[body], @nodes[head], :penwidth => 5)
|
138
166
|
@edges[ekey].arrowsize = 2
|
139
167
|
|
168
|
+
@edges[ekey].color = (@nodes[body]["color"].source || "")
|
140
169
|
@edges[ekey].URL = "#{rule_id}.html" unless rule_id.nil?
|
141
170
|
if head =~ /_msg\z/
|
142
171
|
@edges[ekey].minlen = 2
|
@@ -212,7 +241,7 @@ class GraphGen #:nodoc: all
|
|
212
241
|
if output.nil?
|
213
242
|
@graph.output(:svg => @name)
|
214
243
|
else
|
215
|
-
@graph.output(output => @name)
|
244
|
+
@graph.output(output.to_sym => @name)
|
216
245
|
end
|
217
246
|
end
|
218
247
|
end
|
@@ -234,9 +263,8 @@ class SpaceTime
|
|
234
263
|
@head = {}
|
235
264
|
last = nil
|
236
265
|
processes.each_with_index do |p, i|
|
237
|
-
#@head[p] = @hdr.add_node("process #{p}(#{i})")#, :color => "white", :label => "")
|
238
266
|
@subs[p] = @g.subgraph("buster_#{i+1}")
|
239
|
-
@head[p] = @hdr.
|
267
|
+
@head[p] = @hdr.add_nodes("process #{p}(#{i})", :group => p)#, :color => "white", :label => "")
|
240
268
|
end
|
241
269
|
end
|
242
270
|
|
@@ -272,10 +300,9 @@ class SpaceTime
|
|
272
300
|
if @links
|
273
301
|
url = "DBM_#{k}/tm_#{item}.svg"
|
274
302
|
end
|
275
|
-
snd = @subs[k].
|
276
|
-
|
303
|
+
snd = @subs[k].add_nodes(label, {:label => item.to_s, :width => 0.1, :height => 0.1, :fontsize => 6, :group => k, :URL => url})
|
277
304
|
unless @head[k].id == snd.id
|
278
|
-
@subs[k].
|
305
|
+
@subs[k].add_edges(@head[k], snd, :weight => 2)
|
279
306
|
@head[k] = snd
|
280
307
|
end
|
281
308
|
end
|
@@ -295,7 +322,7 @@ class SpaceTime
|
|
295
322
|
def finish(file, fmt=nil)
|
296
323
|
@edges.each_pair do |k, v|
|
297
324
|
lbl = v[3] > 1 ? "#{v[2]}(#{v[3]})" : v[2]
|
298
|
-
@g.
|
325
|
+
@g.add_edges(v[0], v[1], :label => lbl, :color => "red", :weight => 1)
|
299
326
|
end
|
300
327
|
if fmt.nil?
|
301
328
|
@g.output(:svg => "#{file}.svg")
|
data/lib/bud/joins.rb
CHANGED
@@ -291,7 +291,7 @@ module Bud
|
|
291
291
|
otherpreds = allpreds - @localpreds
|
292
292
|
unless otherpreds.empty?
|
293
293
|
unless @rels[1].class <= Bud::BudJoin
|
294
|
-
raise Bud::CompileError, "join predicates don't match
|
294
|
+
raise Bud::CompileError, "join predicates don't match collections being joined: #{otherpreds.inspect}"
|
295
295
|
end
|
296
296
|
@rels[1].setup_preds(otherpreds)
|
297
297
|
end
|