archimate 1.1.0

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.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.projectile +18 -0
  4. data/.rubocop.yml +13 -0
  5. data/.travis.yml +4 -0
  6. data/.yardocs +15 -0
  7. data/Gemfile +5 -0
  8. data/Guardfile +27 -0
  9. data/LICENSE +201 -0
  10. data/README.md +94 -0
  11. data/Rakefile +29 -0
  12. data/TODOs.org +286 -0
  13. data/archimate.gemspec +51 -0
  14. data/bin/archimate +17 -0
  15. data/bin/console +13 -0
  16. data/bin/setup +8 -0
  17. data/exe/archidiff +7 -0
  18. data/exe/archidiff-summary +7 -0
  19. data/exe/archimate +7 -0
  20. data/exe/archimerge +7 -0
  21. data/exe/fmtxml +7 -0
  22. data/lib/archimate/cli/archi.rb +189 -0
  23. data/lib/archimate/cli/cleanup.rb +54 -0
  24. data/lib/archimate/cli/conflict_resolver.rb +39 -0
  25. data/lib/archimate/cli/convert.rb +39 -0
  26. data/lib/archimate/cli/diff.rb +31 -0
  27. data/lib/archimate/cli/diff_summary.rb +101 -0
  28. data/lib/archimate/cli/duper.rb +85 -0
  29. data/lib/archimate/cli/lint.rb +16 -0
  30. data/lib/archimate/cli/mapper.rb +82 -0
  31. data/lib/archimate/cli/merge.rb +49 -0
  32. data/lib/archimate/cli/merger.rb +109 -0
  33. data/lib/archimate/cli/stats.rb +42 -0
  34. data/lib/archimate/cli/svger.rb +40 -0
  35. data/lib/archimate/color.rb +53 -0
  36. data/lib/archimate/config.rb +35 -0
  37. data/lib/archimate/data_model/any_attribute.rb +13 -0
  38. data/lib/archimate/data_model/any_element.rb +15 -0
  39. data/lib/archimate/data_model/archimate_node.rb +181 -0
  40. data/lib/archimate/data_model/bounds.rb +72 -0
  41. data/lib/archimate/data_model/color.rb +47 -0
  42. data/lib/archimate/data_model/concept.rb +14 -0
  43. data/lib/archimate/data_model/concern.rb +17 -0
  44. data/lib/archimate/data_model/connection.rb +107 -0
  45. data/lib/archimate/data_model/constants.rb +82 -0
  46. data/lib/archimate/data_model/container.rb +17 -0
  47. data/lib/archimate/data_model/diagram.rb +40 -0
  48. data/lib/archimate/data_model/diffable_array.rb +213 -0
  49. data/lib/archimate/data_model/diffable_primitive.rb +83 -0
  50. data/lib/archimate/data_model/documentation.rb +14 -0
  51. data/lib/archimate/data_model/element.rb +87 -0
  52. data/lib/archimate/data_model/font.rb +54 -0
  53. data/lib/archimate/data_model/label.rb +19 -0
  54. data/lib/archimate/data_model/lang_string.rb +41 -0
  55. data/lib/archimate/data_model/location.rb +31 -0
  56. data/lib/archimate/data_model/metadata.rb +14 -0
  57. data/lib/archimate/data_model/model.rb +217 -0
  58. data/lib/archimate/data_model/modeling_note.rb +13 -0
  59. data/lib/archimate/data_model/named_referenceable.rb +14 -0
  60. data/lib/archimate/data_model/organization.rb +40 -0
  61. data/lib/archimate/data_model/property.rb +25 -0
  62. data/lib/archimate/data_model/property_definition.rb +16 -0
  63. data/lib/archimate/data_model/referenceable.rb +29 -0
  64. data/lib/archimate/data_model/relationship.rb +85 -0
  65. data/lib/archimate/data_model/schema_info.rb +18 -0
  66. data/lib/archimate/data_model/style.rb +32 -0
  67. data/lib/archimate/data_model/view.rb +12 -0
  68. data/lib/archimate/data_model/view_concept.rb +18 -0
  69. data/lib/archimate/data_model/view_node.rb +114 -0
  70. data/lib/archimate/data_model/viewpoint.rb +87 -0
  71. data/lib/archimate/data_model.rb +54 -0
  72. data/lib/archimate/diff/archimate_array_reference.rb +113 -0
  73. data/lib/archimate/diff/archimate_identified_node_reference.rb +41 -0
  74. data/lib/archimate/diff/archimate_node_attribute_reference.rb +70 -0
  75. data/lib/archimate/diff/archimate_node_reference.rb +80 -0
  76. data/lib/archimate/diff/change.rb +49 -0
  77. data/lib/archimate/diff/conflict.rb +31 -0
  78. data/lib/archimate/diff/conflicts/base_conflict.rb +53 -0
  79. data/lib/archimate/diff/conflicts/deleted_items_child_updated_conflict.rb +30 -0
  80. data/lib/archimate/diff/conflicts/deleted_items_referenced_conflict.rb +63 -0
  81. data/lib/archimate/diff/conflicts/path_conflict.rb +51 -0
  82. data/lib/archimate/diff/conflicts.rb +89 -0
  83. data/lib/archimate/diff/delete.rb +41 -0
  84. data/lib/archimate/diff/difference.rb +113 -0
  85. data/lib/archimate/diff/insert.rb +43 -0
  86. data/lib/archimate/diff/merge.rb +70 -0
  87. data/lib/archimate/diff/move.rb +51 -0
  88. data/lib/archimate/diff.rb +17 -0
  89. data/lib/archimate/export/csv_export.rb +32 -0
  90. data/lib/archimate/export/cypher.rb +171 -0
  91. data/lib/archimate/export/graph_ml.rb +131 -0
  92. data/lib/archimate/export/n_quads.rb +142 -0
  93. data/lib/archimate/file_format.rb +30 -0
  94. data/lib/archimate/file_formats/archi_file_format.rb +151 -0
  95. data/lib/archimate/file_formats/archi_file_reader.rb +252 -0
  96. data/lib/archimate/file_formats/archi_file_writer.rb +230 -0
  97. data/lib/archimate/file_formats/archimate_v2.rb +461 -0
  98. data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +35 -0
  99. data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +115 -0
  100. data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +28 -0
  101. data/lib/archimate/file_formats/model_exchange_file/xml_property_defs.rb +27 -0
  102. data/lib/archimate/file_formats/model_exchange_file_reader.rb +237 -0
  103. data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +73 -0
  104. data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +134 -0
  105. data/lib/archimate/file_formats/model_exchange_file_writer.rb +157 -0
  106. data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +143 -0
  107. data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +153 -0
  108. data/lib/archimate/file_formats/writer.rb +56 -0
  109. data/lib/archimate/lint/duplicate_entities.rb +121 -0
  110. data/lib/archimate/lint/linter.rb +146 -0
  111. data/lib/archimate/logging.rb +55 -0
  112. data/lib/archimate/maybe_io.rb +34 -0
  113. data/lib/archimate/progress_indicator.rb +29 -0
  114. data/lib/archimate/svg/archimate.css +232 -0
  115. data/lib/archimate/svg/child.rb +29 -0
  116. data/lib/archimate/svg/connection.rb +184 -0
  117. data/lib/archimate/svg/css_style.rb +31 -0
  118. data/lib/archimate/svg/diagram.rb +87 -0
  119. data/lib/archimate/svg/entity/and_junction.rb +14 -0
  120. data/lib/archimate/svg/entity/application_collaboration.rb +14 -0
  121. data/lib/archimate/svg/entity/application_component.rb +41 -0
  122. data/lib/archimate/svg/entity/application_event.rb +13 -0
  123. data/lib/archimate/svg/entity/application_function.rb +13 -0
  124. data/lib/archimate/svg/entity/application_interaction.rb +13 -0
  125. data/lib/archimate/svg/entity/application_interface.rb +13 -0
  126. data/lib/archimate/svg/entity/application_process.rb +13 -0
  127. data/lib/archimate/svg/entity/application_service.rb +13 -0
  128. data/lib/archimate/svg/entity/artifact.rb +39 -0
  129. data/lib/archimate/svg/entity/assessment.rb +14 -0
  130. data/lib/archimate/svg/entity/base_entity.rb +128 -0
  131. data/lib/archimate/svg/entity/business_actor.rb +14 -0
  132. data/lib/archimate/svg/entity/business_collaboration.rb +14 -0
  133. data/lib/archimate/svg/entity/business_event.rb +10 -0
  134. data/lib/archimate/svg/entity/business_function.rb +13 -0
  135. data/lib/archimate/svg/entity/business_interaction.rb +13 -0
  136. data/lib/archimate/svg/entity/business_interface.rb +13 -0
  137. data/lib/archimate/svg/entity/business_object.rb +13 -0
  138. data/lib/archimate/svg/entity/business_process.rb +13 -0
  139. data/lib/archimate/svg/entity/business_role.rb +14 -0
  140. data/lib/archimate/svg/entity/business_service.rb +13 -0
  141. data/lib/archimate/svg/entity/capability.rb +14 -0
  142. data/lib/archimate/svg/entity/communication_network.rb +14 -0
  143. data/lib/archimate/svg/entity/communication_path.rb +14 -0
  144. data/lib/archimate/svg/entity/constraint.rb +15 -0
  145. data/lib/archimate/svg/entity/contract.rb +13 -0
  146. data/lib/archimate/svg/entity/course_of_action.rb +14 -0
  147. data/lib/archimate/svg/entity/data_entity.rb +29 -0
  148. data/lib/archimate/svg/entity/data_object.rb +13 -0
  149. data/lib/archimate/svg/entity/deliverable.rb +13 -0
  150. data/lib/archimate/svg/entity/device.rb +48 -0
  151. data/lib/archimate/svg/entity/diagram_model_reference.rb +22 -0
  152. data/lib/archimate/svg/entity/diagram_object.rb +30 -0
  153. data/lib/archimate/svg/entity/distribution_network.rb +14 -0
  154. data/lib/archimate/svg/entity/driver.rb +14 -0
  155. data/lib/archimate/svg/entity/equipment.rb +16 -0
  156. data/lib/archimate/svg/entity/event_entity.rb +36 -0
  157. data/lib/archimate/svg/entity/facility.rb +16 -0
  158. data/lib/archimate/svg/entity/function_entity.rb +14 -0
  159. data/lib/archimate/svg/entity/gap.rb +21 -0
  160. data/lib/archimate/svg/entity/goal.rb +14 -0
  161. data/lib/archimate/svg/entity/group.rb +24 -0
  162. data/lib/archimate/svg/entity/implementation_event.rb +13 -0
  163. data/lib/archimate/svg/entity/infrastructure_function.rb +13 -0
  164. data/lib/archimate/svg/entity/infrastructure_interface.rb +13 -0
  165. data/lib/archimate/svg/entity/infrastructure_service.rb +13 -0
  166. data/lib/archimate/svg/entity/interaction_entity.rb +14 -0
  167. data/lib/archimate/svg/entity/interface_entity.rb +35 -0
  168. data/lib/archimate/svg/entity/junction.rb +19 -0
  169. data/lib/archimate/svg/entity/location.rb +14 -0
  170. data/lib/archimate/svg/entity/material.rb +14 -0
  171. data/lib/archimate/svg/entity/meaning.rb +40 -0
  172. data/lib/archimate/svg/entity/motivation_entity.rb +40 -0
  173. data/lib/archimate/svg/entity/network.rb +14 -0
  174. data/lib/archimate/svg/entity/node.rb +33 -0
  175. data/lib/archimate/svg/entity/node_shape.rb +64 -0
  176. data/lib/archimate/svg/entity/note.rb +30 -0
  177. data/lib/archimate/svg/entity/or_junction.rb +14 -0
  178. data/lib/archimate/svg/entity/outcome.rb +15 -0
  179. data/lib/archimate/svg/entity/path.rb +14 -0
  180. data/lib/archimate/svg/entity/plateau.rb +15 -0
  181. data/lib/archimate/svg/entity/principle.rb +15 -0
  182. data/lib/archimate/svg/entity/process_entity.rb +63 -0
  183. data/lib/archimate/svg/entity/product.rb +20 -0
  184. data/lib/archimate/svg/entity/rect.rb +13 -0
  185. data/lib/archimate/svg/entity/rect_entity.rb +25 -0
  186. data/lib/archimate/svg/entity/representation.rb +31 -0
  187. data/lib/archimate/svg/entity/requirement.rb +15 -0
  188. data/lib/archimate/svg/entity/resource.rb +14 -0
  189. data/lib/archimate/svg/entity/rounded_rect_entity.rb +23 -0
  190. data/lib/archimate/svg/entity/service_entity.rb +51 -0
  191. data/lib/archimate/svg/entity/sketch_model_sticky.rb +14 -0
  192. data/lib/archimate/svg/entity/stakeholder.rb +15 -0
  193. data/lib/archimate/svg/entity/system_software.rb +14 -0
  194. data/lib/archimate/svg/entity/technology_collaboration.rb +14 -0
  195. data/lib/archimate/svg/entity/technology_event.rb +13 -0
  196. data/lib/archimate/svg/entity/technology_function.rb +13 -0
  197. data/lib/archimate/svg/entity/technology_interaction.rb +13 -0
  198. data/lib/archimate/svg/entity/technology_interface.rb +13 -0
  199. data/lib/archimate/svg/entity/technology_process.rb +13 -0
  200. data/lib/archimate/svg/entity/technology_service.rb +13 -0
  201. data/lib/archimate/svg/entity/value.rb +27 -0
  202. data/lib/archimate/svg/entity/work_package.rb +14 -0
  203. data/lib/archimate/svg/entity.rb +93 -0
  204. data/lib/archimate/svg/entity_factory.rb +17 -0
  205. data/lib/archimate/svg/extents.rb +27 -0
  206. data/lib/archimate/svg/point.rb +7 -0
  207. data/lib/archimate/svg/svg_template.rb +27 -0
  208. data/lib/archimate/svg/svg_template.svg.erb +169 -0
  209. data/lib/archimate/version.rb +4 -0
  210. data/lib/archimate.rb +114 -0
  211. metadata +623 -0
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ ## This class passes an IO (or a fake IO) to the given block based on passing
3
+ # either a filename to permit ouput into or nil for a fake IO.
4
+ #
5
+ module Archimate
6
+ class MaybeIO
7
+ # Creates a MaybeIO object passing it yielding it to the given block
8
+ #
9
+ # @param filename [String, nil] determines the IO yielded to the given block
10
+ # String: filename to make writable IO for
11
+ # nil: - A fake IO
12
+ # @yieldparam [IO] the given block gets an IO (or fake IO)
13
+ #
14
+ # @example Usage
15
+ # Archimate::MaybeIO.new(myfile) do |io|
16
+ # io.write("Writing away")
17
+ # end
18
+ def initialize(filename)
19
+ if filename.nil?
20
+ yield self
21
+ else
22
+ File.open(filename, "w") do |io|
23
+ yield io
24
+ end
25
+ end
26
+ end
27
+
28
+ # Implementation of the NilIO write method - effectively passes the input
29
+ # String to /dev/null
30
+ #
31
+ # @param _str [String] - unused, no effect
32
+ def write(_str); end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby-progressbar"
4
+
5
+ module Archimate
6
+ class ProgressIndicator
7
+ class FakeProgressBar
8
+ def increment; end
9
+
10
+ def finish; end
11
+ end
12
+
13
+ def initialize(total: 100, title: "ArchiMate!")
14
+ @progress = if Config.instance.interactive
15
+ ProgressBar.create(total: total, title: title, throttle_rate: 0.5)
16
+ else
17
+ FakeProgressBar.new
18
+ end
19
+ end
20
+
21
+ def increment
22
+ @progress.increment
23
+ end
24
+
25
+ def finish
26
+ @progress.finish
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,232 @@
1
+ svg {
2
+ font-family: "Lucida Grande";
3
+ font-size: 11px;
4
+ }
5
+
6
+ p {
7
+ fill: black;
8
+ margin: 0;
9
+ stroke: none;
10
+ }
11
+
12
+ path {
13
+ fill: inherit;
14
+ stroke: inherit;
15
+ stroke-width: 1px;
16
+ }
17
+
18
+ .entity-name {
19
+ text-align: center;
20
+ vertical-align: top;
21
+ }
22
+
23
+ .entity>.properties {
24
+ visibility: hidden;
25
+ }
26
+
27
+ .entity:hover>.properties {
28
+ visibility: visible;
29
+ z-index: 1000;
30
+ }
31
+
32
+ table.properties {
33
+ background-color: whitesmoke;
34
+ border: 2px solid gray;
35
+ }
36
+
37
+ table.properties>caption {
38
+ background-color: gray;
39
+ border: 2px solid gray;
40
+ border-top-left-radius: 8px;
41
+ border-top-right-radius: 8px;
42
+ }
43
+
44
+ .archimate-decoration {
45
+ fill:rgba(0,0,0,0.1);
46
+ stroke: inherit;
47
+ }
48
+
49
+ .archimate-badge {
50
+ fill: none;
51
+ stroke: black;
52
+ stroke-width: 1px;
53
+ }
54
+
55
+ .archimate-badge-spacer {
56
+ float: right;
57
+ height: 20px;
58
+ width: 20px;
59
+ /*border: 1px solid red;*/
60
+ }
61
+
62
+ .archimate-icon {
63
+ fill: none;
64
+ stroke: black;
65
+ }
66
+
67
+ .archimate-default-element {
68
+ fill: #ddd;
69
+ stroke: #999;
70
+ }
71
+
72
+ .archimate-strategy-background {
73
+ fill: #eddfac;
74
+ stroke: #44423b;
75
+ }
76
+
77
+ .archimate-business-background {
78
+ fill: #fffeb9;
79
+ stroke: #b2b181;
80
+ }
81
+
82
+ .archimate-business-decoration {
83
+ fill: rgb(229, 229, 162);
84
+ stroke: rgb(178, 178, 126);
85
+ }
86
+
87
+ .archimate-application-background {
88
+ fill: #ccfdfe;
89
+ stroke: #80b2b2;
90
+ }
91
+
92
+ .archimate-application-decoration {
93
+ fill: rgb(162, 229, 229);
94
+ stroke: rgb(126, 178, 178);
95
+ }
96
+
97
+ .archimate-infrastructure-background {
98
+ fill: #cae6b9;
99
+ stroke: #8ca081;
100
+ }
101
+
102
+ .archimate-infrastructure-decoration {
103
+ fill: #b4cfa4;
104
+ stroke: #9bb28d;
105
+ }
106
+
107
+ .archimate-physical-background {
108
+ fill: #cdfeb2;
109
+ stoke: #313331;
110
+ }
111
+
112
+ .archimate-motivation-background {
113
+ fill: #fecdfe;
114
+ stroke: #b18fb1;
115
+ }
116
+
117
+ .archimate-motivation2-background {
118
+ fill: #cccdfd;
119
+ stroke: #8e8fb1;
120
+ }
121
+
122
+ .archimate-implementation-background {
123
+ fill: #fee0e0;
124
+ stroke: #b19c9c;
125
+ }
126
+
127
+ .archimate-implementation2-background {
128
+ fill: #e0ffe0;
129
+ stroke: #9cb29c;
130
+ }
131
+
132
+ .archimate-implementation2-decoration {
133
+ fill: #c9e5c9;
134
+ stroke: #9cb29c;
135
+ }
136
+
137
+ .archimate-note-background {
138
+ fill: #fff;
139
+ stroke: #b2b2b2;
140
+ }
141
+
142
+ .archimate-group-background {
143
+ fill: #d2d7d7;
144
+ stroke: #939696;
145
+ }
146
+
147
+ .archimate-sticky-background {
148
+ fill: #fffeb9;
149
+ stroke: #b2b181;
150
+ }
151
+
152
+ .archimate-junction-background {
153
+ fill: black;
154
+ stroke: black;
155
+ }
156
+
157
+ .archimate-or-junction-background {
158
+ fill: white;
159
+ stroke: black;
160
+ }
161
+
162
+ .archimate-diagram-model-reference-background {
163
+ fill: #dcebeb;
164
+ stroke: #9aa4a4;
165
+ }
166
+
167
+ .archimate-default-background {
168
+ fill: #ddd;
169
+ stroke: #999;
170
+ }
171
+
172
+ /* Relationships */
173
+ .archimate-relationship {
174
+ fill: none;
175
+ stroke: black;
176
+ stroke-width: 1px;
177
+ }
178
+
179
+ .archimate-relationship-name {
180
+ font-size: 9px;
181
+ }
182
+
183
+ .archimate-assignment-relationship {
184
+ marker-end: url(#archimate-dot-marker);
185
+ marker-start: url(#archimate-dot-marker);
186
+ }
187
+
188
+ .archimate-composition-relationship {
189
+ marker-start: url(#archimate-filled-diamond);
190
+ }
191
+
192
+ .archimate-used-by-relationship {
193
+ marker-end: url(#archimate-used-by-arrow);
194
+ }
195
+
196
+ .archimate-serving-relationship {
197
+ marker-end: url(#archimate-used-by-arrow);
198
+ }
199
+
200
+ .archimate-aggregation-relationship {
201
+ marker-start: url(#archimate-hollow-diamond);
202
+ }
203
+
204
+ .archimate-access-relationship {
205
+ marker-end: url(#archimate-open-arrow);
206
+ stroke-dasharray: 2, 3;
207
+ }
208
+
209
+ .archimate-realisation-relationship {
210
+ marker-end: url(#archimate-hollow-arrow);
211
+ stroke-dasharray: 5, 3;
212
+ }
213
+
214
+ .archimate-specialisation-relationship {
215
+ marker-end: url(#archimate-hollow-arrow);
216
+ }
217
+
218
+ /*.archimate-influence-relationship, .archimate-association-relationship {
219
+ }
220
+ */
221
+ .archimate-triggering-relationship {
222
+ marker-end: url(#archimate-filled-arrow);
223
+ }
224
+
225
+ .archimate-flow-relationship {
226
+ marker-end: url(#archimate-filled-arrow);
227
+ stroke-dasharray: 3, 3;
228
+ }
229
+
230
+ /*.archimate-default-connection {
231
+ }
232
+ */
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ class Child
6
+ attr_reader :todos
7
+ attr_reader :child
8
+
9
+ def initialize(child)
10
+ @child = child
11
+ @todos = Hash.new(0)
12
+ end
13
+
14
+ # The info needed to render is contained in the child with the exception of
15
+ # any offset needed. So this will need to be included in the recursive drawing of children
16
+ def render_elements(svg)
17
+ Nokogiri::XML::Builder.with(svg) do |xml|
18
+ entity = EntityFactory.make_entity(child, nil)
19
+ if entity.nil?
20
+ puts "Unable to make an SVG Entity for Child:\n#{child}"
21
+ else
22
+ entity.to_svg(xml)
23
+ end
24
+ end
25
+ svg
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ class Connection
6
+ attr_reader :connection
7
+ attr_reader :css_style
8
+
9
+ def initialize(connection)
10
+ @connection = connection
11
+ @css_style = CssStyle.new(connection.style)
12
+ end
13
+
14
+ def render(svg)
15
+ Nokogiri::XML::Builder.with(svg) do |xml|
16
+ to_svg(xml)
17
+ end
18
+ svg
19
+ end
20
+
21
+ def to_svg(xml)
22
+ return if connection.source_element.nodes.include?(connection.target_element)
23
+ xml.path(path_attrs) do
24
+ xml.title @connection.description
25
+ end
26
+
27
+ name = connection&.relationship_element&.name&.strip
28
+ return if name.nil? || name.empty?
29
+ xml.text_(
30
+ class: "archimate-relationship-name",
31
+ dy: -2,
32
+ "text-anchor" => "middle",
33
+ style: css_style.text
34
+ ) do
35
+ xml.textPath(startOffset: text_position, "xlink:href" => "##{id}") do
36
+ xml.text name
37
+ end
38
+ end
39
+ end
40
+
41
+ def line_style
42
+ style = connection.style
43
+ return "" if style.nil?
44
+ {
45
+ "stroke": style.line_color&.to_rgba,
46
+ "stroke-width": style.line_width
47
+ }.delete_if { |_key, value| value.nil? }
48
+ .map { |key, value| "#{key}:#{value};" }
49
+ .join("")
50
+ end
51
+
52
+ def text_position
53
+ case connection.style
54
+ when 0
55
+ "10%"
56
+ when 1
57
+ "90%"
58
+ else
59
+ "50%"
60
+ end
61
+ end
62
+
63
+ def path_attrs
64
+ {
65
+ id: id,
66
+ class: path_class,
67
+ d: path_d,
68
+ style: line_style
69
+ }
70
+ end
71
+
72
+ def id
73
+ connection.relationship_element&.id || connection.id
74
+ end
75
+
76
+ # Look at the type (if any of the path and set the class appropriately)
77
+ def path_class
78
+ [
79
+ "archimate",
80
+ css_classify(connection&.relationship_element&.type || "default")
81
+ ].join("-") + " archimate-relationship"
82
+ end
83
+
84
+ # TODO: StringRefinements refinement isn't working in this class, so added this method here. Investigate.
85
+ def css_classify(str)
86
+ str.gsub(/::/, '/')
87
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
88
+ .gsub(/([a-z\d])([A-Z])/, '\1-\2')
89
+ .downcase
90
+ end
91
+
92
+ def ranges_overlap(r1, r2)
93
+ begin_max = [r1, r2].map(&:begin).max
94
+ end_min = [r1, r2].map(&:end).min
95
+ return nil if begin_max > end_min
96
+ (begin_max + end_min) / 2.0
97
+ end
98
+
99
+ # builds the line coordinates for the path
100
+ # rough drawing is the point at center of first element, point of each bendpoint, and center of end element
101
+ # First naive implementation
102
+ # if left/right range of both overlap, use centerpoint of overlap range as x val
103
+ # if top/bottom range of both overlap, use centerpoint of overlap range as y val
104
+ def path_d
105
+ source_bounds = connection.source_element&.absolute_position || DataModel::Bounds.zero
106
+ target_bounds = connection.target_element&.absolute_position || DataModel::Bounds.zero
107
+
108
+ start_point = DataModel::Bounds.new(
109
+ x: source_bounds.left + source_bounds.width / 2.0,
110
+ y: source_bounds.top + source_bounds.height / 2.0,
111
+ width: 0,
112
+ height: 0
113
+ )
114
+ bp_bounds = connection.bendpoints.map do |bp|
115
+ DataModel::Bounds.new(
116
+ x: start_point.x + (bp.x || 0),
117
+ y: start_point.y + (bp.y || 0),
118
+ width: 0,
119
+ height: 0
120
+ )
121
+ end
122
+ bp_bounds = bp_bounds.reject do |bounds|
123
+ bounds.inside?(source_bounds) || bounds.inside?(target_bounds)
124
+ end
125
+
126
+ bounds = [source_bounds].concat(bp_bounds) << target_bounds
127
+
128
+ points = []
129
+ a = bounds.shift
130
+ until bounds.empty?
131
+ b = bounds.shift
132
+ points.concat(calc_points(a, b))
133
+ a = b
134
+ end
135
+ points.uniq!
136
+ [move_to(points.shift)].concat(points.map { |pt| line_to(pt) }).join(" ")
137
+ end
138
+
139
+ # a: Bounds
140
+ # b: Bounds
141
+ def calc_points(a, b)
142
+ ax_range = a.x_range
143
+ bx_range = b.x_range
144
+
145
+ overlap_x_center = ranges_overlap(ax_range, bx_range)
146
+
147
+ if overlap_x_center
148
+ ax = bx = overlap_x_center
149
+ elsif b.is_right_of?(a)
150
+ ax = a.right
151
+ bx = b.left
152
+ else
153
+ ax = a.left
154
+ bx = b.right
155
+ end
156
+
157
+ ay_range = a.y_range
158
+ by_range = b.y_range
159
+
160
+ overlap_y_center = ranges_overlap(ay_range, by_range)
161
+
162
+ if overlap_y_center
163
+ ay = by = overlap_y_center
164
+ elsif b.is_above?(a)
165
+ ay = a.top
166
+ by = b.bottom
167
+ else
168
+ ay = a.bottom
169
+ by = b.top
170
+ end
171
+
172
+ [Point.new(ax, ay), Point.new(bx, by)]
173
+ end
174
+
175
+ def move_to(point)
176
+ "M #{point.x} #{point.y}"
177
+ end
178
+
179
+ def line_to(point)
180
+ "L #{point.x} #{point.y}"
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ class CssStyle
6
+ attr_reader :style
7
+
8
+ def initialize(style)
9
+ @style = style
10
+ end
11
+
12
+ def text
13
+ return "" if style.nil?
14
+ to_css(
15
+ "fill": style.font_color&.to_rgba,
16
+ "color": style.font_color&.to_rgba,
17
+ "font-family": style.font&.name,
18
+ "font-size": style.font&.size,
19
+ "text-align": style.text_align
20
+ )
21
+ end
22
+
23
+ def to_css(style_hash)
24
+ style_hash
25
+ .delete_if { |_key, value| value.nil? }
26
+ .map { |key, value| "#{key}:#{value};" }
27
+ .join("")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "nokogiri"
5
+
6
+ module Archimate
7
+ module Svg
8
+ class Diagram
9
+ attr_reader :diagram
10
+
11
+ def initialize(diagram)
12
+ @diagram = diagram
13
+ @svg_template = Nokogiri::XML(SvgTemplate.new.to_s).freeze
14
+ end
15
+
16
+ def to_svg
17
+ svg_doc = @svg_template.clone
18
+ set_title(svg_doc)
19
+ top_group = svg_doc.at_css("#archimate-diagram")
20
+ render_connections(
21
+ render_elements(top_group)
22
+ )
23
+ update_viewbox(svg_doc.at_css("svg"))
24
+ format_node(top_group)
25
+ svg_doc.to_xml(encoding: 'UTF-8', indent: 2)
26
+ end
27
+
28
+ def set_title(svg)
29
+ svg.at_css("title").content = diagram.name || "untitled"
30
+ svg.at_css("desc").content = diagram.documentation.first&.text || ""
31
+ end
32
+
33
+ # Scan the SVG and figure out min & max
34
+ def update_viewbox(svg)
35
+ extents = calculate_max_extents(svg).expand(10)
36
+ svg.set_attribute(:width, extents.width)
37
+ svg.set_attribute(:height, extents.height)
38
+ svg.set_attribute("viewBox", "#{extents.min_x} #{extents.min_y} #{extents.width} #{extents.height}")
39
+ svg
40
+ end
41
+
42
+ def format_node(node, depth = 4)
43
+ node.children.each do |child|
44
+ child.add_previous_sibling("\n#{ ' ' * depth }")
45
+ format_node(child, depth + 2)
46
+ child.add_next_sibling("\n#{ ' ' * (depth - 2) }") if node.children.last == child
47
+ end
48
+ end
49
+
50
+ def calculate_max_extents(doc)
51
+ node_vals =
52
+ doc
53
+ .xpath("//*[@x or @y]")
54
+ .map { |node| %w[x y width height].map { |attr| node.attr(attr).to_i } }
55
+ doc.css(".archimate-relationship")
56
+ .each { |path|
57
+ path.attr("d").split(" ").each_slice(3) do |point|
58
+ node_vals << [point[1].to_i, point[2].to_i, 0, 0]
59
+ end
60
+ }
61
+ Extents.new(
62
+ node_vals.map(&:first).min,
63
+ node_vals.map { |v| v[0] + v[2] }.max,
64
+ node_vals.map { |v| v[1] }.min,
65
+ node_vals.map { |v| v[1] + v[3] }.max
66
+ )
67
+ end
68
+
69
+ def attr_to_i(node, attr)
70
+ ival = node.attr(attr)
71
+ ival.to_i unless ival.nil? || ival.strip.empty?
72
+ end
73
+
74
+ def render_elements(svg_node)
75
+ diagram
76
+ .nodes
77
+ .reduce(svg_node) { |svg, child| Child.new(child).render_elements(svg) }
78
+ end
79
+
80
+ def render_connections(svg_node)
81
+ diagram
82
+ .connections
83
+ .reduce(svg_node) { |svg, connection| Connection.new(connection).render(svg) }
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ class AndJunction < RectEntity
7
+ def initialize(child, bounds_offset)
8
+ super
9
+ @background_class = "archimate-junction-background"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ class ApplicationCollaboration < RectEntity
7
+ def initialize(child, bounds_offset)
8
+ super
9
+ @badge = "#archimate-collaboration-badge"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ # TODO: support alternate appearance
7
+ class ApplicationComponent < BaseEntity
8
+ def initialize(child, bounds_offset)
9
+ super
10
+ end
11
+
12
+ def entity_shape(xml, bounds)
13
+ component_path(xml, bounds)
14
+ end
15
+
16
+ def component_path(xml, bounds)
17
+ main_box_x = bounds.left + 21.0 / 2
18
+ main_box_width = bounds.width - 21 / 2
19
+ set_text_bounds(bounds, main_box_x)
20
+ xml.rect(x: main_box_x, y: bounds.top, width: main_box_width, height: bounds.height, class: background_class, style: shape_style)
21
+ component_decoration(xml, bounds.left, bounds.top + 10)
22
+ component_decoration(xml, bounds.left, bounds.top + 30)
23
+ end
24
+
25
+ def component_decoration(xml, left, top)
26
+ xml.rect(x: left, y: top, width: "21", height: "13", class: background_class, style: shape_style)
27
+ xml.rect(x: left, y: top, width: "21", height: "13", class: "archimate-decoration")
28
+ end
29
+
30
+ def set_text_bounds(bounds, main_box_x)
31
+ @text_bounds = DataModel::Bounds.new(
32
+ x: main_box_x + 21 / 2,
33
+ y: bounds.top + 1,
34
+ width: bounds.width - 22,
35
+ height: bounds.height - 2
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module Svg
5
+ module Entity
6
+ class ApplicationEvent < EventEntity
7
+ def initialize(child, bounds_offset)
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end