diver_down 0.0.1.alpha13 → 0.0.1.alpha14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/exe/diver_down_web +4 -4
- data/lib/diver_down/definition/dependency.rb +10 -0
- data/lib/diver_down/definition/method_id.rb +6 -0
- data/lib/diver_down/definition/source.rb +13 -0
- data/lib/diver_down/definition.rb +8 -0
- data/lib/diver_down/version.rb +1 -1
- data/lib/diver_down/web/action.rb +119 -34
- data/lib/diver_down/web/definition_store.rb +20 -2
- data/lib/diver_down/web/definition_to_dot.rb +86 -74
- data/lib/diver_down/web/metadata/source_alias.rb +128 -0
- data/lib/diver_down/web/metadata/source_metadata.rb +59 -0
- data/lib/diver_down/web/metadata.rb +66 -0
- data/lib/diver_down/web/module_sources_filter.rb +54 -0
- data/lib/diver_down/web/source_alias_resolver.rb +46 -0
- data/lib/diver_down/web.rb +24 -5
- data/web/assets/CFQbqqGu.css +1 -0
- data/web/assets/bundle.js +191 -166
- data/web/index.html +1 -1
- metadata +9 -5
- data/lib/diver_down/web/module_store.rb +0 -92
- data/web/assets/CjLq7LhZ.css +0 -1
@@ -12,8 +12,8 @@ module DiverDown
|
|
12
12
|
# Between modules is prominently distanced
|
13
13
|
MODULE_MINLEN = 3
|
14
14
|
|
15
|
-
class
|
16
|
-
|
15
|
+
class DotMetadataStore
|
16
|
+
DotMetadata = Data.define(:id, :type, :data, :metadata) do
|
17
17
|
# @return [Hash]
|
18
18
|
def to_h
|
19
19
|
case type
|
@@ -31,7 +31,7 @@ module DiverDown
|
|
31
31
|
private
|
32
32
|
|
33
33
|
def source_to_h
|
34
|
-
modules =
|
34
|
+
modules = metadata.source(data.source_name).modules.map do
|
35
35
|
{
|
36
36
|
module_name: _1,
|
37
37
|
}
|
@@ -41,7 +41,7 @@ module DiverDown
|
|
41
41
|
id:,
|
42
42
|
type: 'source',
|
43
43
|
source_name: data.source_name,
|
44
|
-
memo:
|
44
|
+
memo: metadata.source(data.source_name).memo,
|
45
45
|
modules:,
|
46
46
|
}
|
47
47
|
end
|
@@ -77,11 +77,11 @@ module DiverDown
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
def initialize(
|
80
|
+
def initialize(metadata)
|
81
81
|
@prefix = 'graph_'
|
82
|
-
@
|
82
|
+
@metadata = metadata
|
83
83
|
|
84
|
-
# Hash{ id =>
|
84
|
+
# Hash{ id => DotMetadata }
|
85
85
|
@to_h = {}
|
86
86
|
end
|
87
87
|
|
@@ -89,13 +89,13 @@ module DiverDown
|
|
89
89
|
# @param record [DiverDown::Definition::Source]
|
90
90
|
# @return [String]
|
91
91
|
def issue_source_id(source)
|
92
|
-
|
92
|
+
build_dot_metadata_and_return_id(:source, source)
|
93
93
|
end
|
94
94
|
|
95
95
|
# @param dependency [DiverDown::Definition::Dependency]
|
96
96
|
# @return [String]
|
97
97
|
def issue_dependency_id(dependency)
|
98
|
-
|
98
|
+
build_dot_metadata_and_return_id(:dependency, [dependency])
|
99
99
|
end
|
100
100
|
|
101
101
|
# @param module_names [Array<String>]
|
@@ -106,17 +106,17 @@ module DiverDown
|
|
106
106
|
if issued_metadata
|
107
107
|
issued_metadata.id
|
108
108
|
else
|
109
|
-
|
109
|
+
build_dot_metadata_and_return_id(:module, module_names)
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
113
|
# @param id [String]
|
114
114
|
# @param dependency [DiverDown::Definition::Dependency]
|
115
115
|
def append_dependency(id, dependency)
|
116
|
-
|
117
|
-
dependencies =
|
116
|
+
dot_metadata = @to_h.fetch(id)
|
117
|
+
dependencies = dot_metadata.data
|
118
118
|
combined_dependencies = DiverDown::Definition::Dependency.combine(*dependencies, dependency)
|
119
|
-
|
119
|
+
dot_metadata.data.replace(combined_dependencies)
|
120
120
|
end
|
121
121
|
|
122
122
|
# @return [Array<Hash>]
|
@@ -126,10 +126,10 @@ module DiverDown
|
|
126
126
|
|
127
127
|
private
|
128
128
|
|
129
|
-
def
|
129
|
+
def build_dot_metadata_and_return_id(type, data)
|
130
130
|
id = "#{@prefix}#{length + 1}"
|
131
|
-
|
132
|
-
@to_h[id] =
|
131
|
+
dot_metadata = DotMetadata.new(id:, type:, data:, metadata: @metadata)
|
132
|
+
@to_h[id] = dot_metadata
|
133
133
|
|
134
134
|
id
|
135
135
|
end
|
@@ -140,24 +140,24 @@ module DiverDown
|
|
140
140
|
end
|
141
141
|
|
142
142
|
# @param definition [DiverDown::Definition]
|
143
|
-
# @param
|
143
|
+
# @param metadata [DiverDown::Web::Metadata]
|
144
144
|
# @param compound [Boolean]
|
145
145
|
# @param concentrate [Boolean] https://graphviz.org/docs/attrs/concentrate/
|
146
|
-
def initialize(definition,
|
146
|
+
def initialize(definition, metadata, compound: false, concentrate: false, only_module: false)
|
147
147
|
@definition = definition
|
148
|
-
@
|
148
|
+
@metadata = metadata
|
149
149
|
@io = DiverDown::Web::IndentedStringIo.new
|
150
150
|
@indent = 0
|
151
151
|
@compound = compound || only_module # When only-module is enabled, dependencies between modules are displayed as compound.
|
152
152
|
@compound_map = Hash.new { |h, k| h[k] = {} } # Hash{ ltail => Hash{ lhead => issued id } }
|
153
153
|
@concentrate = concentrate
|
154
154
|
@only_module = only_module
|
155
|
-
@
|
155
|
+
@dot_metadata_store = DotMetadataStore.new(metadata)
|
156
156
|
end
|
157
157
|
|
158
158
|
# @return [Array<Hash>]
|
159
|
-
def
|
160
|
-
@
|
159
|
+
def dot_metadata
|
160
|
+
@dot_metadata_store.to_a
|
161
161
|
end
|
162
162
|
|
163
163
|
# @return [String]
|
@@ -179,18 +179,18 @@ module DiverDown
|
|
179
179
|
|
180
180
|
private
|
181
181
|
|
182
|
-
attr_reader :definition, :
|
182
|
+
attr_reader :definition, :metadata, :io
|
183
183
|
|
184
184
|
def render_only_modules
|
185
185
|
# Hash{ from_module => { to_module => Array<DiverDown::Definition::Dependency> } }
|
186
186
|
dependency_map = Hash.new { |h, k| h[k] = Hash.new { |hi, ki| hi[ki] = [] } }
|
187
187
|
|
188
188
|
definition.sources.sort_by(&:source_name).each do |source|
|
189
|
-
source_modules =
|
189
|
+
source_modules = metadata.source(source.source_name).modules
|
190
190
|
next if source_modules.empty?
|
191
191
|
|
192
192
|
source.dependencies.each do |dependency|
|
193
|
-
dependency_modules =
|
193
|
+
dependency_modules = metadata.source(dependency.source_name).modules
|
194
194
|
next if dependency_modules.empty?
|
195
195
|
|
196
196
|
dependency_map[source_modules][dependency_modules].push(dependency)
|
@@ -198,7 +198,7 @@ module DiverDown
|
|
198
198
|
end
|
199
199
|
|
200
200
|
# Remove duplicated prefix modules
|
201
|
-
# from [["A"], ["A", "B"]] to
|
201
|
+
# from [["A"], ["A", "B"], ["A", "C"], ["D"]] to { "A" => { "B" => {}, "C" => {} }, "D" => {} }
|
202
202
|
uniq_modules = [*dependency_map.keys, *dependency_map.values.map(&:keys).flatten(1)].uniq
|
203
203
|
uniq_modules.reject! do |modules|
|
204
204
|
modules.empty? ||
|
@@ -215,9 +215,9 @@ module DiverDown
|
|
215
215
|
|
216
216
|
io.puts %(subgraph "#{escape_quote(module_label(module_names))}" {)
|
217
217
|
io.indented do
|
218
|
-
io.puts %(id="#{@
|
218
|
+
io.puts %(id="#{@dot_metadata_store.issue_modules_id(module_names)}")
|
219
219
|
io.puts %(label="#{escape_quote(module_name)}")
|
220
|
-
io.puts %("#{escape_quote(module_name)}" #{build_attributes(label: module_name, id: @
|
220
|
+
io.puts %("#{escape_quote(module_name)}" #{build_attributes(label: module_name, id: @dot_metadata_store.issue_modules_id(module_names))})
|
221
221
|
|
222
222
|
next_proc&.call
|
223
223
|
end
|
@@ -245,11 +245,11 @@ module DiverDown
|
|
245
245
|
# Add the dependency to the edge of the compound
|
246
246
|
if @compound_map[ltail].include?(lhead)
|
247
247
|
compound_id = @compound_map[ltail][lhead]
|
248
|
-
@
|
248
|
+
@dot_metadata_store.append_dependency(compound_id, _1)
|
249
249
|
next
|
250
250
|
end
|
251
251
|
|
252
|
-
compound_id = @
|
252
|
+
compound_id = @dot_metadata_store.issue_dependency_id(_1)
|
253
253
|
@compound_map[ltail][lhead] = compound_id
|
254
254
|
|
255
255
|
attributes.merge!(
|
@@ -268,67 +268,57 @@ module DiverDown
|
|
268
268
|
end
|
269
269
|
|
270
270
|
def render_sources
|
271
|
+
# Hash{ modules => sources }
|
272
|
+
# Hash{ Array<String> => Array<DiverDown::Definition::Source> }
|
271
273
|
by_modules = definition.sources.group_by do |source|
|
272
|
-
|
274
|
+
metadata.source(source.source_name).modules
|
273
275
|
end
|
274
276
|
|
275
|
-
#
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
277
|
+
# Render subgraph for each module and its sources second
|
278
|
+
nested_modules = array_to_hash(by_modules.keys.uniq.sort)
|
279
|
+
render_nested_modules_sources(by_modules, nested_modules)
|
280
|
+
|
281
|
+
# Render dependencies last
|
282
|
+
definition.sources.sort_by(&:source_name).each do |source|
|
283
|
+
insert_dependencies(source)
|
280
284
|
end
|
285
|
+
end
|
281
286
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
287
|
+
def render_nested_modules_sources(by_modules, nested_modules, prefix = [])
|
288
|
+
nested_modules.each do |module_name, next_nested_modules|
|
289
|
+
module_names = prefix + [module_name].compact
|
290
|
+
sources = (by_modules[module_names] || []).sort_by(&:source_name)
|
286
291
|
|
292
|
+
if module_name.nil?
|
287
293
|
sources.each do |source|
|
288
|
-
|
294
|
+
io.puts build_source_node(source)
|
289
295
|
end
|
290
296
|
else
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
io.puts %(subgraph "#{escape_quote(module_label(module_names))}" {)
|
299
|
-
io.indented do
|
300
|
-
io.puts %(id="#{@metadata_store.issue_modules_id(module_names)}")
|
301
|
-
io.puts %(label="#{escape_quote(module_name)}")
|
302
|
-
|
303
|
-
sources = (by_modules[module_names] || []).sort_by(&:source_name)
|
304
|
-
sources.each do |source|
|
305
|
-
insert_source(source)
|
306
|
-
end
|
307
|
-
|
308
|
-
next_proc&.call
|
309
|
-
end
|
310
|
-
io.puts '}'
|
297
|
+
io.puts %(subgraph "#{escape_quote(module_label(module_names))}" {)
|
298
|
+
io.indented do
|
299
|
+
io.puts %(id="#{@dot_metadata_store.issue_modules_id(module_names)}")
|
300
|
+
io.puts %(label="#{escape_quote(module_name)}")
|
301
|
+
|
302
|
+
sources.each do |source|
|
303
|
+
io.puts build_source_node(source)
|
311
304
|
end
|
312
|
-
end
|
313
305
|
|
314
|
-
|
306
|
+
render_nested_modules_sources(by_modules, next_nested_modules, module_names)
|
307
|
+
end
|
308
|
+
io.puts '}'
|
315
309
|
end
|
316
310
|
end
|
317
|
-
|
318
|
-
definition.sources.sort_by(&:source_name).each do |source|
|
319
|
-
insert_dependencies(source)
|
320
|
-
end
|
321
311
|
end
|
322
312
|
|
323
|
-
def
|
324
|
-
|
313
|
+
def build_source_node(source)
|
314
|
+
%("#{escape_quote(source.source_name)}" #{build_attributes(label: source.source_name, id: @dot_metadata_store.issue_source_id(source))})
|
325
315
|
end
|
326
316
|
|
327
317
|
def insert_dependencies(source)
|
328
318
|
source.dependencies.each do
|
329
319
|
attributes = {}
|
330
|
-
ltail = module_label(*
|
331
|
-
lhead = module_label(*
|
320
|
+
ltail = module_label(*metadata.source(source.source_name).modules)
|
321
|
+
lhead = module_label(*metadata.source(_1.source_name).modules)
|
332
322
|
|
333
323
|
if @compound && (ltail || lhead)
|
334
324
|
# Rendering of dependencies between modules is done only once
|
@@ -338,11 +328,11 @@ module DiverDown
|
|
338
328
|
# Add the dependency to the edge of the compound
|
339
329
|
if between_modules && @compound_map[ltail].include?(lhead)
|
340
330
|
compound_id = @compound_map[ltail][lhead]
|
341
|
-
@
|
331
|
+
@dot_metadata_store.append_dependency(compound_id, _1)
|
342
332
|
next
|
343
333
|
end
|
344
334
|
|
345
|
-
compound_id = @
|
335
|
+
compound_id = @dot_metadata_store.issue_dependency_id(_1)
|
346
336
|
@compound_map[ltail][lhead] = compound_id
|
347
337
|
|
348
338
|
attributes.merge!(
|
@@ -353,7 +343,7 @@ module DiverDown
|
|
353
343
|
)
|
354
344
|
else
|
355
345
|
attributes.merge!(
|
356
|
-
id: @
|
346
|
+
id: @dot_metadata_store.issue_dependency_id(_1)
|
357
347
|
)
|
358
348
|
end
|
359
349
|
|
@@ -420,6 +410,28 @@ module DiverDown
|
|
420
410
|
def escape_quote(string)
|
421
411
|
string.to_s.gsub(/"/, '\"')
|
422
412
|
end
|
413
|
+
|
414
|
+
# from [["A"], ["A", "B"], ["A", "C"], ["D"]] to { "A" => { "B" => {}, "C" => {} }, "D" => {} }
|
415
|
+
def array_to_hash(array)
|
416
|
+
hash = {}
|
417
|
+
array.each do |sub_array|
|
418
|
+
current_hash = hash
|
419
|
+
|
420
|
+
if sub_array.empty?
|
421
|
+
current_hash[nil] = {}
|
422
|
+
else
|
423
|
+
sub_array.each_with_index do |element, index|
|
424
|
+
if index == sub_array.length - 1
|
425
|
+
current_hash[element] = {}
|
426
|
+
else
|
427
|
+
current_hash[element] ||= {}
|
428
|
+
current_hash = current_hash[element]
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
hash
|
434
|
+
end
|
423
435
|
end
|
424
436
|
end
|
425
437
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiverDown
|
4
|
+
class Web
|
5
|
+
class Metadata
|
6
|
+
class SourceAlias
|
7
|
+
class ConflictError < StandardError
|
8
|
+
attr_reader :source_name
|
9
|
+
|
10
|
+
def initialize(message, source_name:)
|
11
|
+
@source_name = source_name
|
12
|
+
|
13
|
+
super(message)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
BLANK_RE = /\A\s*\z/
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
# Hash{ alias_name => Set<source_name, ...> }
|
21
|
+
@alias_to_source_names = {}
|
22
|
+
@source_name_to_alias = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param alias_name [String]
|
26
|
+
# @param source_names [Array<String>]
|
27
|
+
# @return [void]
|
28
|
+
def update_alias(alias_name, source_names)
|
29
|
+
source_names = source_names.reject { BLANK_RE.match?(_1) }
|
30
|
+
|
31
|
+
if source_names.empty?
|
32
|
+
prev_source_names = @alias_to_source_names.delete(alias_name)
|
33
|
+
prev_source_names&.each do |prev_source_name|
|
34
|
+
@source_name_to_alias.delete(prev_source_name)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
check_conflict(alias_name, source_names)
|
38
|
+
@alias_to_source_names[alias_name] = source_names.sort
|
39
|
+
|
40
|
+
source_names.each do |source_name|
|
41
|
+
@source_name_to_alias[source_name] = alias_name
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param alias_name [String]
|
47
|
+
# @return [String]
|
48
|
+
def resolve_alias(source_name)
|
49
|
+
@source_name_to_alias[source_name] if @source_name_to_alias.key?(source_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param alias_name [String]
|
53
|
+
# @return [Array<String>]
|
54
|
+
def aliased_source_names(alias_name)
|
55
|
+
@alias_to_source_names[alias_name] if @alias_to_source_names.key?(alias_name)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Rollback the changes made in the block if an conflict error occurs.
|
59
|
+
#
|
60
|
+
# @raise [ConflictError]
|
61
|
+
def transaction
|
62
|
+
alias_to_source_names = deep_dup(@alias_to_source_names)
|
63
|
+
source_name_to_alias = deep_dup(@source_name_to_alias)
|
64
|
+
|
65
|
+
yield
|
66
|
+
rescue ConflictError
|
67
|
+
@alias_to_source_names = alias_to_source_names
|
68
|
+
@source_name_to_alias = source_name_to_alias
|
69
|
+
|
70
|
+
raise
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Hash]
|
74
|
+
def to_h
|
75
|
+
keys = @alias_to_source_names.keys.sort
|
76
|
+
keys.to_h { [_1, aliased_source_names(_1)] }
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def deep_dup(hash)
|
82
|
+
hash.transform_values do
|
83
|
+
if _1.is_a?(Hash)
|
84
|
+
deep_dup(_1)
|
85
|
+
else
|
86
|
+
_1.dup
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def added_source_names(excluding_alias_name)
|
92
|
+
source_names = Set.new
|
93
|
+
|
94
|
+
@alias_to_source_names.each_key do |name|
|
95
|
+
next if excluding_alias_name == name
|
96
|
+
|
97
|
+
source_names.add(name)
|
98
|
+
|
99
|
+
@alias_to_source_names[name].each do |source_name|
|
100
|
+
source_names.add(source_name)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
source_names
|
105
|
+
end
|
106
|
+
|
107
|
+
def check_conflict(alias_name, source_names)
|
108
|
+
if source_names.any? { _1 == alias_name }
|
109
|
+
raise(ConflictError.new("Cannot create an alias for '#{alias_name}' that refers to itself.", source_name: alias_name))
|
110
|
+
end
|
111
|
+
|
112
|
+
registered_source_names = added_source_names(alias_name)
|
113
|
+
|
114
|
+
if registered_source_names.include?(alias_name)
|
115
|
+
raise ConflictError.new("Alias '#{alias_name}' is already aliased.", source_name: alias_name)
|
116
|
+
end
|
117
|
+
|
118
|
+
conflicted_source_name = source_names.find { registered_source_names.include?(_1) }
|
119
|
+
|
120
|
+
if conflicted_source_name
|
121
|
+
resolved_source_name = resolve_alias(conflicted_source_name)
|
122
|
+
raise ConflictError.new("Source '#{conflicted_source_name}' is already aliased to '#{resolved_source_name}'.", source_name: conflicted_source_name)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiverDown
|
4
|
+
class Web
|
5
|
+
class Metadata
|
6
|
+
class SourceMetadata
|
7
|
+
BLANK_MEMO = ''
|
8
|
+
BLANK_RE = /\A\s*\z/
|
9
|
+
BLANK_ARRAY = [].freeze
|
10
|
+
private_constant(:BLANK_MEMO)
|
11
|
+
private_constant(:BLANK_RE)
|
12
|
+
private_constant(:BLANK_ARRAY)
|
13
|
+
|
14
|
+
attr_reader :memo, :modules
|
15
|
+
|
16
|
+
# @param source_name [String]
|
17
|
+
def initialize(memo: BLANK_MEMO, modules: BLANK_ARRAY)
|
18
|
+
@memo = memo
|
19
|
+
@modules = modules
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param memo [String]
|
23
|
+
# @return [void]
|
24
|
+
def memo=(memo)
|
25
|
+
@memo = memo.strip
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param module_names [Array<String>]
|
29
|
+
# @return [void]
|
30
|
+
def modules=(module_names)
|
31
|
+
@modules = module_names.reject do
|
32
|
+
BLANK_RE.match?(_1)
|
33
|
+
end.freeze
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Boolean]
|
37
|
+
def modules?
|
38
|
+
@modules.any?
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Hash]
|
42
|
+
def to_h
|
43
|
+
hash = {}
|
44
|
+
|
45
|
+
hash[:memo] = memo unless memo == BLANK_MEMO
|
46
|
+
hash[:modules] = modules unless modules.empty?
|
47
|
+
|
48
|
+
hash
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def by_source_name(source_name)
|
54
|
+
@store[source_name] ||= {}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiverDown
|
4
|
+
class Web
|
5
|
+
class Metadata
|
6
|
+
require 'diver_down/web/metadata/source_metadata'
|
7
|
+
require 'diver_down/web/metadata/source_alias'
|
8
|
+
|
9
|
+
attr_reader :source_alias
|
10
|
+
|
11
|
+
# @param path [String]
|
12
|
+
def initialize(path)
|
13
|
+
@path = path
|
14
|
+
load
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param source_name [String]
|
18
|
+
# @return [DiverDown::Web::Metadata::SourceMetadata]
|
19
|
+
def source(source_name)
|
20
|
+
@source_map[source_name]
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Hash]
|
24
|
+
def to_h
|
25
|
+
source_names = @source_map.keys.sort
|
26
|
+
|
27
|
+
sources = source_names.filter_map {
|
28
|
+
h = source(_1).to_h
|
29
|
+
[_1, h] unless h.empty?
|
30
|
+
}.to_h
|
31
|
+
|
32
|
+
{
|
33
|
+
sources:,
|
34
|
+
source_alias: @source_alias.to_h,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Write store to file
|
39
|
+
# @return [void]
|
40
|
+
def flush
|
41
|
+
File.write(@path, to_h.to_yaml)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def load
|
47
|
+
@source_map = Hash.new { |h, source_name| h[source_name] = DiverDown::Web::Metadata::SourceMetadata.new }
|
48
|
+
@source_alias = DiverDown::Web::Metadata::SourceAlias.new
|
49
|
+
|
50
|
+
loaded = YAML.load_file(@path)
|
51
|
+
|
52
|
+
return if loaded.nil?
|
53
|
+
|
54
|
+
# NOTE: This is for backward compatibility. It will be removed in the future.
|
55
|
+
(loaded[:sources] || loaded || []).each do |source_name, source_hash|
|
56
|
+
source(source_name).memo = source_hash[:memo] if source_hash[:memo]
|
57
|
+
source(source_name).modules = source_hash[:modules] if source_hash[:modules]
|
58
|
+
end
|
59
|
+
|
60
|
+
loaded[:source_alias]&.each do |alias_name, source_names|
|
61
|
+
@source_alias.update_alias(alias_name, source_names)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiverDown
|
4
|
+
class Web
|
5
|
+
class ModuleSourcesFilter
|
6
|
+
# @param metadata_alias [DiverDown::Web::Metadata]
|
7
|
+
def initialize(metadata)
|
8
|
+
@metadata = metadata
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param definition [DiverDown::Definition]
|
12
|
+
# @param modules [Array<Array<String>>]
|
13
|
+
# @return [DiverDown::Definition]
|
14
|
+
def filter(definition, modules:)
|
15
|
+
new_definition = DiverDown::Definition.new(
|
16
|
+
definition_group: definition.definition_group,
|
17
|
+
title: definition.title
|
18
|
+
)
|
19
|
+
|
20
|
+
is_match_modules = ->(source_name) do
|
21
|
+
source_modules = @metadata.source(source_name).modules
|
22
|
+
source_modules.first(modules.size) == modules
|
23
|
+
end
|
24
|
+
|
25
|
+
definition.sources.each do |source|
|
26
|
+
next unless is_match_modules.call(source.source_name)
|
27
|
+
|
28
|
+
new_source = new_definition.find_or_build_source(source.source_name)
|
29
|
+
|
30
|
+
source.dependencies.each do |dependency|
|
31
|
+
next unless is_match_modules.call(dependency.source_name)
|
32
|
+
|
33
|
+
new_dependency = new_source.find_or_build_dependency(dependency.source_name)
|
34
|
+
|
35
|
+
next unless new_dependency
|
36
|
+
|
37
|
+
dependency.method_ids.each do |method_id|
|
38
|
+
new_method_id = new_dependency.find_or_build_method_id(
|
39
|
+
context: method_id.context,
|
40
|
+
name: method_id.name
|
41
|
+
)
|
42
|
+
|
43
|
+
method_id.paths.each do |path|
|
44
|
+
new_method_id.add_path(path)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
new_definition
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DiverDown
|
4
|
+
class Web
|
5
|
+
class SourceAliasResolver
|
6
|
+
# @param metadata_alias [DiverDown::Web::Metadata::SourceAlias]
|
7
|
+
def initialize(metadata_alias)
|
8
|
+
@metadata_alias = metadata_alias
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param definition [DiverDown::Definition]
|
12
|
+
# @return [DiverDown::Definition]
|
13
|
+
def resolve(definition)
|
14
|
+
new_definition = DiverDown::Definition.new(
|
15
|
+
definition_group: definition.definition_group,
|
16
|
+
title: definition.title
|
17
|
+
)
|
18
|
+
|
19
|
+
definition.sources.each do |source|
|
20
|
+
resolved_source_name = @metadata_alias.resolve_alias(source.source_name) || source.source_name
|
21
|
+
new_source = new_definition.find_or_build_source(resolved_source_name)
|
22
|
+
|
23
|
+
source.dependencies.each do |dependency|
|
24
|
+
resolved_dependency_source_name = @metadata_alias.resolve_alias(dependency.source_name) || dependency.source_name
|
25
|
+
new_dependency = new_source.find_or_build_dependency(resolved_dependency_source_name)
|
26
|
+
|
27
|
+
next unless new_dependency
|
28
|
+
|
29
|
+
dependency.method_ids.each do |method_id|
|
30
|
+
new_method_id = new_dependency.find_or_build_method_id(
|
31
|
+
context: method_id.context,
|
32
|
+
name: method_id.name
|
33
|
+
)
|
34
|
+
|
35
|
+
method_id.paths.each do |path|
|
36
|
+
new_method_id.add_path(path)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
new_definition
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|