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,237 @@
1
+ # frozen_string_literal: true
2
+ require "nokogiri"
3
+
4
+ module Archimate
5
+ module FileFormats
6
+ # This class implements common methods for the ArchiMate Model Exchange Format
7
+ class ModelExchangeFileReader
8
+ # Parses a Nokogiri document into an Archimate::Model
9
+ def parse(doc)
10
+ return unless doc
11
+ @property_defs = []
12
+ @viewpoints = []
13
+ parse_model(doc.root)
14
+ end
15
+
16
+ def parse_model(root)
17
+ @property_defs = parse_property_defs(root)
18
+ @viewpoints = parse_viewpoints(root)
19
+ DataModel::Model.new(
20
+ index_hash: {},
21
+ id: identifier_to_id(root["identifier"]),
22
+ name: ModelExchangeFile::XmlLangString.parse(root.at_css(">name")),
23
+ version: root["version"],
24
+ metadata: ModelExchangeFile::XmlMetadata.parse(root.at_css(">metadata")),
25
+ documentation: parse_documentation(root),
26
+ properties: parse_properties(root),
27
+ elements: parse_elements(root),
28
+ relationships: parse_relationships(root),
29
+ organizations: parse_organizations(root.css(organizations_root_selector)),
30
+ diagrams: parse_diagrams(root),
31
+ viewpoints: @viewpoints,
32
+ property_definitions: @property_defs,
33
+ schema_locations: root.attr("xsi:schemaLocation").split(" "),
34
+ namespaces: root.namespaces,
35
+ archimate_version: parse_archimate_version(root)
36
+ )
37
+ end
38
+
39
+ def parse_viewpoints(_node)
40
+ return []
41
+ end
42
+
43
+ def parse_documentation(node, element_name = "documentation")
44
+ node.css(">#{element_name}").map do |doc|
45
+ DataModel::Documentation.new(text: doc.content, lang: doc["xml:lang"])
46
+ end
47
+ end
48
+
49
+ def parse_properties(node)
50
+ node.css("> properties > property").map do |i|
51
+ parse_property(i)
52
+ end
53
+ end
54
+
55
+ def parse_property(node)
56
+ property_def = @property_defs.find { |prop_def| prop_def.id == node.attr(property_def_attr_name) }
57
+ DataModel::Property.new(
58
+ property_definition: property_def,
59
+ values: [ModelExchangeFile::XmlLangString.parse(node.at_css("value"))].compact
60
+ )
61
+ end
62
+
63
+ def parse_property_defs(node)
64
+ @property_defs = node.css(property_defs_selector).map do |i|
65
+ DataModel::PropertyDefinition.new(
66
+ id: i["identifier"],
67
+ name: property_def_name(i),
68
+ documentation: parse_documentation(i),
69
+ value_type: i["type"]
70
+ )
71
+ end
72
+ end
73
+
74
+ def parse_elements(model)
75
+ model.css(">elements>element").map do |i|
76
+ DataModel::Element.new(
77
+ id: identifier_to_id(i["identifier"]),
78
+ name: parse_element_name(i),
79
+ type: i["xsi:type"],
80
+ documentation: parse_documentation(i),
81
+ properties: parse_properties(i)
82
+ )
83
+ end
84
+ end
85
+
86
+ def parse_organizations(nodes)
87
+ nodes.map do |i|
88
+ child_items = i.css(">item")
89
+ ref_items = child_items.select { |ci| ci.has_attribute?(identifier_ref_name) }
90
+ DataModel::Organization.new(
91
+ id: i["identifier"], # TODO: model exchange doesn't assign ids to organization items
92
+ name: ModelExchangeFile::XmlLangString.parse(i.at_css(">label")),
93
+ documentation: parse_documentation(i),
94
+ items: ref_items.map { |ri| identifier_to_id(ri[identifier_ref_name]) },
95
+ organizations: parse_organizations(child_items.reject { |ci| ci.has_attribute?(identifier_ref_name) })
96
+ )
97
+ end
98
+ end
99
+
100
+ def parse_relationships(model)
101
+ model.css(">relationships>relationship").map do |i|
102
+ DataModel::Relationship.new(
103
+ id: identifier_to_id(i["identifier"]),
104
+ type: i.attr("xsi:type"),
105
+ source: identifier_to_id(i.attr("source")),
106
+ target: identifier_to_id(i.attr("target")),
107
+ name: parse_element_name(i),
108
+ access_type: i["accessType"],
109
+ documentation: parse_documentation(i),
110
+ properties: parse_properties(i)
111
+ )
112
+ end
113
+ end
114
+
115
+ def parse_diagrams(model)
116
+ model.css(diagrams_path).map do |i|
117
+ nodes = parse_nodes(i)
118
+ connections = parse_connections(i)
119
+ child_id_hash = nodes.each_with_object({}) { |i2, a| a.merge!(i2.child_id_hash) }
120
+ connections.each do |c|
121
+ child_id_hash[c.source].connections << c
122
+ end
123
+ DataModel::Diagram.new(
124
+ id: identifier_to_id(i["identifier"]),
125
+ name: parse_element_name(i),
126
+ viewpoint_type: i["viewpoint"],
127
+ viewpoint: nil, # TODO: support this for ArchiMate v3
128
+ documentation: parse_documentation(i),
129
+ properties: parse_properties(i),
130
+ nodes: nodes,
131
+ connections: connections,
132
+ connection_router_type: i["connectionRouterType"],
133
+ type: i.attr("xsi:type"),
134
+ background: i.attr("background")
135
+ )
136
+ end
137
+ end
138
+
139
+ def parse_nodes(node)
140
+ node.css("> node").map do |i|
141
+ DataModel::ViewNode.new(
142
+ id: identifier_to_id(i["identifier"]),
143
+ type: i.attr(view_node_type_attr),
144
+ model: nil,
145
+ name: ModelExchangeFile::XmlLangString.parse(i.at_css(">label")),
146
+ target_connections: [], # TODO: needed? "targetConnections",
147
+ archimate_element: identifier_to_id(i[view_node_element_ref]),
148
+ bounds: parse_bounds(i),
149
+ nodes: parse_nodes(i),
150
+ connections: parse_connections(i),
151
+ documentation: parse_documentation(i),
152
+ properties: parse_properties(i),
153
+ style: parse_style(i),
154
+ content: i.at_css("> content")&.text,
155
+ child_type: nil
156
+ )
157
+ end
158
+ end
159
+
160
+ def parse_style(node)
161
+ style = node.at_css(">style")
162
+ return nil unless style
163
+ DataModel::Style.new(
164
+ text_alignment: style["textAlignment"],
165
+ fill_color: parse_color(style, "fillColor"),
166
+ line_color: parse_color(style, "lineColor"),
167
+ font_color: parse_color(style.at_css(">font"), "color"),
168
+ font: parse_font(style),
169
+ line_width: style["lineWidth"],
170
+ text_position: style.at_css("textPosition")
171
+ )
172
+ end
173
+
174
+ def parse_font(node)
175
+ font_node = node.at_css(">font")
176
+ return unless font_node && font_node["name"] && font_node["size"]
177
+ DataModel::Font.new(
178
+ name: font_node["name"],
179
+ size: font_node["size"],
180
+ style: style_to_int(font_node["style"]),
181
+ font_data: nil
182
+ )
183
+ end
184
+
185
+ def parse_color(node, el_name)
186
+ return unless node
187
+ color_node = node.at_css(el_name)
188
+ return unless color_node
189
+ DataModel::Color.new(
190
+ r: color_node["r"]&.to_i,
191
+ g: color_node["g"]&.to_i,
192
+ b: color_node["b"]&.to_i,
193
+ a: color_node["a"]&.to_i
194
+ )
195
+ end
196
+
197
+ def parse_bounds(node)
198
+ DataModel::Bounds.new(
199
+ x: node.attr("x"),
200
+ y: node.attr("y"),
201
+ width: node.attr("w"),
202
+ height: node.attr("h")
203
+ )
204
+ end
205
+
206
+ def parse_connections(node)
207
+ node.css("> connection").map do |i|
208
+ DataModel::Connection.new(
209
+ id: identifier_to_id(i["identifier"]),
210
+ type: i.attr(view_node_type_attr),
211
+ source: identifier_to_id(i["source"]),
212
+ target: identifier_to_id(i["target"]),
213
+ relationship: identifier_to_id(i[connection_relationship_ref]),
214
+ name: i.at_css("label")&.content,
215
+ style: parse_style(i),
216
+ bendpoints: parse_bendpoints(i),
217
+ documentation: parse_documentation(i),
218
+ properties: parse_properties(i)
219
+ )
220
+ end
221
+ end
222
+
223
+ def parse_bendpoints(node)
224
+ node.css("bendpoint").map do |i|
225
+ DataModel::Location.new(
226
+ x: i.attr("x"), y: i.attr("y")
227
+ )
228
+ end
229
+ end
230
+
231
+ def identifier_to_id(str)
232
+ # str&.sub(/^id-/, "")
233
+ str
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ require "nokogiri"
3
+
4
+ module Archimate
5
+ module FileFormats
6
+ # This class implements a file reader for ArchiMate 2.1 Model Exchange Format
7
+ class ModelExchangeFileReader21 < ModelExchangeFileReader
8
+ def parse_archimate_version(root)
9
+ case root.namespace.href
10
+ when "http://www.opengroup.org/xsd/archimate"
11
+ :archimate_2_1
12
+ else
13
+ raise "Unexpected namespace: #{root.namespace.href}"
14
+ end
15
+ end
16
+
17
+ def organizations_root_selector
18
+ ">organization>item"
19
+ end
20
+
21
+ def property_defs_selector
22
+ ">propertydefs>propertydef"
23
+ end
24
+
25
+ def property_def_attr_name
26
+ "identifierref"
27
+ end
28
+
29
+ def property_def_name(node)
30
+ node["name"]
31
+ end
32
+
33
+ def parse_element_name(el)
34
+ ModelExchangeFile::XmlLangString.parse(el.at_css(">label"))
35
+ end
36
+
37
+ def identifier_ref_name
38
+ "identifierref"
39
+ end
40
+
41
+ def diagrams_path
42
+ ">views>view"
43
+ end
44
+
45
+ def view_node_element_ref
46
+ "elementref"
47
+ end
48
+
49
+ def view_node_type_attr
50
+ "type"
51
+ end
52
+
53
+ def connection_relationship_ref
54
+ "relationshipref"
55
+ end
56
+
57
+ def style_to_int(str)
58
+ case str
59
+ when nil
60
+ 0
61
+ when "italic"
62
+ 1
63
+ when "bold"
64
+ 2
65
+ when "bold|italic"
66
+ 3
67
+ else
68
+ raise "Broken for value: #{str}"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+ require "nokogiri"
3
+
4
+ module Archimate
5
+ module FileFormats
6
+ class ModelExchangeFileReader30 < ModelExchangeFileReader
7
+ def parse_archimate_version(root)
8
+ case root.namespace.href
9
+ when "http://www.opengroup.org/xsd/archimate/3.0/"
10
+ :archimate_3_0
11
+ else
12
+ raise "Unexpected namespace version: #{root.namespace.href}"
13
+ end
14
+ end
15
+
16
+ def organizations_root_selector
17
+ ">organizations"
18
+ end
19
+
20
+ def property_defs_selector
21
+ ">propertyDefinitions>propertyDefinition"
22
+ end
23
+
24
+ def property_def_attr_name
25
+ "propertyDefinitionRef"
26
+ end
27
+
28
+ def property_def_name(node)
29
+ ModelExchangeFile::XmlLangString.parse(node.at_css("name"))
30
+ end
31
+
32
+ def parse_element_name(el)
33
+ ModelExchangeFile::XmlLangString.parse(el.at_css(">name"))
34
+ end
35
+
36
+ def identifier_ref_name
37
+ "identifierRef"
38
+ end
39
+
40
+ def diagrams_path
41
+ ">views>diagrams>view"
42
+ end
43
+
44
+ def view_node_element_ref
45
+ "elementRef"
46
+ end
47
+
48
+ def view_node_type_attr
49
+ "xsi:type"
50
+ end
51
+
52
+ def connection_relationship_ref
53
+ "relationshipRef"
54
+ end
55
+
56
+ def style_to_int(str)
57
+ case str
58
+ when nil
59
+ 0
60
+ when "italic"
61
+ 1
62
+ when "bold"
63
+ 2
64
+ when "bold italic"
65
+ 3
66
+ else
67
+ raise "Broken for value: #{str}"
68
+ end
69
+ end
70
+
71
+ # <xs:simpleType name="ViewpointPurposeEnum">
72
+ # <xs:restriction base="xs:NMTOKEN">
73
+ # <xs:enumeration value="Designing" />
74
+ # <xs:enumeration value="Deciding" />
75
+ # <xs:enumeration value="Informing" />
76
+ # </xs:restriction>
77
+ # </xs:simpleType>
78
+
79
+ # <xs:simpleType name="ViewpointPurposeType">
80
+ # <xs:list itemType="ViewpointPurposeEnum" />
81
+ # </xs:simpleType>
82
+
83
+ # <xs:simpleType name="ViewpointContentEnum">
84
+ # <xs:restriction base="xs:NMTOKEN">
85
+ # <xs:enumeration value="Details" />
86
+ # <xs:enumeration value="Coherence" />
87
+ # <xs:enumeration value="Overview" />
88
+ # </xs:restriction>
89
+ # </xs:simpleType>
90
+
91
+ # <xs:simpleType name="ViewpointContentType">
92
+ # <xs:list itemType="ViewpointContentEnum" />
93
+ # </xs:simpleType>
94
+
95
+ # <xs:complexType name="ViewpointType">
96
+ # <xs:complexContent>
97
+ # <xs:extension base="NamedReferenceableType">
98
+ # <xs:sequence>
99
+ # <xs:group ref="PropertiesGroup" />
100
+ # <xs:element name="concern" type="ConcernType" minOccurs="0" maxOccurs="unbounded" />
101
+ # <xs:element name="viewpointPurpose" type="ViewpointPurposeType" minOccurs="0" maxOccurs="1" />
102
+ # <xs:element name="viewpointContent" type="ViewpointContentType" minOccurs="0" maxOccurs="1" />
103
+ # <xs:element name="allowedElementType" type="AllowedElementTypeType" minOccurs="0" maxOccurs="unbounded" />
104
+ # <xs:element name="allowedRelationshipType" type="AllowedRelationshipTypeType" minOccurs="0" maxOccurs="unbounded" />
105
+ # <xs:element name="modelingNote" type="ModelingNoteType" minOccurs="0" maxOccurs="unbounded" />
106
+ # </xs:sequence>
107
+ # </xs:extension>
108
+ # </xs:complexContent>
109
+ # </xs:complexType>
110
+ def parse_viewpoints(model)
111
+ []
112
+ # model.css("views > viewpoints").map do |i|
113
+ # attribute :concern, ConcernList
114
+ # attribute :viewpointPurpose, ViewpointPurpose.optional
115
+ # attribute :viewpointContent, ViewpointContent.optional
116
+ # attribute :allowedElementTypes, AllowedElementTypes
117
+ # attribute :allowedRelationshipTypes, AllowedRelationshipTypes
118
+ # attribute :modelingNotes, Strict::Array.member(ModelingNote).default([])
119
+ # DataModel::Viewpoint.new(
120
+ # id: identifier_to_id(i["identifier"]),
121
+ # name: parse_element_name(i),
122
+ # documentation: parse_documentation(i),
123
+ # properties: parse_properties(i),
124
+ # nodes: nodes,
125
+ # connections: connections,
126
+ # connection_router_type: i["connectionRouterType"],
127
+ # type: i.attr("xsi:type"),
128
+ # background: i.attr("background")
129
+ # )
130
+ # end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+ require "nokogiri"
3
+
4
+ module Archimate
5
+ module FileFormats
6
+ class ModelExchangeFileWriter < Writer
7
+ attr_reader :model
8
+
9
+ def initialize(model)
10
+ super
11
+ end
12
+
13
+ def write(output_io)
14
+ builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
15
+ serialize_model(xml)
16
+ end
17
+ output_io.write(builder.to_xml)
18
+ end
19
+
20
+ def serialize_elements(xml)
21
+ xml.elements { serialize(xml, model.elements) } unless model.elements.empty?
22
+ end
23
+
24
+ def serialize_element(xml, element)
25
+ return if element.type == "SketchModel" # TODO: print a warning that data is lost
26
+ xml.element(identifier: identifier(element['id']),
27
+ "xsi:type" => meff_type(element.type)) do
28
+ elementbase(xml, element)
29
+ end
30
+ end
31
+
32
+ def elementbase(xml, element)
33
+ serialize_label(xml, element.name)
34
+ serialize(xml, element.documentation)
35
+ serialize_properties(xml, element)
36
+ end
37
+
38
+ def serialize_label(xml, str)
39
+ return if str.nil? || str.strip.empty?
40
+ name_attrs = str.lang && !str.lang.empty? ? {"xml:lang" => str.lang} : {}
41
+ xml.label(name_attrs) { xml.text text_proc(str) }
42
+ end
43
+
44
+ def serialize_relationships(xml)
45
+ return if model.relationships.empty?
46
+ xml.relationships { serialize(xml, model.relationships) }
47
+ end
48
+
49
+ def relationship_attributes(relationship)
50
+ {
51
+ identifier: identifier(relationship.id),
52
+ source: identifier(relationship.source),
53
+ target: identifier(relationship.target),
54
+ "xsi:type" => meff_type(relationship.type)
55
+ }
56
+ end
57
+
58
+ def serialize_relationship(xml, relationship)
59
+ xml.relationship(
60
+ relationship_attributes(relationship)
61
+ ) do
62
+ elementbase(xml, relationship)
63
+ end
64
+ end
65
+
66
+ def serialize_organization_root(xml, organizations)
67
+ return unless organizations && organizations.size > 0
68
+ xml.organization do
69
+ serialize(xml, organizations)
70
+ end
71
+ end
72
+
73
+ def serialize_organization(xml, organization)
74
+ return if organization.items.empty? && organization.documentation.empty? && organization.organizations.empty?
75
+ item_attrs = organization.id.nil? || organization.id.empty? ? {} : {identifier: organization.id}
76
+ xml.item(item_attrs) do
77
+ serialize_organization_body(xml, organization)
78
+ end
79
+ end
80
+
81
+ def serialize_organization_body(xml, organization)
82
+ return if organization.items.empty? && organization.documentation.empty? && organization.organizations.empty?
83
+ str = organization.name
84
+ label_attrs = organization.name&.lang && !organization.name.lang.empty? ? {"xml:lang" => organization.name.lang} : {}
85
+ xml.label(label_attrs) { xml.text text_proc(str) } unless str.nil? || str.strip.empty?
86
+ serialize(xml, organization.documentation)
87
+ serialize(xml, organization.organizations)
88
+ organization.items.each { |i| serialize_item(xml, i) }
89
+ end
90
+
91
+ def serialize_properties(xml, element)
92
+ return if element.properties.empty?
93
+ xml.properties do
94
+ serialize(xml, element.properties)
95
+ end
96
+ end
97
+
98
+ def serialize_style(xml, style)
99
+ return unless style
100
+ xml.style(
101
+ remove_nil_values(
102
+ lineWidth: style.line_width
103
+ )
104
+ ) do
105
+ serialize_color(xml, style.fill_color, :fillColor)
106
+ serialize_color(xml, style.line_color, :lineColor)
107
+ serialize_font(xml, style)
108
+ # TODO: complete this
109
+ end
110
+ end
111
+
112
+ def serialize_font(xml, style)
113
+ return unless style && (style.font || style.font_color)
114
+ xml.font(
115
+ remove_nil_values(
116
+ name: style.font&.name,
117
+ size: style.font&.size&.round,
118
+ style: font_style_string(style.font)
119
+ )
120
+ ) { serialize_color(xml, style&.font_color, :color) }
121
+ end
122
+
123
+ def serialize_color(xml, color, sym)
124
+ return if color.nil?
125
+ h = {
126
+ r: color.r,
127
+ g: color.g,
128
+ b: color.b,
129
+ a: color.a
130
+ }
131
+ h.delete(:a) if color.a.nil? || color.a == 100
132
+ xml.send(sym, h)
133
+ end
134
+
135
+ def serialize_location(xml, location)
136
+ xml.bendpoint(x: location.x.round, y: location.y.round)
137
+ end
138
+
139
+ # # Processes text for text elements
140
+ def text_proc(str)
141
+ str.strip.tr("\r", "\n")
142
+ end
143
+
144
+ # TODO: this should replace namespaces as appropriate for the desired export version
145
+ def model_namespaces
146
+ model.namespaces
147
+ end
148
+
149
+ # TODO: Archi uses hex numbers for ids which may not be valid for
150
+ # identifer. If we are converting from Archi, decorate the IDs here.
151
+ def identifier(str)
152
+ return "id-#{str}" if str =~ /^\d/
153
+ str
154
+ end
155
+ end
156
+ end
157
+ end