archimate 1.2.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +47 -0
- data/TODOs.org +219 -0
- data/archimate.gemspec +2 -1
- data/exe/archidiff +7 -0
- data/exe/archidiff-summary +7 -0
- data/exe/archimerge +7 -0
- data/exe/fmtxml +7 -0
- data/lib/archimate.rb +10 -21
- data/lib/archimate/cli/archi.rb +2 -1
- data/lib/archimate/cli/cleanup.rb +8 -9
- data/lib/archimate/cli/convert.rb +3 -1
- data/lib/archimate/cli/mapper.rb +1 -1
- data/lib/archimate/cli/stats.rb +1 -1
- data/lib/archimate/config.rb +4 -1
- data/lib/archimate/data_model.rb +11 -24
- data/lib/archimate/data_model/any_attribute.rb +18 -5
- data/lib/archimate/data_model/any_element.rb +30 -7
- data/lib/archimate/data_model/bounds.rb +34 -7
- data/lib/archimate/data_model/color.rb +32 -7
- data/lib/archimate/data_model/comparison.rb +87 -0
- data/lib/archimate/data_model/concern.rb +20 -7
- data/lib/archimate/data_model/connection.rb +71 -51
- data/lib/archimate/data_model/connector_type.rb +23 -0
- data/lib/archimate/data_model/diagram.rb +72 -10
- data/lib/archimate/data_model/diagram_type.rb +17 -0
- data/lib/archimate/data_model/differentiable.rb +142 -0
- data/lib/archimate/data_model/element.rb +39 -45
- data/lib/archimate/data_model/element_type.rb +89 -0
- data/lib/archimate/data_model/font.rb +30 -12
- data/lib/archimate/data_model/lang_string.rb +89 -16
- data/lib/archimate/data_model/layer.rb +55 -0
- data/lib/archimate/data_model/layers.rb +62 -0
- data/lib/archimate/data_model/location.rb +27 -11
- data/lib/archimate/data_model/metadata.rb +10 -3
- data/lib/archimate/data_model/model.rb +188 -121
- data/lib/archimate/data_model/modeling_note.rb +14 -3
- data/lib/archimate/data_model/organization.rb +44 -13
- data/lib/archimate/data_model/{documentation.rb → preserved_lang_string.rb} +1 -5
- data/lib/archimate/data_model/property.rb +17 -11
- data/lib/archimate/data_model/property_definition.rb +34 -4
- data/lib/archimate/data_model/referenceable.rb +0 -9
- data/lib/archimate/data_model/referenceable_collection.rb +201 -0
- data/lib/archimate/data_model/relationship.rb +52 -33
- data/lib/archimate/data_model/relationship_type.rb +43 -0
- data/lib/archimate/data_model/schema_info.rb +17 -6
- data/lib/archimate/data_model/style.rb +41 -11
- data/lib/archimate/data_model/view_node.rb +153 -59
- data/lib/archimate/data_model/viewpoint.rb +56 -80
- data/lib/archimate/data_model/viewpoint_type.rb +429 -0
- data/lib/archimate/export/csv_export.rb +2 -2
- data/lib/archimate/export/cypher.rb +2 -2
- data/lib/archimate/export/graph_ml.rb +7 -5
- data/lib/archimate/export/jsonl.rb +166 -0
- data/lib/archimate/export/n_quads.rb +8 -5
- data/lib/archimate/file_format.rb +4 -5
- data/lib/archimate/file_formats/archi_file_reader.rb +7 -240
- data/lib/archimate/file_formats/archi_file_writer.rb +16 -188
- data/lib/archimate/file_formats/model_exchange_file_reader.rb +7 -225
- data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +22 -114
- data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +22 -122
- data/lib/archimate/file_formats/sax.rb +55 -0
- data/lib/archimate/file_formats/sax/any_element.rb +64 -0
- data/lib/archimate/file_formats/sax/archi/archi_handler_factory.rb +48 -0
- data/lib/archimate/file_formats/sax/archi/bounds.rb +25 -0
- data/lib/archimate/file_formats/sax/archi/connection.rb +47 -0
- data/lib/archimate/file_formats/sax/archi/content.rb +28 -0
- data/lib/archimate/file_formats/sax/archi/diagram.rb +66 -0
- data/lib/archimate/file_formats/sax/archi/element.rb +36 -0
- data/lib/archimate/file_formats/sax/archi/location.rb +25 -0
- data/lib/archimate/file_formats/sax/archi/model.rb +109 -0
- data/lib/archimate/file_formats/sax/archi/organization.rb +60 -0
- data/lib/archimate/file_formats/sax/archi/property.rb +54 -0
- data/lib/archimate/file_formats/sax/archi/relationship.rb +50 -0
- data/lib/archimate/file_formats/sax/archi/style.rb +35 -0
- data/lib/archimate/file_formats/sax/archi/view_node.rb +76 -0
- data/lib/archimate/file_formats/sax/capture_content.rb +20 -0
- data/lib/archimate/file_formats/sax/capture_documentation.rb +19 -0
- data/lib/archimate/file_formats/sax/capture_properties.rb +20 -0
- data/lib/archimate/file_formats/sax/content_element.rb +19 -0
- data/lib/archimate/file_formats/sax/document.rb +80 -0
- data/lib/archimate/file_formats/sax/handler.rb +54 -0
- data/lib/archimate/file_formats/sax/lang_string.rb +28 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/color.rb +36 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/connection.rb +67 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/diagram.rb +60 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/element.rb +43 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/font.rb +44 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/item.rb +64 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/location.rb +23 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/metadata.rb +66 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/model.rb +124 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/model_exchange_handler_factory.rb +53 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/property.rb +32 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/property_definition.rb +36 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/relationship.rb +49 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/schema_info.rb +47 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/style.rb +66 -0
- data/lib/archimate/file_formats/sax/model_exchange_file/view_node.rb +86 -0
- data/lib/archimate/file_formats/sax/no_op.rb +17 -0
- data/lib/archimate/file_formats/sax/preserved_lang_string.rb +28 -0
- data/lib/archimate/file_formats/serializer.rb +57 -0
- data/lib/archimate/file_formats/serializer/archi/bounds.rb +23 -0
- data/lib/archimate/file_formats/serializer/archi/connection.rb +33 -0
- data/lib/archimate/file_formats/serializer/archi/diagram.rb +28 -0
- data/lib/archimate/file_formats/serializer/archi/documentation.rb +16 -0
- data/lib/archimate/file_formats/serializer/archi/element.rb +24 -0
- data/lib/archimate/file_formats/serializer/archi/location.rb +26 -0
- data/lib/archimate/file_formats/serializer/archi/model.rb +25 -0
- data/lib/archimate/file_formats/serializer/archi/organization.rb +21 -0
- data/lib/archimate/file_formats/serializer/archi/property.rb +15 -0
- data/lib/archimate/file_formats/serializer/archi/relationship.rb +36 -0
- data/lib/archimate/file_formats/serializer/archi/view_node.rb +52 -0
- data/lib/archimate/file_formats/serializer/archi/viewpoint_type.rb +45 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/element.rb +25 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/location.rb +15 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/model_exchange_file_writer.rb +32 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/organization.rb +23 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/properties.rb +15 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/relationship.rb +19 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/style.rb +48 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/connection.rb +25 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/diagram.rb +27 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/item.rb +17 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/label.rb +17 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/model.rb +36 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/organization_body.rb +25 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/property.rb +19 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v21/view_node.rb +44 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/connection.rb +26 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/diagram.rb +27 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/item.rb +17 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/label.rb +17 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/model.rb +41 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/organization_body.rb +25 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/property.rb +19 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/property_definitions.rb +34 -0
- data/lib/archimate/file_formats/serializer/model_exchange_file/v30/view_node.rb +45 -0
- data/lib/archimate/file_formats/serializer/named_collection.rb +21 -0
- data/lib/archimate/file_formats/serializer/writer.rb +56 -0
- data/lib/archimate/file_formats/serializer/xml_lang_string.rb +30 -0
- data/lib/archimate/file_formats/serializer/xml_metadata.rb +64 -0
- data/lib/archimate/file_formats/{model_exchange_file → serializer}/xml_property_defs.rb +2 -2
- data/lib/archimate/lint/duplicate_entities.rb +3 -3
- data/lib/archimate/lint/linter.rb +24 -29
- data/lib/archimate/svg/connection.rb +13 -103
- data/lib/archimate/svg/diagram.rb +1 -1
- data/lib/archimate/svg/entity/base_entity.rb +12 -8
- data/lib/archimate/svg/entity/data_entity.rb +2 -2
- data/lib/archimate/svg/entity/diagram_model_reference.rb +1 -1
- data/lib/archimate/svg/entity/event_entity.rb +2 -2
- data/lib/archimate/svg/entity/gap.rb +1 -1
- data/lib/archimate/svg/entity/group.rb +1 -1
- data/lib/archimate/svg/entity/motivation_entity.rb +1 -1
- data/lib/archimate/svg/entity/node.rb +1 -1
- data/lib/archimate/svg/entity/rect_entity.rb +1 -1
- data/lib/archimate/svg/entity/rounded_rect_entity.rb +1 -1
- data/lib/archimate/svg/entity/service_entity.rb +2 -2
- data/lib/archimate/svg/entity/value.rb +2 -2
- data/lib/archimate/svg/path.rb +153 -0
- data/lib/archimate/svg/point.rb +8 -1
- data/lib/archimate/version.rb +1 -1
- metadata +118 -36
- data/lib/archimate/data_model/archimate_node.rb +0 -181
- data/lib/archimate/data_model/concept.rb +0 -14
- data/lib/archimate/data_model/constants.rb +0 -82
- data/lib/archimate/data_model/container.rb +0 -17
- data/lib/archimate/data_model/diffable_array.rb +0 -213
- data/lib/archimate/data_model/diffable_primitive.rb +0 -83
- data/lib/archimate/data_model/label.rb +0 -19
- data/lib/archimate/data_model/named_referenceable.rb +0 -14
- data/lib/archimate/data_model/view.rb +0 -12
- data/lib/archimate/data_model/view_concept.rb +0 -18
- data/lib/archimate/file_formats/archi_file_format.rb +0 -151
- data/lib/archimate/file_formats/archimate_v2.rb +0 -461
- data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +0 -35
- data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +0 -115
- data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +0 -28
- data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +0 -73
- data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +0 -134
- data/lib/archimate/file_formats/model_exchange_file_writer.rb +0 -157
- 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
|
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.
|
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::
|
90
|
-
layer_sort_order = layer ? DataModel::
|
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 =
|
59
|
-
model.elements.reject { |el| referenced_elements.include?(el
|
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
|
-
|
64
|
-
model.relationships.reject { |el|
|
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.
|
99
|
-
valid_relation_types = VIEWPOINTS[diagram.
|
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
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
133
|
+
errors << "#{entity} name #{entity.name} is too short"
|
139
134
|
elsif entity.name.include?("(copy)")
|
140
|
-
errors << "#{entity} name #{entity.name
|
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.
|
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&.
|
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
|
-
|
33
|
+
x: pt.x,
|
34
|
+
y: pt.y,
|
32
35
|
"text-anchor" => "middle",
|
33
36
|
style: css_style.text
|
34
37
|
) do
|
35
|
-
xml.
|
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:
|
68
|
+
d: @path.d,
|
68
69
|
style: line_style
|
69
70
|
}
|
70
71
|
end
|
71
72
|
|
72
73
|
def id
|
73
|
-
connection.
|
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&.
|
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
|