diagrammatron 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/diagrammatron-edges +28 -42
- data/bin/diagrammatron-get +4 -5
- data/bin/diagrammatron-nodes +18 -40
- data/bin/diagrammatron-place +20 -21
- data/bin/diagrammatron-prune +15 -7
- data/bin/diagrammatron-render +22 -20
- data/bin/diagrammatron-schema +107 -0
- data/bin/diagrammatron-subset +188 -0
- data/bin/dot_json2diagrammatron +14 -25
- data/lib/common.rb +50 -2
- data/lib/edges.yaml +45 -0
- data/lib/nodes.yaml +36 -0
- data/lib/place.yaml +65 -0
- data/lib/render.yaml +111 -0
- data/lib/subset.yaml +55 -0
- metadata +36 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c51dc3c8502bd1626d2a78bccd7e772e60fb25a26e6327879f42144849db598
|
4
|
+
data.tar.gz: 78548d0ad0af86031afecb81bf4fedca42da58420d0de3a0d5063f07cb68538e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03d48ecd6c7e586007dcb470655fff6814e21d32f1921dcb828b35602bea208e48f58d9ba2ea5cdf5f16fb8f633a242a9d43a599c21fbf61d5ffaa631282c827
|
7
|
+
data.tar.gz: 5ed263d065a49d69a031fa140ac0159d58301da26f4b51807573e5b8eefbeca6238301f6953cca5c8b44423a83fec18903a7e9d960a5b3fcf1d4702f1b671233
|
data/bin/diagrammatron-edges
CHANGED
@@ -6,54 +6,32 @@
|
|
6
6
|
|
7
7
|
require_relative '../lib/common'
|
8
8
|
require 'optparse'
|
9
|
-
require 'yaml'
|
10
9
|
require 'set'
|
11
|
-
require 'pathname'
|
12
10
|
|
13
11
|
|
14
12
|
def work_copy(src, quiet)
|
15
13
|
work = { edges: {}, nodes: [] }
|
16
|
-
# Expected nodes, edges. Other pass-through.
|
17
14
|
label2idx = {}
|
18
15
|
errors = false
|
19
16
|
edge_nodes = Set.new
|
20
|
-
edges = src
|
21
|
-
unedges = []
|
17
|
+
edges = src['edges']
|
22
18
|
selfedges = []
|
23
19
|
edges.each_index do |k|
|
24
20
|
edge = edges[k]
|
25
|
-
labels = edge
|
26
|
-
if labels.
|
27
|
-
|
28
|
-
elsif labels.size == 2
|
29
|
-
if labels.first == labels.last
|
30
|
-
selfedges.push(k)
|
31
|
-
else
|
32
|
-
edge_nodes.add labels.first
|
33
|
-
edge_nodes.add labels.last
|
34
|
-
work[:edges][k] = { idx: k, between: [ labels[0], labels[1] ] }
|
35
|
-
end
|
21
|
+
labels = edge['between']
|
22
|
+
if labels.first == labels.last
|
23
|
+
selfedges.push(k)
|
36
24
|
else
|
37
|
-
|
38
|
-
|
25
|
+
edge_nodes.add labels.first
|
26
|
+
edge_nodes.add labels.last
|
27
|
+
work[:edges][k] = { idx: k, between: [ labels[0], labels[1] ] }
|
39
28
|
end
|
40
29
|
end
|
41
30
|
labeled_nodes = Set.new
|
42
|
-
|
43
|
-
nodes = src.fetch('nodes', [])
|
31
|
+
nodes = src['nodes']
|
44
32
|
subsets = {}
|
45
33
|
nodes.each_index do |k|
|
46
34
|
node = nodes[k]
|
47
|
-
unless node.key? 'sid'
|
48
|
-
aargh "Node without sid: #{node.fetch('label', k + 1)}"
|
49
|
-
errors = true
|
50
|
-
next
|
51
|
-
end
|
52
|
-
unless node.key?('xo') && node.key?('yo')
|
53
|
-
aargh "Node without xo or yo: #{node.fetch('label', k + 1)}"
|
54
|
-
errors = true
|
55
|
-
next
|
56
|
-
end
|
57
35
|
sid = node['sid']
|
58
36
|
subsets[sid] = [] unless subsets.key? sid
|
59
37
|
subsets[sid].push(k)
|
@@ -63,10 +41,6 @@ def work_copy(src, quiet)
|
|
63
41
|
xo: node['xo'] * 2, # Make room for edge coordinates.
|
64
42
|
yo: node['yo'] * 2
|
65
43
|
})
|
66
|
-
unless node.key? 'label'
|
67
|
-
unlabeled.push k
|
68
|
-
next
|
69
|
-
end
|
70
44
|
label = node['label']
|
71
45
|
if label2idx.key?(label) && edge_nodes.member?(label)
|
72
46
|
aargh "Edge-referred label used twice: #{label}"
|
@@ -80,12 +54,14 @@ def work_copy(src, quiet)
|
|
80
54
|
aargh "Edges refer to missing node labels: #{missing.to_a.join(' ')}"
|
81
55
|
errors = true
|
82
56
|
end
|
57
|
+
unless selfedges.empty?
|
58
|
+
info = selfedges.map { |k| "#{edges[k]['between'].first} (#{k})" }
|
59
|
+
aargh "Edges from node to itself: #{info.join(' ')}"
|
60
|
+
errors = true
|
61
|
+
end
|
83
62
|
return nil if errors
|
84
63
|
unused = labeled_nodes - edge_nodes
|
85
|
-
[ [ unused.to_a, 'unconnected labeled nodes' ]
|
86
|
-
[ unlabeled, 'unlabeled nodes' ],
|
87
|
-
[ selfedges, 'edges from node to itself' ],
|
88
|
-
[ unedges, 'edges without end-points' ]
|
64
|
+
[ [ unused.to_a, 'unconnected labeled nodes' ]
|
89
65
|
].each do |x|
|
90
66
|
next if quiet || x.first.empty?
|
91
67
|
aargh("Note, #{x.last}: #{x.first.join(' ')}")
|
@@ -125,7 +101,7 @@ Segment = Struct.new(:vertical, :cc, :range, :edge_index, :at_node, :segment_ind
|
|
125
101
|
node_subset.each do |n|
|
126
102
|
node = work[:nodes][n]
|
127
103
|
next unless cc == node[ck]
|
128
|
-
|
104
|
+
2.times do |k|
|
129
105
|
return true if range[i0] < node[rk] && node[rk] < range[i1]
|
130
106
|
next if at_node[k]
|
131
107
|
return true if range[k] == node[rk]
|
@@ -631,7 +607,7 @@ def place_edges(work)
|
|
631
607
|
all.push nil
|
632
608
|
all.concat(layered_order(gright, glur).reverse)
|
633
609
|
# Give each rational offset using layer index + 1 and layer count + 2.
|
634
|
-
denominator = 2 + all.count
|
610
|
+
denominator = 2 + all.count(&:nil?)
|
635
611
|
layer = 1
|
636
612
|
all.each do |sg|
|
637
613
|
if sg.nil?
|
@@ -737,6 +713,8 @@ end
|
|
737
713
|
def main
|
738
714
|
input = nil
|
739
715
|
output = nil
|
716
|
+
input_schema = 'edges'
|
717
|
+
output_schema = 'place'
|
740
718
|
quiet = false
|
741
719
|
parser = OptionParser.new do |opts|
|
742
720
|
opts.summary_indent = ' '
|
@@ -757,13 +735,21 @@ def main
|
|
757
735
|
$stdout.puts %(#{opts}
|
758
736
|
|
759
737
|
Input YAML file is expected to be the output of diagrammatron-nodes.
|
738
|
+
|
739
|
+
Input YAML file schema is returned by:
|
740
|
+
diagrammatron-schema #{input_schema}
|
741
|
+
|
742
|
+
Output YAML file schema is returned by:
|
743
|
+
diagrammatron-schema #{output_schema}
|
744
|
+
|
745
|
+
There can be other fields present but they are ignored and retained.
|
760
746
|
)
|
761
747
|
exit 0
|
762
748
|
end
|
763
749
|
end
|
764
750
|
parser.parse! ARGV
|
765
751
|
|
766
|
-
doc =
|
752
|
+
doc = load_verified(input, input_schema)
|
767
753
|
return 2 if doc.nil?
|
768
754
|
|
769
755
|
begin
|
@@ -775,7 +761,7 @@ Input YAML file is expected to be the output of diagrammatron-nodes.
|
|
775
761
|
|
776
762
|
place_edges(work)
|
777
763
|
prepare_output(doc, work)
|
778
|
-
|
764
|
+
save_verified(output, doc, 4, output_schema)
|
779
765
|
end
|
780
766
|
|
781
767
|
exit(main) if (defined? $unit_test).nil?
|
data/bin/diagrammatron-get
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
# Copyright © 2021
|
4
|
+
# Copyright © 2021-2023 Ismo Kärkkäinen
|
5
5
|
# Licensed under Universal Permissive License. See LICENSE.txt.
|
6
6
|
|
7
7
|
require_relative '../lib/common'
|
8
8
|
require 'optparse'
|
9
|
-
require 'pathname'
|
10
9
|
|
11
10
|
|
12
11
|
def template(name = nil)
|
@@ -28,8 +27,8 @@ def main
|
|
28
27
|
end
|
29
28
|
opts.on('-h', '--help', 'Print this help and exit.') do
|
30
29
|
$stdout.puts %(#{opts}
|
31
|
-
This is used to easily access template files included in the gem without
|
32
|
-
to clone the original repository.
|
30
|
+
This is used to easily access template files included in the gem without
|
31
|
+
the need to clone the original repository.
|
33
32
|
|
34
33
|
Without arguments, lists all templates, template root, and content files
|
35
34
|
included in the gem.
|
@@ -41,7 +40,7 @@ Given a name of a included file, saves it to --output.
|
|
41
40
|
end
|
42
41
|
parser.parse! ARGV
|
43
42
|
|
44
|
-
if ARGV.
|
43
|
+
if ARGV.empty?
|
45
44
|
# List all files in templates directory.
|
46
45
|
Dir.entries(template).sort.each do |name|
|
47
46
|
next if name.start_with? '.'
|
data/bin/diagrammatron-nodes
CHANGED
@@ -6,9 +6,7 @@
|
|
6
6
|
|
7
7
|
require_relative '../lib/common'
|
8
8
|
require 'optparse'
|
9
|
-
require 'yaml'
|
10
9
|
require 'set'
|
11
|
-
require 'pathname'
|
12
10
|
|
13
11
|
|
14
12
|
def vertical(work)
|
@@ -139,7 +137,7 @@ def shifts(count)
|
|
139
137
|
side = (count / 2.0).ceil
|
140
138
|
side = ((side / 4) + ((side % 4).positive? ? 1 : 0)) * 4
|
141
139
|
xs = Array.new(side) { |index| Integer((index - side / 2).round) }
|
142
|
-
|
140
|
+
4.times { |k| xs.push(-xs[k]) }
|
143
141
|
ys = Array.new(xs)
|
144
142
|
xs.rotate!(side / 2 - 1)
|
145
143
|
ys.rotate!(side - 1) # First half-way to offset with xs, then like xs.
|
@@ -281,36 +279,23 @@ def work_copy(src, quiet)
|
|
281
279
|
errors = false
|
282
280
|
edge_nodes = Set.new
|
283
281
|
edges = src.fetch('edges', [])
|
284
|
-
unedges = []
|
285
282
|
selfedges = []
|
286
283
|
edges.each_index do |k|
|
287
284
|
edge = edges[k]
|
288
|
-
labels = edge
|
289
|
-
if labels.
|
290
|
-
|
291
|
-
elsif labels.size == 2
|
292
|
-
if labels.first == labels.last
|
293
|
-
selfedges.push(k)
|
294
|
-
else
|
295
|
-
edge_nodes.add labels.first
|
296
|
-
edge_nodes.add labels.last
|
297
|
-
work[:edges].push({ idx: k, between: [ labels[0], labels[1] ] })
|
298
|
-
end
|
285
|
+
labels = edge['between']
|
286
|
+
if labels.first == labels.last
|
287
|
+
selfedges.push(k)
|
299
288
|
else
|
300
|
-
|
301
|
-
|
289
|
+
edge_nodes.add labels.first
|
290
|
+
edge_nodes.add labels.last
|
291
|
+
work[:edges].push({ idx: k, between: [ labels[0], labels[1] ] })
|
302
292
|
end
|
303
293
|
end
|
304
294
|
labeled_nodes = Set.new
|
305
|
-
unlabeled = []
|
306
295
|
nodes = src.fetch('nodes', [])
|
307
296
|
nodes.each_index do |k|
|
308
297
|
work[:nodes].push({ idx: k })
|
309
298
|
node = nodes[k]
|
310
|
-
unless node.key? 'label'
|
311
|
-
unlabeled.push k
|
312
|
-
next
|
313
|
-
end
|
314
299
|
label = node['label']
|
315
300
|
if label2idx.key?(label) && edge_nodes.member?(label)
|
316
301
|
aargh "Edge-referred label used twice: #{label}"
|
@@ -327,9 +312,7 @@ def work_copy(src, quiet)
|
|
327
312
|
return nil if errors
|
328
313
|
unused = labeled_nodes - edge_nodes
|
329
314
|
[ [ unused.to_a, 'unconnected labeled nodes' ],
|
330
|
-
[
|
331
|
-
[ selfedges, 'edges from node to itself' ],
|
332
|
-
[ unedges, 'edges without end-points' ]
|
315
|
+
[ selfedges, 'edges from node to itself' ]
|
333
316
|
].each do |x|
|
334
317
|
next if quiet || x.first.empty?
|
335
318
|
aargh("Note, #{x.last}: #{x.first.join(' ')}")
|
@@ -351,6 +334,8 @@ def prepare_output(doc, work)
|
|
351
334
|
end
|
352
335
|
|
353
336
|
def main
|
337
|
+
input_schema = 'nodes'
|
338
|
+
output_schema = 'edges'
|
354
339
|
input = nil
|
355
340
|
output = nil
|
356
341
|
algo = 'pathlength'
|
@@ -378,22 +363,15 @@ def main
|
|
378
363
|
$stdout.puts %(
|
379
364
|
Algorithm names are: #{$algorithms.keys.sort.join(' ')}
|
380
365
|
|
381
|
-
Input YAML file is
|
382
|
-
|
383
|
-
|
384
|
-
- label: something
|
385
|
-
- label: another
|
386
|
-
- ignored: "Since no label. Still placed."
|
387
|
-
- label: "Unused and ok. Still placed."
|
388
|
-
edges:
|
389
|
-
- between: [ something, another ]
|
390
|
-
- between: [ something, something ] # Ignored.
|
391
|
-
- between: [ ] # Ignored.
|
392
|
-
- ignored: "Since no between."
|
393
|
-
...
|
366
|
+
Input YAML file schema is returned by:
|
367
|
+
diagrammatron-schema #{input_schema}
|
368
|
+
|
394
369
|
There can be other fields present but they are ignored. The nodes will
|
395
370
|
receive values xo and yo that indicate horizontal and vertical coordinates.
|
396
371
|
|
372
|
+
Output YAML file schema is returned by:
|
373
|
+
diagrammatron-schema #{output_schema}
|
374
|
+
|
397
375
|
Output is the input file with 'xo', 'yo' and 'sid' added to each node.
|
398
376
|
The 'xo' and 'yo' indicate which unique x- and y-coordinate the value is.
|
399
377
|
The 'sid' indicates the sub-diagram consisting of connected nodes.
|
@@ -408,7 +386,7 @@ The 'sid' indicates the sub-diagram consisting of connected nodes.
|
|
408
386
|
end
|
409
387
|
algo = $algorithms[algo]
|
410
388
|
|
411
|
-
doc =
|
389
|
+
doc = load_verified(input, input_schema)
|
412
390
|
return 2 if doc.nil?
|
413
391
|
|
414
392
|
begin
|
@@ -420,7 +398,7 @@ The 'sid' indicates the sub-diagram consisting of connected nodes.
|
|
420
398
|
|
421
399
|
algo.call(work)
|
422
400
|
prepare_output(doc, work)
|
423
|
-
|
401
|
+
save_verified(output, doc, 4, output_schema)
|
424
402
|
end
|
425
403
|
|
426
404
|
exit(main) if (defined? $unit_test).nil?
|
data/bin/diagrammatron-place
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
# Copyright © 2021
|
4
|
+
# Copyright © 2021-2023 Ismo Kärkkäinen
|
5
5
|
# Licensed under Universal Permissive License. See LICENSE.txt.
|
6
6
|
|
7
7
|
require_relative '../lib/common'
|
8
8
|
require 'optparse'
|
9
|
-
require 'yaml'
|
10
9
|
require 'set'
|
11
|
-
require 'pathname'
|
12
10
|
|
13
|
-
|
11
|
+
|
12
|
+
def info(msg)
|
14
13
|
$stderr.puts(msg) unless $QUIET
|
15
|
-
return_value
|
16
14
|
end
|
17
15
|
|
18
16
|
BoundingBox = Struct.new(:xmin, :ymin, :xmax, :ymax) do
|
@@ -91,22 +89,19 @@ end
|
|
91
89
|
|
92
90
|
def work_copy(src)
|
93
91
|
work = { edges: {}, nodes: {} }
|
94
|
-
|
95
|
-
nodes = src.fetch('nodes', [])
|
92
|
+
nodes = src['nodes']
|
96
93
|
nodes.each_index do |k|
|
97
94
|
node = nodes[k]
|
98
|
-
sid = node
|
99
|
-
xo = node
|
100
|
-
yo = node
|
101
|
-
next if sid.nil? || xo.nil? || yo.nil?
|
95
|
+
sid = node['sid']
|
96
|
+
xo = node['xo']
|
97
|
+
yo = node['yo']
|
102
98
|
work[:nodes][sid] = work[:nodes].fetch(sid, []).push(Node.new(k, sid, xo, yo))
|
103
99
|
end
|
104
|
-
edges = src
|
100
|
+
edges = src['edges']
|
105
101
|
edges.each_index do |k|
|
106
102
|
edge = edges[k]
|
107
|
-
path = edge
|
108
|
-
sid = edge
|
109
|
-
next if path.nil? || sid.nil?
|
103
|
+
path = edge['path']
|
104
|
+
sid = edge['sid']
|
110
105
|
work[:edges][sid] = work[:edges].fetch(sid, []).push(Edge.new(k, sid, path))
|
111
106
|
end
|
112
107
|
work[:subsets] = work[:nodes].keys.to_set.merge(work[:edges].keys.to_set).to_a
|
@@ -140,7 +135,7 @@ def area_order(bbs)
|
|
140
135
|
end
|
141
136
|
order.sort! do |a, b|
|
142
137
|
d = area_compare(a[1], b[1])
|
143
|
-
|
138
|
+
d.zero? ? (a[0] <=> b[0]) : d
|
144
139
|
end
|
145
140
|
order
|
146
141
|
end
|
@@ -362,6 +357,7 @@ $QUIET = false
|
|
362
357
|
def main
|
363
358
|
input = nil
|
364
359
|
output = nil
|
360
|
+
input_output_schema = 'edges'
|
365
361
|
algo = 'tallwide'
|
366
362
|
parser = OptionParser.new do |opts|
|
367
363
|
opts.summary_indent = ' '
|
@@ -389,10 +385,13 @@ def main
|
|
389
385
|
$stdout.puts %(
|
390
386
|
Algorithm names are: #{$algorithms.keys.sort.join(' ')}
|
391
387
|
|
392
|
-
Input YAML file is
|
388
|
+
Input and output YAML file schema is returned by:
|
389
|
+
diagrammatron-schema #{input_output_schema}
|
390
|
+
|
391
|
+
There can be other fields present but they are ignored and retained.
|
393
392
|
|
394
|
-
Output is the input file with 'xo' and '
|
395
|
-
|
393
|
+
Output is the input file with 'xo', 'yo', and 'path' modified to remove
|
394
|
+
overlap between sub-diagrams and edges.
|
396
395
|
)
|
397
396
|
exit 0
|
398
397
|
end
|
@@ -415,7 +414,7 @@ do not overlap.
|
|
415
414
|
end
|
416
415
|
algo = $algorithms[algo]
|
417
416
|
|
418
|
-
doc =
|
417
|
+
doc = load_verified(input, input_output_schema)
|
419
418
|
return 2 if doc.nil?
|
420
419
|
|
421
420
|
begin
|
@@ -427,7 +426,7 @@ do not overlap.
|
|
427
426
|
|
428
427
|
algo.call(work)
|
429
428
|
prepare_output(doc, work)
|
430
|
-
|
429
|
+
save_verified(output, doc, 4, input_output_schema)
|
431
430
|
end
|
432
431
|
|
433
432
|
exit(main) if (defined? $unit_test).nil?
|
data/bin/diagrammatron-prune
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
# Copyright © 2021 Ismo Kärkkäinen
|
4
|
+
# Copyright © 2021-2023 Ismo Kärkkäinen
|
5
5
|
# Licensed under Universal Permissive License. See LICENSE.txt.
|
6
6
|
|
7
7
|
require_relative '../lib/common'
|
8
8
|
require 'optparse'
|
9
|
-
require 'yaml'
|
10
9
|
require 'set'
|
11
|
-
require 'pathname'
|
12
10
|
|
13
11
|
|
14
12
|
def prune_array(original, matching, keep)
|
@@ -26,7 +24,12 @@ def prune(doc, patterns, keep)
|
|
26
24
|
nodes = doc.fetch('nodes', [])
|
27
25
|
matching = Array.new(nodes.size, false)
|
28
26
|
nodes.each_index do |k|
|
29
|
-
label = nodes[k].fetch('label',
|
27
|
+
label = nodes[k].fetch('label', nil)
|
28
|
+
if label.nil?
|
29
|
+
# Schemas require 'label' to be present.
|
30
|
+
matching[k] = !keep
|
31
|
+
next
|
32
|
+
end
|
30
33
|
patterns.each do |p|
|
31
34
|
next unless p.match(label)
|
32
35
|
matching[k] = true
|
@@ -40,10 +43,12 @@ def prune(doc, patterns, keep)
|
|
40
43
|
edges.each_index do |k|
|
41
44
|
between = edges[k].fetch('between', [])
|
42
45
|
if between.size != 2
|
43
|
-
matching[k] = keep #
|
46
|
+
matching[k] = !keep # Schemas require between size to be 2.
|
44
47
|
elsif keep
|
48
|
+
# Both ends matched reversed remove rule, keep the edge.
|
45
49
|
matching[k] = (labels.member?(between[0]) && labels.member?(between[1]))
|
46
50
|
else
|
51
|
+
# If either end matched remove rule, remove the edge.
|
47
52
|
matching[k] = (labels.member?(between[0]) || labels.member?(between[1]))
|
48
53
|
end
|
49
54
|
end
|
@@ -53,6 +58,7 @@ end
|
|
53
58
|
def main
|
54
59
|
input = nil
|
55
60
|
output = nil
|
61
|
+
input_output_schema = 'nodes'
|
56
62
|
keep = false
|
57
63
|
ENV['POSIXLY_CORRECT'] = '1' # Leaves patterns as they are.
|
58
64
|
parser = OptionParser.new do |opts|
|
@@ -75,6 +81,8 @@ def main
|
|
75
81
|
Patterns are strings used to create Ruby Regexps.
|
76
82
|
|
77
83
|
Input YAML file is expected to be dot_json2diagrammatron output.
|
84
|
+
Input and output YAML file schema is returned by:
|
85
|
+
diagrammatron-schema #{input_output_schema}
|
78
86
|
|
79
87
|
Output is the input file with nodes that have labels that match patterns
|
80
88
|
removed or kept depending on options. Edges to removed nodes are removed.
|
@@ -89,7 +97,7 @@ removed or kept depending on options. Edges to removed nodes are removed.
|
|
89
97
|
rescue StandardError => e
|
90
98
|
return aargh("Error creating Regexp: #{e}", 1)
|
91
99
|
end
|
92
|
-
doc =
|
100
|
+
doc = load_verified(input, input_output_schema)
|
93
101
|
return 2 if doc.nil?
|
94
102
|
|
95
103
|
begin
|
@@ -98,7 +106,7 @@ removed or kept depending on options. Edges to removed nodes are removed.
|
|
98
106
|
return aargh('Error processing input.', 3)
|
99
107
|
end
|
100
108
|
|
101
|
-
|
109
|
+
save_verified(output, doc, 4, input_output_schema)
|
102
110
|
end
|
103
111
|
|
104
112
|
exit(main) if (defined? $unit_test).nil?
|
data/bin/diagrammatron-render
CHANGED
@@ -61,8 +61,7 @@ def separate_coordinates(doc)
|
|
61
61
|
push_coords(xcoords, ycoords, ckd2count, node.clone, 1, 1, true)
|
62
62
|
end
|
63
63
|
doc['edges'].each do |edge|
|
64
|
-
path = edge
|
65
|
-
next if path.nil?
|
64
|
+
path = edge['path']
|
66
65
|
xdirection, ydirection = end_directions(path[0], path[1])
|
67
66
|
push_coords(xcoords, ycoords, ckd2count, path[0], xdirection, ydirection)
|
68
67
|
(1...(path.size - 1)).each do |k|
|
@@ -99,7 +98,7 @@ class Styles
|
|
99
98
|
@d = base_styles(base_styles({}, template_styles, 'diagram'), diagram_styles, 'diagram')
|
100
99
|
end
|
101
100
|
|
102
|
-
def fill(mapping,
|
101
|
+
def fill(mapping, _type_name, item)
|
103
102
|
styles = item.fetch('style', [ 'default' ])
|
104
103
|
styles = [ styles ] unless styles.is_a?(Array)
|
105
104
|
s = {}
|
@@ -112,7 +111,7 @@ class Styles
|
|
112
111
|
end
|
113
112
|
s.merge!(mapping['default']) unless found # Merge default at least.
|
114
113
|
# Keep values specified explicitly.
|
115
|
-
item.merge!(s) { |
|
114
|
+
item.merge!(s) { |_key, existing, from_template| existing || from_template }
|
116
115
|
end
|
117
116
|
|
118
117
|
def apply_node_styles(node)
|
@@ -169,7 +168,7 @@ def estimate_sizes(doc, ckd2count)
|
|
169
168
|
$render = SizeEstimation.new(ckd2count, doc)
|
170
169
|
doc['nodes'].each do |node|
|
171
170
|
$render.node = node
|
172
|
-
label = node
|
171
|
+
label = node['label']
|
173
172
|
style = node.fetch('style', 'default')
|
174
173
|
code = node.fetch('size_estimator',
|
175
174
|
%(raise NotImplementedError, "No size estimator for style: #{style}"))
|
@@ -187,7 +186,7 @@ end
|
|
187
186
|
def maxima(doc)
|
188
187
|
xmax = Hash.new(0)
|
189
188
|
ymax = Hash.new(0)
|
190
|
-
doc
|
189
|
+
doc['nodes'].each do |node|
|
191
190
|
xmax[node['xo']] = [ node['w'], xmax[node['xo']] ].max
|
192
191
|
ymax[node['yo']] = [ node['h'], ymax[node['yo']] ].max
|
193
192
|
end
|
@@ -195,7 +194,7 @@ def maxima(doc)
|
|
195
194
|
end
|
196
195
|
|
197
196
|
def apply_maxima(doc, xmax, ymax)
|
198
|
-
doc
|
197
|
+
doc['nodes'].each do |node|
|
199
198
|
node['w'] = xmax[node['xo']]
|
200
199
|
node['h'] = ymax[node['yo']]
|
201
200
|
end
|
@@ -258,13 +257,12 @@ class Render
|
|
258
257
|
def dimensions
|
259
258
|
w = 0
|
260
259
|
h = 0
|
261
|
-
@doc
|
260
|
+
@doc['nodes'].each do |node|
|
262
261
|
w = [ w, node['xo'] + node['w'] ].max
|
263
262
|
h = [ h, node['yo'] + node['h'] ].max
|
264
263
|
end
|
265
|
-
@doc
|
266
|
-
path = edge
|
267
|
-
next if path.nil?
|
264
|
+
@doc['edges'].each do |edge|
|
265
|
+
path = edge['path']
|
268
266
|
path.each do |p|
|
269
267
|
w = [ w, p['xo'] ].max
|
270
268
|
h = [ h, p['yo'] ].max
|
@@ -305,6 +303,7 @@ end
|
|
305
303
|
def main
|
306
304
|
template = nil
|
307
305
|
input = nil
|
306
|
+
input_schema = 'render'
|
308
307
|
output = nil
|
309
308
|
styles = nil
|
310
309
|
parser = OptionParser.new do |opts|
|
@@ -324,7 +323,10 @@ def main
|
|
324
323
|
end
|
325
324
|
opts.on('-h', '--help', 'Print this help and exit.') do
|
326
325
|
$stdout.puts %(#{opts}
|
327
|
-
Input YAML file is
|
326
|
+
Input YAML file schema is returned by:
|
327
|
+
diagrammatron-schema #{input_schema}
|
328
|
+
|
329
|
+
There can be other fields present as needed by the template.
|
328
330
|
|
329
331
|
Output is the file produced by the erb-template.
|
330
332
|
)
|
@@ -347,15 +349,15 @@ Output is the file produced by the erb-template.
|
|
347
349
|
end
|
348
350
|
end
|
349
351
|
|
350
|
-
doc =
|
352
|
+
doc = load_verified(input, input_schema)
|
351
353
|
return 2 if doc.nil?
|
352
354
|
|
353
355
|
styles = Styles.new(template.fetch('styles', {}), doc.fetch('styles', {}))
|
354
|
-
doc
|
356
|
+
doc['nodes'].each do |node|
|
355
357
|
styles.apply_node_styles(node)
|
356
|
-
node['text'] = node.fetch('text', node
|
358
|
+
node['text'] = node.fetch('text', node['label']).split("\n")
|
357
359
|
end
|
358
|
-
doc
|
360
|
+
doc['edges'].each { |edge| styles.apply_edge_styles(edge) }
|
359
361
|
doc['diagram'] = {} unless doc.key? 'diagram'
|
360
362
|
styles.apply_diagram_styles(doc['diagram'])
|
361
363
|
|
@@ -376,16 +378,16 @@ Output is the file produced by the erb-template.
|
|
376
378
|
remap_coordinates(xcoords, xmax, x2min, doc.dig('diagram', 'edge_gap'))
|
377
379
|
remap_coordinates(ycoords, ymax, y2min, doc.dig('diagram', 'edge_gap'))
|
378
380
|
|
379
|
-
doc['nodes'] = reverse_depth_sort(doc
|
380
|
-
doc['edges'] = reverse_depth_sort(doc
|
381
|
-
all = doc
|
381
|
+
doc['nodes'] = reverse_depth_sort(doc['nodes'])
|
382
|
+
doc['edges'] = reverse_depth_sort(doc['edges'])
|
383
|
+
all = doc['nodes'].map do |a|
|
382
384
|
{
|
383
385
|
'kind' => 'node',
|
384
386
|
'depth' => a.fetch('depth', 0),
|
385
387
|
'item' => a
|
386
388
|
}
|
387
389
|
end
|
388
|
-
all.concat(doc
|
390
|
+
all.concat(doc['edges'].map do |a|
|
389
391
|
{
|
390
392
|
'kind' => 'edge',
|
391
393
|
'depth' => a.fetch('depth', 0),
|