jekyll-archimate 0.2.2 → 0.2.3
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/.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
|