diver_down 0.0.1.alpha13 → 0.0.1.alpha14
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/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
|