archimate 1.2.1 → 2.0.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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +47 -0
  3. data/TODOs.org +219 -0
  4. data/archimate.gemspec +2 -1
  5. data/exe/archidiff +7 -0
  6. data/exe/archidiff-summary +7 -0
  7. data/exe/archimerge +7 -0
  8. data/exe/fmtxml +7 -0
  9. data/lib/archimate.rb +10 -21
  10. data/lib/archimate/cli/archi.rb +2 -1
  11. data/lib/archimate/cli/cleanup.rb +8 -9
  12. data/lib/archimate/cli/convert.rb +3 -1
  13. data/lib/archimate/cli/mapper.rb +1 -1
  14. data/lib/archimate/cli/stats.rb +1 -1
  15. data/lib/archimate/config.rb +4 -1
  16. data/lib/archimate/data_model.rb +11 -24
  17. data/lib/archimate/data_model/any_attribute.rb +18 -5
  18. data/lib/archimate/data_model/any_element.rb +30 -7
  19. data/lib/archimate/data_model/bounds.rb +34 -7
  20. data/lib/archimate/data_model/color.rb +32 -7
  21. data/lib/archimate/data_model/comparison.rb +87 -0
  22. data/lib/archimate/data_model/concern.rb +20 -7
  23. data/lib/archimate/data_model/connection.rb +71 -51
  24. data/lib/archimate/data_model/connector_type.rb +23 -0
  25. data/lib/archimate/data_model/diagram.rb +72 -10
  26. data/lib/archimate/data_model/diagram_type.rb +17 -0
  27. data/lib/archimate/data_model/differentiable.rb +142 -0
  28. data/lib/archimate/data_model/element.rb +39 -45
  29. data/lib/archimate/data_model/element_type.rb +89 -0
  30. data/lib/archimate/data_model/font.rb +30 -12
  31. data/lib/archimate/data_model/lang_string.rb +89 -16
  32. data/lib/archimate/data_model/layer.rb +55 -0
  33. data/lib/archimate/data_model/layers.rb +62 -0
  34. data/lib/archimate/data_model/location.rb +27 -11
  35. data/lib/archimate/data_model/metadata.rb +10 -3
  36. data/lib/archimate/data_model/model.rb +188 -121
  37. data/lib/archimate/data_model/modeling_note.rb +14 -3
  38. data/lib/archimate/data_model/organization.rb +44 -13
  39. data/lib/archimate/data_model/{documentation.rb → preserved_lang_string.rb} +1 -5
  40. data/lib/archimate/data_model/property.rb +17 -11
  41. data/lib/archimate/data_model/property_definition.rb +34 -4
  42. data/lib/archimate/data_model/referenceable.rb +0 -9
  43. data/lib/archimate/data_model/referenceable_collection.rb +201 -0
  44. data/lib/archimate/data_model/relationship.rb +52 -33
  45. data/lib/archimate/data_model/relationship_type.rb +43 -0
  46. data/lib/archimate/data_model/schema_info.rb +17 -6
  47. data/lib/archimate/data_model/style.rb +41 -11
  48. data/lib/archimate/data_model/view_node.rb +153 -59
  49. data/lib/archimate/data_model/viewpoint.rb +56 -80
  50. data/lib/archimate/data_model/viewpoint_type.rb +429 -0
  51. data/lib/archimate/export/csv_export.rb +2 -2
  52. data/lib/archimate/export/cypher.rb +2 -2
  53. data/lib/archimate/export/graph_ml.rb +7 -5
  54. data/lib/archimate/export/jsonl.rb +166 -0
  55. data/lib/archimate/export/n_quads.rb +8 -5
  56. data/lib/archimate/file_format.rb +4 -5
  57. data/lib/archimate/file_formats/archi_file_reader.rb +7 -240
  58. data/lib/archimate/file_formats/archi_file_writer.rb +16 -188
  59. data/lib/archimate/file_formats/model_exchange_file_reader.rb +7 -225
  60. data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +22 -114
  61. data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +22 -122
  62. data/lib/archimate/file_formats/sax.rb +55 -0
  63. data/lib/archimate/file_formats/sax/any_element.rb +64 -0
  64. data/lib/archimate/file_formats/sax/archi/archi_handler_factory.rb +48 -0
  65. data/lib/archimate/file_formats/sax/archi/bounds.rb +25 -0
  66. data/lib/archimate/file_formats/sax/archi/connection.rb +47 -0
  67. data/lib/archimate/file_formats/sax/archi/content.rb +28 -0
  68. data/lib/archimate/file_formats/sax/archi/diagram.rb +66 -0
  69. data/lib/archimate/file_formats/sax/archi/element.rb +36 -0
  70. data/lib/archimate/file_formats/sax/archi/location.rb +25 -0
  71. data/lib/archimate/file_formats/sax/archi/model.rb +109 -0
  72. data/lib/archimate/file_formats/sax/archi/organization.rb +60 -0
  73. data/lib/archimate/file_formats/sax/archi/property.rb +54 -0
  74. data/lib/archimate/file_formats/sax/archi/relationship.rb +50 -0
  75. data/lib/archimate/file_formats/sax/archi/style.rb +35 -0
  76. data/lib/archimate/file_formats/sax/archi/view_node.rb +76 -0
  77. data/lib/archimate/file_formats/sax/capture_content.rb +20 -0
  78. data/lib/archimate/file_formats/sax/capture_documentation.rb +19 -0
  79. data/lib/archimate/file_formats/sax/capture_properties.rb +20 -0
  80. data/lib/archimate/file_formats/sax/content_element.rb +19 -0
  81. data/lib/archimate/file_formats/sax/document.rb +80 -0
  82. data/lib/archimate/file_formats/sax/handler.rb +54 -0
  83. data/lib/archimate/file_formats/sax/lang_string.rb +28 -0
  84. data/lib/archimate/file_formats/sax/model_exchange_file/color.rb +36 -0
  85. data/lib/archimate/file_formats/sax/model_exchange_file/connection.rb +67 -0
  86. data/lib/archimate/file_formats/sax/model_exchange_file/diagram.rb +60 -0
  87. data/lib/archimate/file_formats/sax/model_exchange_file/element.rb +43 -0
  88. data/lib/archimate/file_formats/sax/model_exchange_file/font.rb +44 -0
  89. data/lib/archimate/file_formats/sax/model_exchange_file/item.rb +64 -0
  90. data/lib/archimate/file_formats/sax/model_exchange_file/location.rb +23 -0
  91. data/lib/archimate/file_formats/sax/model_exchange_file/metadata.rb +66 -0
  92. data/lib/archimate/file_formats/sax/model_exchange_file/model.rb +124 -0
  93. data/lib/archimate/file_formats/sax/model_exchange_file/model_exchange_handler_factory.rb +53 -0
  94. data/lib/archimate/file_formats/sax/model_exchange_file/property.rb +32 -0
  95. data/lib/archimate/file_formats/sax/model_exchange_file/property_definition.rb +36 -0
  96. data/lib/archimate/file_formats/sax/model_exchange_file/relationship.rb +49 -0
  97. data/lib/archimate/file_formats/sax/model_exchange_file/schema_info.rb +47 -0
  98. data/lib/archimate/file_formats/sax/model_exchange_file/style.rb +66 -0
  99. data/lib/archimate/file_formats/sax/model_exchange_file/view_node.rb +86 -0
  100. data/lib/archimate/file_formats/sax/no_op.rb +17 -0
  101. data/lib/archimate/file_formats/sax/preserved_lang_string.rb +28 -0
  102. data/lib/archimate/file_formats/serializer.rb +57 -0
  103. data/lib/archimate/file_formats/serializer/archi/bounds.rb +23 -0
  104. data/lib/archimate/file_formats/serializer/archi/connection.rb +33 -0
  105. data/lib/archimate/file_formats/serializer/archi/diagram.rb +28 -0
  106. data/lib/archimate/file_formats/serializer/archi/documentation.rb +16 -0
  107. data/lib/archimate/file_formats/serializer/archi/element.rb +24 -0
  108. data/lib/archimate/file_formats/serializer/archi/location.rb +26 -0
  109. data/lib/archimate/file_formats/serializer/archi/model.rb +25 -0
  110. data/lib/archimate/file_formats/serializer/archi/organization.rb +21 -0
  111. data/lib/archimate/file_formats/serializer/archi/property.rb +15 -0
  112. data/lib/archimate/file_formats/serializer/archi/relationship.rb +36 -0
  113. data/lib/archimate/file_formats/serializer/archi/view_node.rb +52 -0
  114. data/lib/archimate/file_formats/serializer/archi/viewpoint_type.rb +45 -0
  115. data/lib/archimate/file_formats/serializer/model_exchange_file/element.rb +25 -0
  116. data/lib/archimate/file_formats/serializer/model_exchange_file/location.rb +15 -0
  117. data/lib/archimate/file_formats/serializer/model_exchange_file/model_exchange_file_writer.rb +32 -0
  118. data/lib/archimate/file_formats/serializer/model_exchange_file/organization.rb +23 -0
  119. data/lib/archimate/file_formats/serializer/model_exchange_file/properties.rb +15 -0
  120. data/lib/archimate/file_formats/serializer/model_exchange_file/relationship.rb +19 -0
  121. data/lib/archimate/file_formats/serializer/model_exchange_file/style.rb +48 -0
  122. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/connection.rb +25 -0
  123. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/diagram.rb +27 -0
  124. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/item.rb +17 -0
  125. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/label.rb +17 -0
  126. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/model.rb +36 -0
  127. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/organization_body.rb +25 -0
  128. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/property.rb +19 -0
  129. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/view_node.rb +44 -0
  130. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/connection.rb +26 -0
  131. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/diagram.rb +27 -0
  132. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/item.rb +17 -0
  133. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/label.rb +17 -0
  134. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/model.rb +41 -0
  135. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/organization_body.rb +25 -0
  136. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/property.rb +19 -0
  137. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/property_definitions.rb +34 -0
  138. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/view_node.rb +45 -0
  139. data/lib/archimate/file_formats/serializer/named_collection.rb +21 -0
  140. data/lib/archimate/file_formats/serializer/writer.rb +56 -0
  141. data/lib/archimate/file_formats/serializer/xml_lang_string.rb +30 -0
  142. data/lib/archimate/file_formats/serializer/xml_metadata.rb +64 -0
  143. data/lib/archimate/file_formats/{model_exchange_file → serializer}/xml_property_defs.rb +2 -2
  144. data/lib/archimate/lint/duplicate_entities.rb +3 -3
  145. data/lib/archimate/lint/linter.rb +24 -29
  146. data/lib/archimate/svg/connection.rb +13 -103
  147. data/lib/archimate/svg/diagram.rb +1 -1
  148. data/lib/archimate/svg/entity/base_entity.rb +12 -8
  149. data/lib/archimate/svg/entity/data_entity.rb +2 -2
  150. data/lib/archimate/svg/entity/diagram_model_reference.rb +1 -1
  151. data/lib/archimate/svg/entity/event_entity.rb +2 -2
  152. data/lib/archimate/svg/entity/gap.rb +1 -1
  153. data/lib/archimate/svg/entity/group.rb +1 -1
  154. data/lib/archimate/svg/entity/motivation_entity.rb +1 -1
  155. data/lib/archimate/svg/entity/node.rb +1 -1
  156. data/lib/archimate/svg/entity/rect_entity.rb +1 -1
  157. data/lib/archimate/svg/entity/rounded_rect_entity.rb +1 -1
  158. data/lib/archimate/svg/entity/service_entity.rb +2 -2
  159. data/lib/archimate/svg/entity/value.rb +2 -2
  160. data/lib/archimate/svg/path.rb +153 -0
  161. data/lib/archimate/svg/point.rb +8 -1
  162. data/lib/archimate/version.rb +1 -1
  163. metadata +118 -36
  164. data/lib/archimate/data_model/archimate_node.rb +0 -181
  165. data/lib/archimate/data_model/concept.rb +0 -14
  166. data/lib/archimate/data_model/constants.rb +0 -82
  167. data/lib/archimate/data_model/container.rb +0 -17
  168. data/lib/archimate/data_model/diffable_array.rb +0 -213
  169. data/lib/archimate/data_model/diffable_primitive.rb +0 -83
  170. data/lib/archimate/data_model/label.rb +0 -19
  171. data/lib/archimate/data_model/named_referenceable.rb +0 -14
  172. data/lib/archimate/data_model/view.rb +0 -12
  173. data/lib/archimate/data_model/view_concept.rb +0 -18
  174. data/lib/archimate/file_formats/archi_file_format.rb +0 -151
  175. data/lib/archimate/file_formats/archimate_v2.rb +0 -461
  176. data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +0 -35
  177. data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +0 -115
  178. data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +0 -28
  179. data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +0 -73
  180. data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +0 -134
  181. data/lib/archimate/file_formats/model_exchange_file_writer.rb +0 -157
  182. data/lib/archimate/file_formats/writer.rb +0 -56
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ module ModelExchangeFile
7
+ module V30
8
+ module OrganizationBody
9
+ def serialize_organization_body(xml, organization)
10
+ if organization.items.empty? &&
11
+ (!organization.documentation || organization.documentation.empty?) &&
12
+ organization.organizations.empty?
13
+ return
14
+ end
15
+ serialize_label(xml, organization.name, :label)
16
+ serialize(xml, organization.documentation)
17
+ serialize(xml, organization.organizations)
18
+ organization.items.each { |i| serialize_item(xml, i) }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ module ModelExchangeFile
7
+ module V30
8
+ module Property
9
+ def serialize_property(xml, property)
10
+ xml.property("propertyDefinitionRef" => property.property_definition.id) do
11
+ XmlLangString.new(property.value, :value).serialize(xml)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ module ModelExchangeFile
7
+ module V30
8
+ # Property Definitions as defined in ArchiMate 3.0 Model Exchange XSDs
9
+ class PropertyDefinitions
10
+ def initialize(property_defs)
11
+ @property_definitions = property_defs
12
+ end
13
+
14
+ def serialize(xml)
15
+ return if @property_definitions.empty?
16
+ xml.propertyDefinitions do
17
+ @property_definitions.each { |property_def| serialize_property_definition(xml, property_def) }
18
+ end
19
+ end
20
+
21
+ def serialize_property_definition(xml, property_def)
22
+ xml.propertyDefinition(
23
+ "identifier" => property_def.id,
24
+ "type" => property_def.type
25
+ ) do
26
+ XmlLangString.new(property_def.name, :name).serialize(xml)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ module ModelExchangeFile
7
+ module V30
8
+ module ViewNode
9
+ def serialize_view_node(xml, view_node, x_offset = 0, y_offset = 0)
10
+ attrs = view_node_attrs(view_node, x_offset, y_offset)
11
+ xml.node(attrs) do
12
+ serialize_label(xml, view_node.name, :label)
13
+ serialize(xml, view_node.style) if view_node.style
14
+ view_node.nodes.each do |c|
15
+ serialize_view_node(xml, c) # , view_node_attrs[:x].to_f, view_node_attrs[:y].to_f)
16
+ end
17
+ end
18
+ end
19
+
20
+ def view_node_attrs(view_node, x_offset = 0, y_offset = 0)
21
+ attrs = {
22
+ identifier: identifier(view_node.id),
23
+ elementRef: nil,
24
+ "xsi:type" => view_node.type,
25
+ "x" => view_node.bounds ? (view_node.bounds&.x + x_offset).round : nil,
26
+ "y" => view_node.bounds ? (view_node.bounds&.y + y_offset).round : nil,
27
+ "w" => view_node.bounds&.width&.round,
28
+ "h" => view_node.bounds&.height&.round
29
+ }
30
+ if view_node.element
31
+ attrs[:elementRef] = identifier(view_node.element.id)
32
+ elsif view_node.view_refs
33
+ # Since it doesn't seem to be forbidden, we just assume we can use
34
+ # the elementref for views in views
35
+ attrs[:elementRef] = view_node.view_refs
36
+ attrs[:type] = "model"
37
+ end
38
+ remove_nil_values(attrs)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ class NamedCollection
7
+ def initialize(name, collection)
8
+ @name = name
9
+ @collection = collection
10
+ end
11
+
12
+ def serialize(xml, &block)
13
+ return unless @collection&.size&.positive?
14
+ xml.send(@name) do
15
+ block.call(xml, @collection)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ class Writer
7
+ attr_reader :model
8
+
9
+ def self.write(model, output_io)
10
+ writer = new(model)
11
+ writer.write(output_io)
12
+ end
13
+
14
+ def initialize(model)
15
+ @model = model
16
+ end
17
+
18
+ def serialize(xml, collection)
19
+ Array(collection).each do |item|
20
+ case item
21
+ when DataModel::Element
22
+ serialize_element(xml, item)
23
+ when DataModel::Relationship
24
+ serialize_relationship(xml, item)
25
+ when DataModel::Organization
26
+ serialize_organization(xml, item)
27
+ when DataModel::Diagram
28
+ serialize_diagram(xml, item)
29
+ when DataModel::Location
30
+ serialize_location(xml, item)
31
+ when DataModel::Bounds
32
+ serialize_bounds(xml, item)
33
+ when DataModel::ViewNode
34
+ serialize_view_node(xml, item)
35
+ when DataModel::PreservedLangString
36
+ Serializer::XmlLangString.new(item, :documentation).serialize(xml)
37
+ when DataModel::Property
38
+ serialize_property(xml, item)
39
+ when DataModel::Connection
40
+ serialize_connection(xml, item)
41
+ when DataModel::Style
42
+ serialize_style(xml, item)
43
+ else
44
+ raise TypeError, "Unexpected item type #{item.class}"
45
+ end
46
+ end
47
+ end
48
+
49
+ def remove_nil_values(h)
50
+ h.delete_if { |_k, v| v.nil? }
51
+ h
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ class XmlLangString
7
+ def initialize(lang_str, tag_name)
8
+ @tag_name = tag_name
9
+ @lang_str = lang_str
10
+ end
11
+
12
+ def serialize(xml)
13
+ return unless @lang_str && !@lang_str.empty?
14
+
15
+ @lang_str.langs.each do |lang|
16
+ attrs = lang && !lang.empty? ? { "xml:lang" => lang } : {}
17
+ xml.send(@tag_name, attrs) { xml.text text_proc(@lang_str.by_lang(lang)) }
18
+ end
19
+ end
20
+
21
+ # Processes text for text elements
22
+ private
23
+
24
+ def text_proc(str)
25
+ str.strip.tr("\r", "\n")
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Archimate
4
+ module FileFormats
5
+ module Serializer
6
+ class XmlMetadata
7
+ def initialize(metadata)
8
+ @metadata = metadata
9
+ end
10
+
11
+ def serialize(xml)
12
+ return unless @metadata && !@metadata.schema_infos.empty?
13
+ xml.metadata do
14
+ if @metadata.schema_infos.size == 1
15
+ serialize_schema_info_body(xml, @metadata.schema_infos.first)
16
+ else
17
+ @metadata.schema_infos.each do |schema_info|
18
+ serialize_schema_info(xml, schema_info)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def serialize_schema_info(xml, schema_info)
27
+ xml.schemaInfo do
28
+ serialize_schema_info_body(xml, schema_info)
29
+ end
30
+ end
31
+
32
+ def serialize_schema_info_body(xml, schema_info)
33
+ xml.schema { xml.text schema_info.schema } if schema_info.schema
34
+ xml.schemaversion { xml.text schema_info.schemaversion } if schema_info.schemaversion
35
+ schema_info.elements.each do |el|
36
+ serialize_any_element(xml, el)
37
+ end
38
+ end
39
+
40
+ def serialize_any_element(xml, el)
41
+ xml_prefix(xml, el).send(el.element.to_sym, serialize_any_attributes(el.attributes)) do
42
+ xml.text(el.content) if el.content&.size&.positive?
43
+ el.children.each { |child| serialize_any_element(xml, child) }
44
+ end
45
+ end
46
+
47
+ def xml_prefix(xml, el)
48
+ if el.prefix && !el.prefix.empty?
49
+ xml[el.prefix]
50
+ else
51
+ xml
52
+ end
53
+ end
54
+
55
+ def serialize_any_attributes(attrs)
56
+ attrs.each_with_object({}) do |attr, hash|
57
+ key = attr.prefix&.size&.positive? ? [attr.prefix, attr.attribute].join(":") : attr.attribute
58
+ hash[key] = attr.value
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Archimate
4
4
  module FileFormats
