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
@@ -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.
|
@@ -9,6 +11,7 @@ module Jekyll
|
|
9
11
|
attr_reader :caption
|
10
12
|
attr_reader :element_types
|
11
13
|
attr_reader :markup
|
14
|
+
attr_reader :model
|
12
15
|
|
13
16
|
def initialize(tag_name, markup, tokens)
|
14
17
|
@markup = markup
|
@@ -20,12 +23,13 @@ module Jekyll
|
|
20
23
|
|
21
24
|
def render(context)
|
22
25
|
@context = context
|
26
|
+
@model = ArchimateCache.instance.model
|
23
27
|
scan_attributes(context)
|
24
28
|
render_table
|
25
29
|
end
|
26
30
|
|
27
31
|
def render_table
|
28
|
-
<<-
|
32
|
+
<<-TABLE.gsub(/^ {6}/, '')
|
29
33
|
<table>
|
30
34
|
<caption>#{caption}</caption>
|
31
35
|
<thead>
|
@@ -36,26 +40,33 @@ module Jekyll
|
|
36
40
|
</tr>
|
37
41
|
</thead>
|
38
42
|
<tbody>
|
39
|
-
#{render_rows(elements
|
43
|
+
#{render_rows(elements)}
|
40
44
|
</tbody>
|
41
45
|
</table>
|
42
|
-
|
46
|
+
TABLE
|
43
47
|
end
|
44
48
|
|
45
|
-
def elements
|
46
|
-
@element_types
|
49
|
+
def elements
|
50
|
+
@element_types
|
51
|
+
.map do |element_type|
|
52
|
+
model
|
53
|
+
.elements
|
54
|
+
.select { |el| el.type == element_type }
|
55
|
+
end
|
56
|
+
.flatten
|
57
|
+
.compact
|
47
58
|
end
|
48
59
|
|
49
60
|
def render_rows(elements)
|
50
61
|
return "<tr><td colspan=\"3\">No Items</td></tr>" if elements.empty?
|
51
62
|
elements.map do |element|
|
52
|
-
<<-
|
63
|
+
<<-TABLE_ROW
|
53
64
|
<tr>
|
54
|
-
<td><span class="badge badge-primary">#{element
|
55
|
-
<td>#{@converter.convert(element
|
56
|
-
<td>#{render_properties(element
|
65
|
+
<td><span class="badge badge-primary">#{element.type}</span> #{element.name}</td>
|
66
|
+
<td>#{@converter.convert(element.documentation.to_s).gsub(%r{</?p[^>]*>}, '').chomp if element.documentation}</td>
|
67
|
+
<td>#{render_properties(element.properties)}</td>
|
57
68
|
</tr>
|
58
|
-
|
69
|
+
TABLE_ROW
|
59
70
|
end.join("")
|
60
71
|
end
|
61
72
|
|
@@ -78,7 +89,8 @@ module Jekyll
|
|
78
89
|
end
|
79
90
|
|
80
91
|
caption = attributes['caption']&.gsub!(/\A"|"\Z/, '')
|
81
|
-
@caption = @converter.convert(caption).gsub(/<\/?p[^>]*>/, '').chomp if @caption
|
92
|
+
# @caption = @converter.convert(caption).gsub(/<\/?p[^>]*>/, '').chomp if @caption
|
93
|
+
@caption = @converter.convert(caption).gsub(%r{</?p[^>]*>}, '').chomp if @caption
|
82
94
|
element_type = attributes['type']
|
83
95
|
element_type = element_type.gsub!(/\A"|"\Z/, '') if element_type
|
84
96
|
@element_types = element_type.split(",").map(&:strip)
|
@@ -98,4 +110,3 @@ module Jekyll
|
|
98
110
|
end
|
99
111
|
|
100
112
|
Liquid::Template.register_tag("catalog", Jekyll::Archimate::CatalogTag)
|
101
|
-
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Persists an ArchiMate diagram to a file
|
6
|
+
class ConditionalFile
|
7
|
+
attr_reader :site
|
8
|
+
attr_reader :dir
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :filename
|
11
|
+
attr_reader :archimate_file
|
12
|
+
attr_reader :relative_path
|
13
|
+
|
14
|
+
def initialize(site, dir, name, archimate_file)
|
15
|
+
@site = site
|
16
|
+
@dir = dir
|
17
|
+
@name = name
|
18
|
+
@archimate_file = archimate_file
|
19
|
+
@filename = File.join(site.source, dir, name)
|
20
|
+
@relative_path = File.join(dir, name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def needs_write?(content)
|
24
|
+
return true unless File.exist?(filename)
|
25
|
+
return true if archimate_file.modified_time.to_i > File.mtime(filename).to_i
|
26
|
+
File.read(filename) != content
|
27
|
+
end
|
28
|
+
|
29
|
+
# Writes content to filename if
|
30
|
+
# * File doesn't exit
|
31
|
+
# * Or File content is different than content
|
32
|
+
def write(content)
|
33
|
+
return unless needs_write?(content)
|
34
|
+
Jekyll.logger.info "Rendering #{relative_path}"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def write_file(content)
|
40
|
+
File.open(filename, "w") { |file| file.write(content) }
|
41
|
+
site.static_files << Jekyll::StaticFile.new(site, site.source, dir, name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Represents an ArchiMate Diagram
|
6
|
+
class DiagramEntity < EntityBase
|
7
|
+
def attr_hash
|
8
|
+
super.merge(
|
9
|
+
type: "Diagram",
|
10
|
+
path: "svg/#{entity.id}.svg",
|
11
|
+
viewpoint: entity.viewpoint,
|
12
|
+
elements: entity.elements.map(&:id),
|
13
|
+
relationships: entity.relationships.map(&:id),
|
14
|
+
views: []
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Represents an ArchiMate Element
|
6
|
+
class ElementEntity < EntityBase
|
7
|
+
def attr_hash
|
8
|
+
super.merge(
|
9
|
+
type: "Element",
|
10
|
+
element_type: entity.type,
|
11
|
+
relationships: element_relationships,
|
12
|
+
views: model.diagrams.select { |dia| dia.element_ids.include?(entity.id) }.map(&:id)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def element_relationships
|
19
|
+
model.relationships.select do |rel|
|
20
|
+
rel.source&.id == entity.id || rel.target&.id == entity.id
|
21
|
+
end
|
22
|
+
.map(&:id)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Base class for ArchiMate Entities: Model, Diagram, Element, Relationship
|
6
|
+
class EntityBase
|
7
|
+
attr_reader :entity
|
8
|
+
attr_reader :model
|
9
|
+
|
10
|
+
def initialize(entity, model: nil)
|
11
|
+
@entity = entity
|
12
|
+
@model = model
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_h
|
16
|
+
Archimate.hash_purge(attr_hash)
|
17
|
+
end
|
18
|
+
|
19
|
+
def attr_hash
|
20
|
+
{
|
21
|
+
id: entity.id,
|
22
|
+
name: entity.name,
|
23
|
+
documentation: entity.documentation&.to_h,
|
24
|
+
properties: entity.properties.map(&:to_h)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Represents an ArchiMate Organizing Folder
|
6
|
+
class Folder
|
7
|
+
attr_reader :folder
|
8
|
+
|
9
|
+
def initialize(folder)
|
10
|
+
@folder = folder
|
11
|
+
end
|
12
|
+
|
13
|
+
# This item check is necessary because some models seem to contain
|
14
|
+
# an item that is a string rather than an element of some sort.
|
15
|
+
def items
|
16
|
+
folder.items.map { |item| item.is_a?(String) ? item : item.id }
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
Archimate.hash_purge(
|
21
|
+
id: folder.id,
|
22
|
+
name: folder.name.to_s,
|
23
|
+
folders: folder.organizations.map { |child| Folder.new(child).to_h },
|
24
|
+
diagrams: items
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Writes any object that can be hashified (with to_h) to a JSON file
|
6
|
+
class JsonFile
|
7
|
+
def initialize(filename)
|
8
|
+
@filename = filename
|
9
|
+
end
|
10
|
+
|
11
|
+
def write(obj)
|
12
|
+
File.open(@filename, "wb") do |file|
|
13
|
+
file.write(JSON.generate(obj.to_h))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
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.
|
@@ -5,12 +7,13 @@ module Jekyll
|
|
5
7
|
# {% matrix plateau:"Today" | caption: "Today's Application Interaction" }
|
6
8
|
#
|
7
9
|
class MatrixTag < Liquid::Tag
|
10
|
+
EMPTY_CELL = "<td></td>"
|
11
|
+
|
8
12
|
attr_reader :context
|
9
13
|
attr_reader :caption
|
10
14
|
attr_reader :element_types
|
11
15
|
attr_reader :markup
|
12
16
|
|
13
|
-
|
14
17
|
def initialize(tag_name, markup, tokens)
|
15
18
|
@markup = markup
|
16
19
|
@context = nil
|
@@ -26,104 +29,52 @@ module Jekyll
|
|
26
29
|
render_table
|
27
30
|
end
|
28
31
|
|
29
|
-
# Here I want all of the Serving relationships between 2 app components
|
30
|
-
# included or derived.
|
31
|
-
#
|
32
|
-
# attrs:
|
33
|
-
# source_selector: Element selector for source elements
|
34
|
-
# target_selector: Element selector for target elements
|
35
|
-
# relationship_selector
|
36
|
-
def application_interaction
|
37
|
-
model = site.data["archimate_model"]
|
38
|
-
dr_engine = ::Archimate::DerivedRelations.new(model)
|
39
|
-
|
40
|
-
relationship_filter = lambda { |rel| rel.weight >= ::Archimate::DataModel::Serving::WEIGHT }
|
41
|
-
|
42
|
-
plateau_today = dr_engine.element_by_name("Today")
|
43
|
-
today_rels = model.relationships.select do |rel|
|
44
|
-
rel.source.id == plateau_today.id &&
|
45
|
-
%w{CompositionRelationship AggregationRelationship}.include?(rel.type) &&
|
46
|
-
rel.target.type == "ApplicationComponent"
|
47
|
-
end
|
48
|
-
today_apps = today_rels.map { |rel| rel.target }
|
49
|
-
source_filter = lambda { |el| }
|
50
|
-
target_filter = lambda { |el| today_apps.map(&:id).include?(el.id) }
|
51
|
-
stop_filter = lambda { |el| el.type == "ApplicationComponent" }
|
52
|
-
|
53
|
-
concrete_rels = model.relationships.select { |rel|
|
54
|
-
rel.type == "ServingRelationship" &&
|
55
|
-
today_apps.include?(rel.source.id) &&
|
56
|
-
today_apps.include?(rel.target.id)
|
57
|
-
}
|
58
|
-
|
59
|
-
derived_rels = dr_engine.derived_relations(
|
60
|
-
today_apps,
|
61
|
-
relationship_filter,
|
62
|
-
target_filter,
|
63
|
-
stop_filter
|
64
|
-
)
|
65
|
-
|
66
|
-
@all_rels = [concrete_rels, derived_rels].flatten
|
67
|
-
|
68
|
-
@callers = @all_rels.map(&:source).uniq.sort { |a, b| a.name.to_s <=> b.name.to_s }
|
69
|
-
@callees = @all_rels.map(&:target).uniq.sort { |a, b| a.name.to_s <=> b.name.to_s }
|
70
|
-
end
|
71
|
-
|
72
|
-
def matrix_data
|
73
|
-
model = site.data["archimate_model"]
|
74
|
-
dr_engine = ::Archimate::DerivedRelations.new(model)
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
32
|
def render_table
|
79
|
-
<<~
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
33
|
+
<<~TABLE
|
34
|
+
<table class="table table-condensed table-hover table-striped">
|
35
|
+
<caption>#{caption}</caption>
|
36
|
+
<thead>
|
37
|
+
<tr>
|
38
|
+
<th> </th>
|
39
|
+
<th class="success" scope="col" colspan="#{@callers.size}">Callers</th>
|
40
|
+
</tr>
|
41
|
+
<tr>
|
42
|
+
<th class="info" scope="col">Callees</th>
|
43
|
+
#{@callers.map { |ac| "<th class=\"success\" scope=\"col\" style=\"text-transform: capitalize\">#{ac.name}</th>" }.join("\n")}
|
44
|
+
</tr>
|
45
|
+
</thead>
|
46
|
+
<tbody>
|
47
|
+
#{render_rows.strip}
|
48
|
+
</tbody>
|
49
|
+
</table>
|
50
|
+
TABLE
|
97
51
|
end
|
98
52
|
|
99
53
|
def render_rows
|
100
54
|
return "<tr><td>No Items</td></tr>" if @callees.empty?
|
101
55
|
@callees.map do |callee|
|
102
|
-
<<~
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
56
|
+
<<~TABLE_ROW
|
57
|
+
<tr>
|
58
|
+
<th class="info" scope="row">#{callee.name}</th>
|
59
|
+
#{@callers.map { |caller| cell_content(caller, callee) }.join('')}
|
60
|
+
</tr>
|
61
|
+
TABLE_ROW
|
108
62
|
end.join("")
|
109
63
|
end
|
110
64
|
|
111
65
|
def cell_content(caller, callee)
|
112
66
|
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
|
67
|
+
return EMPTY_CELL if rels.empty?
|
68
|
+
derived = rels.all?(&:derived)
|
69
|
+
span_class = derived ? "text-danger" : "text-primary"
|
70
|
+
tooltip = "#{caller.name} → #{callee.name} #{'(derived)' if derived}"
|
71
|
+
<<~TABLE_CELL
|
120
72
|
<td>
|
121
73
|
<a href="#" data-toggle="tooltip" data-placement="top" title="#{tooltip}">
|
122
74
|
<span class="#{span_class}">↵ calls</span>
|
123
75
|
</a>
|
124
76
|
</td>
|
125
|
-
|
126
|
-
end
|
77
|
+
TABLE_CELL
|
127
78
|
end
|
128
79
|
|
129
80
|
def scan_attributes(context)
|
@@ -157,4 +108,3 @@ module Jekyll
|
|
157
108
|
end
|
158
109
|
|
159
110
|
Liquid::Template.register_tag("matrix", Jekyll::Archimate::MatrixTag)
|
160
|
-
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Archimate
|
5
|
+
# Represents an ArchiMate Relationship
|
6
|
+
class RelationshipEntity < EntityBase
|
7
|
+
def attr_hash
|
8
|
+
super.merge(
|
9
|
+
type: "Relationship",
|
10
|
+
relationship_type: entity.type,
|
11
|
+
source: entity.source&.id,
|
12
|
+
target: entity.target&.id,
|
13
|
+
views: relationship_views
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def relationship_views
|
20
|
+
model.diagrams.select { |dia| dia.relationship_ids.include?(entity.id) }.map(&:id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|