jekyll-archimate 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/jekyll-archimate.rb +23 -1
- data/lib/jekyll/archimate/application_interaction_matrix_tag.rb +42 -50
- data/lib/jekyll/archimate/archimate_cache.rb +34 -57
- data/lib/jekyll/archimate/archimate_diagram_tag.rb +6 -4
- data/lib/jekyll/archimate/archimate_generator.rb +31 -0
- data/lib/jekyll/archimate/archimate_index_generator.rb +29 -0
- data/lib/jekyll/archimate/archimate_svg_generator.rb +53 -0
- data/lib/jekyll/archimate/catalog_tag.rb +23 -12
- data/lib/jekyll/archimate/conditional_file.rb +45 -0
- data/lib/jekyll/archimate/diagram_entity.rb +19 -0
- data/lib/jekyll/archimate/element_entity.rb +26 -0
- data/lib/jekyll/archimate/entity_base.rb +29 -0
- data/lib/jekyll/archimate/folder.rb +29 -0
- data/lib/jekyll/archimate/json_file.rb +18 -0
- data/lib/jekyll/archimate/matrix_tag.rb +34 -84
- data/lib/jekyll/archimate/model_entity.rb +14 -0
- data/lib/jekyll/archimate/relationship_entity.rb +24 -0
- data/lib/jekyll/archimate/svg_file.rb +18 -0
- data/lib/jekyll/archimate/unified_model.rb +47 -0
- data/lib/jekyll/archimate/version.rb +3 -1
- metadata +15 -3
- data/lib/jekyll/archimate/archimate_hook.rb +0 -265
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 450c76bef35c5a96c2dd7b52a7e8598ef0b3910a
|
4
|
+
data.tar.gz: 9506cf3a7a0a23f70ac2f4083be19f9ae25023b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad3da00341c4db0c5329e8e23a50cdf1eac79c9f0fcbf36db9f85a6cfd8acc4171716a98539c77f69183cc27053f2d28b2965a0ab3c43c0cd4674dc8bdc2bd21
|
7
|
+
data.tar.gz: 79ac5eae532d4709e7fe08de80acea38649c8f3c95ae8d5029a565648ef1b5a442681b888c91ae00069e15bed420d7258e0a29c5ded297e54b82a9730b691bc5
|
data/.gitignore
CHANGED
data/lib/jekyll-archimate.rb
CHANGED
@@ -1,8 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "jekyll"
|
4
|
+
require "archimate"
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module Archimate
|
8
|
+
# Removes all keys that have null or empty values
|
9
|
+
def self.hash_purge(hash)
|
10
|
+
hash.delete_if { |_, value| !value || (value.is_a?(String) && value.empty?) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
2
14
|
|
3
15
|
require "jekyll/archimate/version"
|
4
16
|
require "jekyll/archimate/archimate_cache"
|
5
17
|
require "jekyll/archimate/archimate_diagram_tag"
|
6
18
|
require "jekyll/archimate/catalog_tag"
|
7
19
|
require "jekyll/archimate/application_interaction_matrix_tag"
|
8
|
-
require "jekyll/archimate/
|
20
|
+
require "jekyll/archimate/conditional_file"
|
21
|
+
require "jekyll/archimate/archimate_index_generator"
|
22
|
+
require "jekyll/archimate/archimate_svg_generator"
|
23
|
+
require "jekyll/archimate/entity_base"
|
24
|
+
require "jekyll/archimate/model_entity"
|
25
|
+
require "jekyll/archimate/element_entity"
|
26
|
+
require "jekyll/archimate/relationship_entity"
|
27
|
+
require "jekyll/archimate/diagram_entity"
|
28
|
+
require "jekyll/archimate/folder"
|
29
|
+
require "jekyll/archimate/unified_model"
|
30
|
+
require "jekyll/archimate/archimate_generator"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jekyll
|
2
4
|
module Archimate
|
3
5
|
# Insert a diagram from the ArchiMate model.
|
@@ -5,12 +7,13 @@ module Jekyll
|
|
5
7
|
# {% application_interaction_matrix plateau:"Today" | caption: "Today's Application Interaction" }
|
6
8
|
#
|
7
9
|
class ApplicationInteractionMatrixTag < Liquid::Tag
|
10
|
+
EMPTY_CELL = "<td></td>"
|
11
|
+
|
8
12
|
attr_reader :context
|
9
13
|
attr_reader :markup
|
10
14
|
attr_reader :caption
|
11
15
|
attr_reader :plateau
|
12
16
|
|
13
|
-
|
14
17
|
def initialize(tag_name, markup, tokens)
|
15
18
|
@markup = markup
|
16
19
|
@context = nil
|
@@ -34,27 +37,26 @@ module Jekyll
|
|
34
37
|
# target_selector: Element selector for target elements
|
35
38
|
# relationship_selector
|
36
39
|
def application_interaction
|
37
|
-
model =
|
40
|
+
model = ArchimateCache.instance.model
|
38
41
|
dr_engine = ::Archimate::DerivedRelations.new(model)
|
39
42
|
|
40
|
-
relationship_filter =
|
43
|
+
relationship_filter = ->(rel) { rel.weight >= ::Archimate::DataModel::Serving::WEIGHT }
|
41
44
|
|
42
45
|
plateau_today = dr_engine.element_by_name(plateau)
|
43
46
|
today_rels = model.relationships.select do |rel|
|
44
47
|
rel.source.id == plateau_today.id &&
|
45
|
-
%w
|
48
|
+
%w[CompositionRelationship AggregationRelationship].include?(rel.type) &&
|
46
49
|
rel.target.type == "ApplicationComponent"
|
47
50
|
end
|
48
|
-
today_apps = today_rels.map
|
49
|
-
|
50
|
-
|
51
|
-
stop_filter = lambda { |el| el.type == "ApplicationComponent" }
|
51
|
+
today_apps = today_rels.map(&:target)
|
52
|
+
target_filter = ->(el) { today_apps.map(&:id).include?(el.id) }
|
53
|
+
stop_filter = ->(el) { el.type == "ApplicationComponent" }
|
52
54
|
|
53
|
-
concrete_rels = model.relationships.select
|
55
|
+
concrete_rels = model.relationships.select do |rel|
|
54
56
|
rel.type == "ServingRelationship" &&
|
55
57
|
today_apps.include?(rel.source.id) &&
|
56
58
|
today_apps.include?(rel.target.id)
|
57
|
-
|
59
|
+
end
|
58
60
|
|
59
61
|
derived_rels = dr_engine.derived_relations(
|
60
62
|
today_apps,
|
@@ -69,61 +71,52 @@ module Jekyll
|
|
69
71
|
@callees = @all_rels.map(&:target).uniq.sort { |a, b| a.name.to_s <=> b.name.to_s }
|
70
72
|
end
|
71
73
|
|
72
|
-
def matrix_data
|
73
|
-
model = site.data["archimate_model"]
|
74
|
-
dr_engine = ::Archimate::DerivedRelations.new(model)
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
74
|
def render_table
|
79
|
-
<<~
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
75
|
+
<<~TABLE
|
76
|
+
<table class="table table-condensed table-hover table-striped">
|
77
|
+
<caption>#{caption}</caption>
|
78
|
+
<thead>
|
79
|
+
<tr>
|
80
|
+
<th> </th>
|
81
|
+
<th class="success" scope="col" colspan="#{@callers.size}">Callers</th>
|
82
|
+
</tr>
|
83
|
+
<tr>
|
84
|
+
<th class="info" scope="col">Callees</th>
|
85
|
+
#{@callers.map { |ac| "<th class=\"success\" scope=\"col\" style=\"text-transform: capitalize\">#{ac.name}</th>" }.join("\n")}
|
86
|
+
</tr>
|
87
|
+
</thead>
|
88
|
+
<tbody>
|
89
|
+
#{render_rows.strip}
|
90
|
+
</tbody>
|
91
|
+
</table>
|
92
|
+
TABLE
|
97
93
|
end
|
98
94
|
|
99
95
|
def render_rows
|
100
96
|
return "<tr><td>No Items</td></tr>" if @callees.empty?
|
101
97
|
@callees.map do |callee|
|
102
|
-
<<~
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
98
|
+
<<~TABLE_ROW
|
99
|
+
<tr>
|
100
|
+
<th class="info" scope="row">#{callee.name}</th>
|
101
|
+
#{@callers.map { |caller| cell_content(caller, callee) }.join('')}
|
102
|
+
</tr>
|
103
|
+
TABLE_ROW
|
108
104
|
end.join("")
|
109
105
|
end
|
110
106
|
|
111
107
|
def cell_content(caller, callee)
|
112
108
|
rels = @all_rels.select { |rel| rel.source == caller && rel.target == callee }
|
113
|
-
if rels.empty?
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
tooltip = "#{caller.name} → #{}#{callee.name} #{"(derived)" if derived}"
|
119
|
-
cell = <<~END
|
109
|
+
return EMPTY_CELL if rels.empty?
|
110
|
+
derived = rels.all?(&:derived)
|
111
|
+
span_class = derived ? "text-danger" : "text-primary"
|
112
|
+
tooltip = "#{caller.name} → #{callee.name} #{'(derived)' if derived}"
|
113
|
+
<<~TABLE_CELL
|
120
114
|
<td>
|
121
115
|
<a href="#" data-toggle="tooltip" data-placement="top" title="#{tooltip}">
|
122
116
|
<span class="#{span_class}">↵ calls</span>
|
123
117
|
</a>
|
124
118
|
</td>
|
125
|
-
|
126
|
-
end
|
119
|
+
TABLE_CELL
|
127
120
|
end
|
128
121
|
|
129
122
|
def scan_attributes(context)
|
@@ -147,4 +140,3 @@ module Jekyll
|
|
147
140
|
end
|
148
141
|
|
149
142
|
Liquid::Template.register_tag("application_interaction_matrix", Jekyll::Archimate::ApplicationInteractionMatrixTag)
|
150
|
-
|
@@ -1,75 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "archimate"
|
4
|
-
|
5
3
|
module Jekyll
|
6
4
|
module Archimate
|
7
|
-
|
8
|
-
# load an archimate model from either...
|
9
|
-
# 1. Memory
|
10
|
-
# 2. Cached & Marshaled File
|
11
|
-
# 3. Archimate File
|
12
|
-
# Defaulting to the Archimate file if it is newer than either cached version
|
13
|
-
def load_model(file_path)
|
14
|
-
@@cache ||= {}
|
15
|
-
file_path.sub!(%r{^/}, "")
|
16
|
-
mod_time = File.mtime(file_path)
|
17
|
-
|
18
|
-
if @@cache.key?(file_path)
|
19
|
-
model_info = @@cache[file_path]
|
20
|
-
return model_info[:model] if model_info[:cache_time] >= mod_time
|
21
|
-
end
|
5
|
+
ArchimateFileCacheInfo = Struct.new(:archimate_file, :model)
|
22
6
|
|
23
|
-
|
24
|
-
|
25
|
-
begin
|
26
|
-
@@cache[file_path] = {
|
27
|
-
cache_time: File.mtime(cache_file),
|
28
|
-
model: File.open(cache_file, "rb") { |f| Marshal.load(f) }
|
29
|
-
}
|
30
|
-
return @@cache[file_path][:model]
|
31
|
-
rescue ArgumentError
|
32
|
-
puts "Cache file is invalid - removing cache #{cache_file} and loading #{file_path}"
|
33
|
-
FileUtils.rm cache_file
|
34
|
-
end
|
35
|
-
end
|
7
|
+
class ArchimateCache
|
8
|
+
include Singleton
|
36
9
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
cache_time: File.mtime(cache_file),
|
41
|
-
model: model
|
42
|
-
}
|
43
|
-
|
44
|
-
model
|
10
|
+
def initialize
|
11
|
+
@cache = {}
|
12
|
+
@default_archimate_file = nil
|
45
13
|
end
|
46
|
-
module_function :load_model
|
47
14
|
|
48
|
-
def
|
49
|
-
|
15
|
+
def cache_valid?(archimate_file)
|
16
|
+
path = archimate_file.path
|
17
|
+
@cache.key?(path) &&
|
18
|
+
@cache[path].archimate_file.modified_time.to_i == archimate_file.modified_time.to_i
|
50
19
|
end
|
51
20
|
|
52
|
-
|
21
|
+
def model(archimate_file = nil)
|
22
|
+
archimate_file ||= default_archimate_file
|
23
|
+
raise "No ArchiMate file has been detected." unless archimate_file
|
24
|
+
update_cache(archimate_file) unless cache_valid?(archimate_file)
|
25
|
+
@cache[archimate_file.path].model
|
26
|
+
end
|
53
27
|
|
54
|
-
def
|
55
|
-
|
56
|
-
rel = rel_path(file_path)
|
57
|
-
mod_time = File.mtime(rel)
|
58
|
-
!@@cache.key?(rel) ||
|
59
|
-
@@cache[rel][:cache_time] < mod_time
|
28
|
+
def default_archimate_file
|
29
|
+
@default_archimate_file || @cache.keys.first
|
60
30
|
end
|
61
|
-
module_function :cache_stale?
|
62
31
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
npath
|
32
|
+
def default_archimate_file=(archimate_file)
|
33
|
+
unless @cache.key?(archimate_file.path)
|
34
|
+
raise(
|
35
|
+
"Default ArchiMate file does not exist in cache: #{archimate_file.relative_path}"
|
36
|
+
)
|
69
37
|
end
|
70
|
-
|
38
|
+
@default_archimate_file = archimate_file
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_cache(archimate_file)
|
42
|
+
# update the cache
|
43
|
+
Jekyll.logger.info " loading ArchiMate #{archimate_file.relative_path}"
|
44
|
+
load_start_time = Time.new
|
45
|
+
model = ::Archimate.read(archimate_file.path)
|
46
|
+
load_finish_time = Time.new
|
47
|
+
Jekyll.logger.info format(" %.1f seconds", (load_finish_time - load_start_time))
|
48
|
+
@cache[archimate_file.path] = ArchimateFileCacheInfo.new(archimate_file, model)
|
71
49
|
end
|
72
|
-
module_function :marshal_cache_file
|
73
50
|
end
|
74
51
|
end
|
75
52
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Jekyll
|
2
4
|
module Archimate
|
3
5
|
# Insert a diagram from the ArchiMate model.
|
@@ -21,12 +23,12 @@ module Jekyll
|
|
21
23
|
# TODO: make the archimate_dir configurable in _config.yml and as an
|
22
24
|
# optional argument in the tag.
|
23
25
|
archimate_dir = [baseurl, "archimate", "svg"].join("/")
|
24
|
-
<<~
|
26
|
+
<<~FIGURE
|
25
27
|
<figure id="#{@diagram_id}">
|
26
|
-
<a href="#{
|
28
|
+
<a href="#{archimate_dir}/#{@diagram_id}.svg" alt="View Full Screen">
|
27
29
|
<span class="glyphicon glyphicon-fullscreen" style="float:right"></span>
|
28
30
|
</a>
|
29
|
-
<img src="#{
|
31
|
+
<img src="#{archimate_dir}/#{@diagram_id}.svg" class="img-responsive" alt="#{@caption}">
|
30
32
|
<figcaption>
|
31
33
|
#{@caption}
|
32
34
|
<br/>
|
@@ -35,7 +37,7 @@ module Jekyll
|
|
35
37
|
</a>
|
36
38
|
</figcaption>
|
37
39
|
</figure>
|
38
|
-
|
40
|
+
FIGURE
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
class ArchimateGenerator < Jekyll::Generator
|
6
|
+
def generate(site)
|
7
|
+
Jekyll.logger.info "ArchimateGenerator.generate"
|
8
|
+
archimate_files = site.static_files.select { |static_file| static_file.extname =~ /\.(archimate|xml)$/ }
|
9
|
+
archimate_file = preload_cache(archimate_files)
|
10
|
+
return unless needs_generation?
|
11
|
+
ArchimateSvgGenerator.new(site, archimate_file).generate
|
12
|
+
ArchimateIndexGenerator.new(site, archimate_file).generate
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def needs_generation?
|
18
|
+
cache.cache_valid?(cache.default_archimate_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def preload_cache(archimate_files)
|
22
|
+
archimate_files.each { |file| cache.model(file) }
|
23
|
+
cache.default_archimate_file = archimate_files.first # TODO: select file in the `archimate` directory
|
24
|
+
end
|
25
|
+
|
26
|
+
def cache
|
27
|
+
@cache ||= ArchimateCache.instance
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
class ArchimateIndexGenerator
|
6
|
+
attr_reader :site
|
7
|
+
attr_reader :archimate_file
|
8
|
+
|
9
|
+
def initialize(site, archimate_file)
|
10
|
+
@site = site
|
11
|
+
@archimate_file = archimate_file
|
12
|
+
@name = "index.json"
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate
|
16
|
+
ConditionalFile.new(
|
17
|
+
site,
|
18
|
+
File.dirname(archimate_file.relative_path),
|
19
|
+
@name,
|
20
|
+
archimate_file
|
21
|
+
).write(JSON.generate(UnifiedModel.new(model).to_h))
|
22
|
+
end
|
23
|
+
|
24
|
+
def model
|
25
|
+
@model ||= ArchimateCache.instance.model(archimate_file)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
class ArchimateSvgGenerator
|
6
|
+
attr_reader :site
|
7
|
+
attr_reader :archimate_file
|
8
|
+
|
9
|
+
def initialize(site, archimate_file)
|
10
|
+
@site = site
|
11
|
+
@archimate_file = archimate_file
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
create_svg_source_path_if_needed
|
16
|
+
model.diagrams.each do |diagram|
|
17
|
+
generate_diagram(diagram)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def model
|
24
|
+
@model ||= ArchimateCache.instance.model(archimate_file)
|
25
|
+
end
|
26
|
+
|
27
|
+
def svg_source_path
|
28
|
+
@svg_source_path ||= File.join(
|
29
|
+
site.source,
|
30
|
+
File.dirname(archimate_file.relative_path),
|
31
|
+
'svg'
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def svg_relative_path
|
36
|
+
@svg_relative_path ||= File.join(File.dirname(archimate_file.relative_path), "svg")
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_svg_source_path_if_needed
|
40
|
+
Dir.mkdir(svg_source_path) unless Dir.exist?(svg_source_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_diagram(diagram)
|
44
|
+
ConditionalFile.new(
|
45
|
+
site,
|
46
|
+
svg_relative_path,
|
47
|
+
"#{diagram.id}.svg",
|
48
|
+
archimate_file
|
49
|
+
).write(::Archimate::Svg::Diagram.new(diagram).to_svg)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|