5
- module ModelExchangeFile
5
+ module Serializer
6
6
  # Property Definitions as defined in ArchiMate 2.1 Model Exchange XSDs
7
7
  class XmlPropertyDefs
8
8
  def initialize(property_defs)
@@ -16,7 +16,7 @@ module Archimate
16
16
  xml.propertydef(
17
17
  "identifier" => property_def.id,
18
18
  "name" => property_def.name,
19
- "type" => property_def.value_type
19
+ "type" => property_def.type
20
20
  )
21
21
  end
22
22
  end
@@ -86,8 +86,8 @@ module Archimate
86
86
  end
87
87
 
88
88
  def entity_hash_name(entity)
89
- layer = DataModel::Constants::ELEMENT_LAYER.fetch(entity.type, nil)
90
- layer_sort_order = layer ? DataModel::Constants::LAYER_ELEMENTS.keys.index(layer) : 9
89
+ layer = DataModel::Layers.for_element(entity.type)
90
+ layer_sort_order = layer ? DataModel::Layers.find_index(layer) : 9
91
91
  [
92
92
  entity.class.name, # Taking advantage of Element being before Relationship
93
93
  layer_sort_order.to_s,
@@ -104,7 +104,7 @@ module Archimate
104
104
  # 4. names differ only in punctuation
105
105
  # 5. names differ only by stop-words (list of words such as "the", "api", etc.)
106
106
  def simplify(entity)
107
- name = entity.name&.dup || ""
107
+ name = entity.name&.dup.to_s || ""
108
108
  name.sub!("(copy)", "") # (copy) is a special case inserted by the Archi tool
109
109
  name.downcase!
110
110
  name.gsub!(/[[:punct:]]/, "") unless entity.is_a?(DataModel::Relationship)
@@ -13,8 +13,6 @@ module Archimate
13
13
  # [x] warn about names with (copy)
14
14
  # [x] blank element names
15
15
  class Linter
16
- include FileFormats::ArchimateV2
17
-
18
16
  attr_reader :model
19
17
 
20
18
  def initialize(model)
@@ -50,18 +48,18 @@ module Archimate
50
48
  def report_subsection(issues, output_io)
51
49
  issues.each do |sub_issues|
52
50
  output_io.puts(sub_issues)
53
- output_io.puts("Sub Total: #{sub_issues.size}")
51
+ output_io.puts("Sub Total: #{sub_issues.size}") unless sub_issues.empty?
54
52
  end
55
53
  end
56
54
 
57
55
  def unused_elements
58
- referenced_elements = diagram_referenced_ids
59
- model.elements.reject { |el| referenced_elements.include?(el.id) }
56
+ referenced_elements = model.diagrams.inject([]) { |memo, dia| memo.concat(dia.elements) }.uniq
57
+ model.elements.reject { |el| referenced_elements.include?(el) }
60
58
  end
61
59
 
62
60
  def unused_relationships
63
- referenced_ids = diagram_referenced_ids
64
- model.relationships.reject { |el| referenced_ids.include?(el.id) }
61
+ referenced_relationships = model.diagrams.inject([]) { |memo, dia| memo.concat(dia.relationships) }.uniq
62
+ model.relationships.reject { |el| referenced_relationships.include?(el) }
65
63
  end
66
64
 
67
65
  def empty_views
@@ -88,15 +86,11 @@ module Archimate
88
86
  end
89
87
  end
90
88
 
91
- def diagram_referenced_ids
92
- @ref_ids ||= model.diagrams.inject([]) { |memo, dia| memo.concat(dia.referenced_identified_nodes) }.uniq
93
- end
94
-
95
89
  def invalid_for_viewpoint
96
90
  model.diagrams.each_with_object([]) do |diagram, errors|
97
91
  next if diagram.total_viewpoint?
98
- valid_entity_types = VIEWPOINTS[diagram.viewpoint][:entities]
99
- valid_relation_types = VIEWPOINTS[diagram.viewpoint][:relations]
92
+ valid_entity_types = DataModel::ViewpointType::VIEWPOINTS[diagram.viewpoint_type][:entities]
93
+ valid_relation_types = DataModel::ViewpointType::VIEWPOINTS[diagram.viewpoint_type][:relations]
100
94
  invalid_elements = diagram.all_nodes.reject do |child|
101
95
  child.element&.type.nil? || valid_entity_types.include?(child.element&.type)
102
96
  end
@@ -113,21 +107,22 @@ module Archimate
113
107
  end
114
108
  end
115
109
 
116
- # Nesting is valid for relations:
117
- # * CompositionRelationship
118
- # * AggregationRelationship
119
- # * AssignmentRelationship
120
110
  def nesting_without_relation
121
- model.find_by_class(DataModel::ViewNode).each_with_object([]) do |parent, errors|
122
- missing_relations = parent.nodes.reject do |child|
123
- model.relationships.any? do |rel|
124
- parent.archimate_element.nil? ||
125
- child.archimate_element.nil? ||
126
- (rel.source == parent.archimate_element && rel.target == child.archimate_element)
127
- end
128
- end
129
- errors.concat(missing_relations.map { |child| "#{child.element} should not nest in #{parent.element} without valid relationship" })
130
- end
111
+ model
112
+ .diagrams
113
+ .flat_map(&:all_nodes) # These are top level view nodes
114
+ .reject { |view_node| !view_node.element || view_node.nodes.empty? } # reject the ones with no child view nodes
115
+ .flat_map { |parent|
116
+ parent
117
+ .nodes
118
+ .select(&:element)
119
+ .map { |child| [parent, child] } } # map into parent-child pairs for children that are elements
120
+ .select { |pair|
121
+ model.relationships.none? { |rel|
122
+ (rel.source.equal?(pair[0]) && rel.target.equal?(pair[1]))
123
+ }
124
+ }
125
+ .map { |pair| "#{pair[1].element} should not nest in #{pair[0].element} without valid relationship"}
131
126
  end
132
127
 
133
128
  def entity_naming_rules
@@ -135,9 +130,9 @@ module Archimate
135
130
  if entity.name.nil? || entity.name.empty?
136
131
  errors << "#{entity} name is empty"
137
132
  elsif entity.name.size < 2
138
- errors << "#{entity} name #{entity.name.inspect} is too short"
133
+ errors << "#{entity} name #{entity.name} is too short"
139
134
  elsif entity.name.include?("(copy)")
140
- errors << "#{entity} name #{entity.name.inspect} contains '(copy)'"
135
+ errors << "#{entity} name #{entity.name} contains '(copy)'"
141
136
  end
142
137
  end
143
138
  end
@@ -8,6 +8,7 @@ module Archimate
8
8
 
9
9
  def initialize(connection)
10
10
  @connection = connection
11
+ @path = Path.new(@connection)
11
12
  @css_style = CssStyle.new(connection.style)
12
13
  end
13
14
 
@@ -19,22 +20,22 @@ module Archimate
19
20
  end
20
21
 
21
22
  def to_svg(xml)
22
- return if connection.source_element.nodes.include?(connection.target_element)
23
+ return if connection.source.nodes.include?(connection.target)
23
24
  xml.path(path_attrs) do
24
25
  xml.title @connection.description
25
26
  end
26
27
 
27
- name = connection&.relationship_element&.name&.strip
28
+ name = connection&.relationship&.name&.strip
28
29
  return if name.nil? || name.empty?
30
+ pt = @path.point(text_position)
29
31
  xml.text_(
30
32
  class: "archimate-relationship-name",
31
- dy: -2,
33
+ x: pt.x,
34
+ y: pt.y,
32
35
  "text-anchor" => "middle",
33
36
  style: css_style.text
34
37
  ) do
35
- xml.textPath(startOffset: text_position, "xlink:href" => "##{id}") do
36
- xml.text name
37
- end
38
+ xml.text name
38
39
  end
39
40
  end
40
41
 
@@ -52,11 +53,11 @@ module Archimate
52
53
  def text_position
53
54
  case connection.style
54
55
  when 0
55
- "10%"
56
+ 0.1 # "10%"
56
57
  when 1
57
- "90%"
58
+ 0.9 # "90%"
58
59
  else
59
- "50%"
60
+ 0.5 # "50%"
60
61
  end
61
62
  end
62
63
 
@@ -64,20 +65,20 @@ module Archimate
64
65
  {
65
66
  id: id,
66
67
  class: path_class,
67
- d: path_d,
68
+ d: @path.d,
68
69
  style: line_style
69
70
  }
70
71
  end
71
72
 
72
73
  def id
73
- connection.relationship_element&.id || connection.id
74
+ connection.relationship&.id || connection.id
74
75
  end
75
76
 
76
77
  # Look at the type (if any of the path and set the class appropriately)
77
78
  def path_class
78
79
  [
79
80
  "archimate",
80
- css_classify(connection&.relationship_element&.type || "default")
81
+ css_classify(connection&.relationship&.type || "default")
81
82
  ].join("-") + " archimate-relationship"
82
83
  end
83
84
 
@@ -88,97 +89,6 @@ module Archimate
88
89
  .gsub(/([a-z\d])([A-Z])/, '\1-\2')
89
90
  .downcase
90
91
  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
92
  end
183
93
  end
184
94
  end