diagrammatron 0.4.3 → 0.5.0
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.
- 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),
|