archimate 1.2.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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