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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.projectile +18 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -0
- data/.yardocs +15 -0
- data/Gemfile +5 -0
- data/Guardfile +27 -0
- data/LICENSE +201 -0
- data/README.md +94 -0
- data/Rakefile +29 -0
- data/TODOs.org +286 -0
- data/archimate.gemspec +51 -0
- data/bin/archimate +17 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/exe/archidiff +7 -0
- data/exe/archidiff-summary +7 -0
- data/exe/archimate +7 -0
- data/exe/archimerge +7 -0
- data/exe/fmtxml +7 -0
- data/lib/archimate/cli/archi.rb +189 -0
- data/lib/archimate/cli/cleanup.rb +54 -0
- data/lib/archimate/cli/conflict_resolver.rb +39 -0
- data/lib/archimate/cli/convert.rb +39 -0
- data/lib/archimate/cli/diff.rb +31 -0
- data/lib/archimate/cli/diff_summary.rb +101 -0
- data/lib/archimate/cli/duper.rb +85 -0
- data/lib/archimate/cli/lint.rb +16 -0
- data/lib/archimate/cli/mapper.rb +82 -0
- data/lib/archimate/cli/merge.rb +49 -0
- data/lib/archimate/cli/merger.rb +109 -0
- data/lib/archimate/cli/stats.rb +42 -0
- data/lib/archimate/cli/svger.rb +40 -0
- data/lib/archimate/color.rb +53 -0
- data/lib/archimate/config.rb +35 -0
- data/lib/archimate/data_model/any_attribute.rb +13 -0
- data/lib/archimate/data_model/any_element.rb +15 -0
- data/lib/archimate/data_model/archimate_node.rb +181 -0
- data/lib/archimate/data_model/bounds.rb +72 -0
- data/lib/archimate/data_model/color.rb +47 -0
- data/lib/archimate/data_model/concept.rb +14 -0
- data/lib/archimate/data_model/concern.rb +17 -0
- data/lib/archimate/data_model/connection.rb +107 -0
- data/lib/archimate/data_model/constants.rb +82 -0
- data/lib/archimate/data_model/container.rb +17 -0
- data/lib/archimate/data_model/diagram.rb +40 -0
- data/lib/archimate/data_model/diffable_array.rb +213 -0
- data/lib/archimate/data_model/diffable_primitive.rb +83 -0
- data/lib/archimate/data_model/documentation.rb +14 -0
- data/lib/archimate/data_model/element.rb +87 -0
- data/lib/archimate/data_model/font.rb +54 -0
- data/lib/archimate/data_model/label.rb +19 -0
- data/lib/archimate/data_model/lang_string.rb +41 -0
- data/lib/archimate/data_model/location.rb +31 -0
- data/lib/archimate/data_model/metadata.rb +14 -0
- data/lib/archimate/data_model/model.rb +217 -0
- data/lib/archimate/data_model/modeling_note.rb +13 -0
- data/lib/archimate/data_model/named_referenceable.rb +14 -0
- data/lib/archimate/data_model/organization.rb +40 -0
- data/lib/archimate/data_model/property.rb +25 -0
- data/lib/archimate/data_model/property_definition.rb +16 -0
- data/lib/archimate/data_model/referenceable.rb +29 -0
- data/lib/archimate/data_model/relationship.rb +85 -0
- data/lib/archimate/data_model/schema_info.rb +18 -0
- data/lib/archimate/data_model/style.rb +32 -0
- data/lib/archimate/data_model/view.rb +12 -0
- data/lib/archimate/data_model/view_concept.rb +18 -0
- data/lib/archimate/data_model/view_node.rb +114 -0
- data/lib/archimate/data_model/viewpoint.rb +87 -0
- data/lib/archimate/data_model.rb +54 -0
- data/lib/archimate/diff/archimate_array_reference.rb +113 -0
- data/lib/archimate/diff/archimate_identified_node_reference.rb +41 -0
- data/lib/archimate/diff/archimate_node_attribute_reference.rb +70 -0
- data/lib/archimate/diff/archimate_node_reference.rb +80 -0
- data/lib/archimate/diff/change.rb +49 -0
- data/lib/archimate/diff/conflict.rb +31 -0
- data/lib/archimate/diff/conflicts/base_conflict.rb +53 -0
- data/lib/archimate/diff/conflicts/deleted_items_child_updated_conflict.rb +30 -0
- data/lib/archimate/diff/conflicts/deleted_items_referenced_conflict.rb +63 -0
- data/lib/archimate/diff/conflicts/path_conflict.rb +51 -0
- data/lib/archimate/diff/conflicts.rb +89 -0
- data/lib/archimate/diff/delete.rb +41 -0
- data/lib/archimate/diff/difference.rb +113 -0
- data/lib/archimate/diff/insert.rb +43 -0
- data/lib/archimate/diff/merge.rb +70 -0
- data/lib/archimate/diff/move.rb +51 -0
- data/lib/archimate/diff.rb +17 -0
- data/lib/archimate/export/csv_export.rb +32 -0
- data/lib/archimate/export/cypher.rb +171 -0
- data/lib/archimate/export/graph_ml.rb +131 -0
- data/lib/archimate/export/n_quads.rb +142 -0
- data/lib/archimate/file_format.rb +30 -0
- data/lib/archimate/file_formats/archi_file_format.rb +151 -0
- data/lib/archimate/file_formats/archi_file_reader.rb +252 -0
- data/lib/archimate/file_formats/archi_file_writer.rb +230 -0
- data/lib/archimate/file_formats/archimate_v2.rb +461 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +35 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +115 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +28 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_property_defs.rb +27 -0
- data/lib/archimate/file_formats/model_exchange_file_reader.rb +237 -0
- data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +73 -0
- data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +134 -0
- data/lib/archimate/file_formats/model_exchange_file_writer.rb +157 -0
- data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +143 -0
- data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +153 -0
- data/lib/archimate/file_formats/writer.rb +56 -0
- data/lib/archimate/lint/duplicate_entities.rb +121 -0
- data/lib/archimate/lint/linter.rb +146 -0
- data/lib/archimate/logging.rb +55 -0
- data/lib/archimate/maybe_io.rb +34 -0
- data/lib/archimate/progress_indicator.rb +29 -0
- data/lib/archimate/svg/archimate.css +232 -0
- data/lib/archimate/svg/child.rb +29 -0
- data/lib/archimate/svg/connection.rb +184 -0
- data/lib/archimate/svg/css_style.rb +31 -0
- data/lib/archimate/svg/diagram.rb +87 -0
- data/lib/archimate/svg/entity/and_junction.rb +14 -0
- data/lib/archimate/svg/entity/application_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/application_component.rb +41 -0
- data/lib/archimate/svg/entity/application_event.rb +13 -0
- data/lib/archimate/svg/entity/application_function.rb +13 -0
- data/lib/archimate/svg/entity/application_interaction.rb +13 -0
- data/lib/archimate/svg/entity/application_interface.rb +13 -0
- data/lib/archimate/svg/entity/application_process.rb +13 -0
- data/lib/archimate/svg/entity/application_service.rb +13 -0
- data/lib/archimate/svg/entity/artifact.rb +39 -0
- data/lib/archimate/svg/entity/assessment.rb +14 -0
- data/lib/archimate/svg/entity/base_entity.rb +128 -0
- data/lib/archimate/svg/entity/business_actor.rb +14 -0
- data/lib/archimate/svg/entity/business_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/business_event.rb +10 -0
- data/lib/archimate/svg/entity/business_function.rb +13 -0
- data/lib/archimate/svg/entity/business_interaction.rb +13 -0
- data/lib/archimate/svg/entity/business_interface.rb +13 -0
- data/lib/archimate/svg/entity/business_object.rb +13 -0
- data/lib/archimate/svg/entity/business_process.rb +13 -0
- data/lib/archimate/svg/entity/business_role.rb +14 -0
- data/lib/archimate/svg/entity/business_service.rb +13 -0
- data/lib/archimate/svg/entity/capability.rb +14 -0
- data/lib/archimate/svg/entity/communication_network.rb +14 -0
- data/lib/archimate/svg/entity/communication_path.rb +14 -0
- data/lib/archimate/svg/entity/constraint.rb +15 -0
- data/lib/archimate/svg/entity/contract.rb +13 -0
- data/lib/archimate/svg/entity/course_of_action.rb +14 -0
- data/lib/archimate/svg/entity/data_entity.rb +29 -0
- data/lib/archimate/svg/entity/data_object.rb +13 -0
- data/lib/archimate/svg/entity/deliverable.rb +13 -0
- data/lib/archimate/svg/entity/device.rb +48 -0
- data/lib/archimate/svg/entity/diagram_model_reference.rb +22 -0
- data/lib/archimate/svg/entity/diagram_object.rb +30 -0
- data/lib/archimate/svg/entity/distribution_network.rb +14 -0
- data/lib/archimate/svg/entity/driver.rb +14 -0
- data/lib/archimate/svg/entity/equipment.rb +16 -0
- data/lib/archimate/svg/entity/event_entity.rb +36 -0
- data/lib/archimate/svg/entity/facility.rb +16 -0
- data/lib/archimate/svg/entity/function_entity.rb +14 -0
- data/lib/archimate/svg/entity/gap.rb +21 -0
- data/lib/archimate/svg/entity/goal.rb +14 -0
- data/lib/archimate/svg/entity/group.rb +24 -0
- data/lib/archimate/svg/entity/implementation_event.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_function.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_interface.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_service.rb +13 -0
- data/lib/archimate/svg/entity/interaction_entity.rb +14 -0
- data/lib/archimate/svg/entity/interface_entity.rb +35 -0
- data/lib/archimate/svg/entity/junction.rb +19 -0
- data/lib/archimate/svg/entity/location.rb +14 -0
- data/lib/archimate/svg/entity/material.rb +14 -0
- data/lib/archimate/svg/entity/meaning.rb +40 -0
- data/lib/archimate/svg/entity/motivation_entity.rb +40 -0
- data/lib/archimate/svg/entity/network.rb +14 -0
- data/lib/archimate/svg/entity/node.rb +33 -0
- data/lib/archimate/svg/entity/node_shape.rb +64 -0
- data/lib/archimate/svg/entity/note.rb +30 -0
- data/lib/archimate/svg/entity/or_junction.rb +14 -0
- data/lib/archimate/svg/entity/outcome.rb +15 -0
- data/lib/archimate/svg/entity/path.rb +14 -0
- data/lib/archimate/svg/entity/plateau.rb +15 -0
- data/lib/archimate/svg/entity/principle.rb +15 -0
- data/lib/archimate/svg/entity/process_entity.rb +63 -0
- data/lib/archimate/svg/entity/product.rb +20 -0
- data/lib/archimate/svg/entity/rect.rb +13 -0
- data/lib/archimate/svg/entity/rect_entity.rb +25 -0
- data/lib/archimate/svg/entity/representation.rb +31 -0
- data/lib/archimate/svg/entity/requirement.rb +15 -0
- data/lib/archimate/svg/entity/resource.rb +14 -0
- data/lib/archimate/svg/entity/rounded_rect_entity.rb +23 -0
- data/lib/archimate/svg/entity/service_entity.rb +51 -0
- data/lib/archimate/svg/entity/sketch_model_sticky.rb +14 -0
- data/lib/archimate/svg/entity/stakeholder.rb +15 -0
- data/lib/archimate/svg/entity/system_software.rb +14 -0
- data/lib/archimate/svg/entity/technology_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/technology_event.rb +13 -0
- data/lib/archimate/svg/entity/technology_function.rb +13 -0
- data/lib/archimate/svg/entity/technology_interaction.rb +13 -0
- data/lib/archimate/svg/entity/technology_interface.rb +13 -0
- data/lib/archimate/svg/entity/technology_process.rb +13 -0
- data/lib/archimate/svg/entity/technology_service.rb +13 -0
- data/lib/archimate/svg/entity/value.rb +27 -0
- data/lib/archimate/svg/entity/work_package.rb +14 -0
- data/lib/archimate/svg/entity.rb +93 -0
- data/lib/archimate/svg/entity_factory.rb +17 -0
- data/lib/archimate/svg/extents.rb +27 -0
- data/lib/archimate/svg/point.rb +7 -0
- data/lib/archimate/svg/svg_template.rb +27 -0
- data/lib/archimate/svg/svg_template.svg.erb +169 -0
- data/lib/archimate/version.rb +4 -0
- data/lib/archimate.rb +114 -0
- metadata +623 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archimate
|
|
4
|
+
module DataModel
|
|
5
|
+
# Basic Viewpoints
|
|
6
|
+
# Category:Composition Viewpoints that defines internal compositions and aggregations of elements.
|
|
7
|
+
COMPOSITION_VIEWPOINTS = [
|
|
8
|
+
"Organization",
|
|
9
|
+
"Application Platform",
|
|
10
|
+
"Information Structure",
|
|
11
|
+
"Technology",
|
|
12
|
+
"Layered",
|
|
13
|
+
"Physical"
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
# Category:Support Viewpoints where you are looking at elements that are supported by other elements. Typically from one layer and upwards to an above layer.
|
|
17
|
+
SUPPORT_VIEWPOINTS = [
|
|
18
|
+
"Product",
|
|
19
|
+
"Application Usage",
|
|
20
|
+
"Technology Usage"
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
# Category:Cooperation Towards peer elements which cooperate with each other. Typically across aspects.
|
|
24
|
+
COOPERATION_VIEWPOINTS = [
|
|
25
|
+
"Business Process Cooperation",
|
|
26
|
+
"Application Cooperation"
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
# Category:Realization Viewpoints where you are looking at elements that realize other elements. Typically from one layer and downwards to a below layer.
|
|
30
|
+
REALIZATION_VIEWPOINTS = [
|
|
31
|
+
"Service Realization",
|
|
32
|
+
"Implementation and Deployment",
|
|
33
|
+
"Goal Realization",
|
|
34
|
+
"Goal Contribution",
|
|
35
|
+
"Principles",
|
|
36
|
+
"Requirements Realization",
|
|
37
|
+
"Motivation"
|
|
38
|
+
].freeze
|
|
39
|
+
|
|
40
|
+
# Strategy Viewpoints
|
|
41
|
+
STRATEGY_VIEWPOINTS = [
|
|
42
|
+
"Strategy",
|
|
43
|
+
"Capability Map",
|
|
44
|
+
"Outcome Realization",
|
|
45
|
+
"Resource Map"
|
|
46
|
+
].freeze
|
|
47
|
+
|
|
48
|
+
# Implementation and Migration Viewpoints
|
|
49
|
+
IMPLEMENTATION_AND_MIGRATION_VIEWPOINTS = [
|
|
50
|
+
"Project",
|
|
51
|
+
"Migration",
|
|
52
|
+
"Implementation and Migration"
|
|
53
|
+
].freeze
|
|
54
|
+
|
|
55
|
+
# Other Viewpoints
|
|
56
|
+
Other_Viewpoints = %w[Stakeholder].freeze
|
|
57
|
+
|
|
58
|
+
VIEWPOINTS_ENUM = [].concat(
|
|
59
|
+
[COMPOSITION_VIEWPOINTS, SUPPORT_VIEWPOINTS, COOPERATION_VIEWPOINTS,
|
|
60
|
+
REALIZATION_VIEWPOINTS, STRATEGY_VIEWPOINTS,
|
|
61
|
+
IMPLEMENTATION_AND_MIGRATION_VIEWPOINTS].flatten
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
ViewpointType = Strict::String.enum(*VIEWPOINTS_ENUM).optional
|
|
65
|
+
|
|
66
|
+
ViewpointContentEnum = Strict::String.enum(%w[Details Coherence Overview])
|
|
67
|
+
ViewpointContent = Strict::Array.member(ViewpointContentEnum).default([])
|
|
68
|
+
|
|
69
|
+
ViewpointPurposeEnum = Strict::String.enum(%w[Designing Deciding Informing])
|
|
70
|
+
ViewpointPurpose = Strict::Array.member(ViewpointPurposeEnum).default([])
|
|
71
|
+
|
|
72
|
+
class Viewpoint < NamedReferenceable
|
|
73
|
+
using DataModel::DiffableArray
|
|
74
|
+
using DataModel::DiffablePrimitive
|
|
75
|
+
|
|
76
|
+
attribute :concern, ConcernList
|
|
77
|
+
attribute :viewpointPurpose, ViewpointPurpose.optional
|
|
78
|
+
attribute :viewpointContent, ViewpointContent.optional
|
|
79
|
+
attribute :allowedElementTypes, AllowedElementTypes
|
|
80
|
+
attribute :allowedRelationshipTypes, AllowedRelationshipTypes
|
|
81
|
+
attribute :modelingNotes, Strict::Array.member(ModelingNote).default([])
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
Dry::Types.register_class(Viewpoint)
|
|
85
|
+
ViewpointList = Strict::Array.member(Viewpoint).default([])
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archimate
|
|
4
|
+
module DataModel
|
|
5
|
+
include Dry::Types.module
|
|
6
|
+
|
|
7
|
+
Coercible = Archimate::DataModel::Coercible
|
|
8
|
+
Strict = Archimate::DataModel::Strict
|
|
9
|
+
|
|
10
|
+
# Identifiers in the ArchiMate exchange format standard are of
|
|
11
|
+
Identifier = Strict::String # .constrained(format: /[[[:alpha:]]_][\w\-\.]*/)
|
|
12
|
+
|
|
13
|
+
# An enumeration of data types.
|
|
14
|
+
DataType = Strict::String.default("string").enum("string", "boolean", "currency", "date", "time", "number")
|
|
15
|
+
|
|
16
|
+
# Enumeration of Influence Strength types. These are suggestions.
|
|
17
|
+
InfluenceStrengthEnum = Strict::String.enum(%w[+ ++ - -- 0 1 2 3 4 5 6 7 8 9 10])
|
|
18
|
+
|
|
19
|
+
require 'archimate/data_model/diffable_primitive'
|
|
20
|
+
require 'archimate/data_model/diffable_array'
|
|
21
|
+
require 'archimate/data_model/constants'
|
|
22
|
+
require 'archimate/data_model/archimate_node'
|
|
23
|
+
require 'archimate/data_model/any_attribute'
|
|
24
|
+
require 'archimate/data_model/any_element'
|
|
25
|
+
require 'archimate/data_model/lang_string'
|
|
26
|
+
require 'archimate/data_model/schema_info'
|
|
27
|
+
require 'archimate/data_model/metadata'
|
|
28
|
+
require 'archimate/data_model/color'
|
|
29
|
+
require 'archimate/data_model/font'
|
|
30
|
+
require 'archimate/data_model/style'
|
|
31
|
+
require 'archimate/data_model/bounds'
|
|
32
|
+
require 'archimate/data_model/documentation'
|
|
33
|
+
require 'archimate/data_model/modeling_note'
|
|
34
|
+
require 'archimate/data_model/referenceable'
|
|
35
|
+
require 'archimate/data_model/named_referenceable'
|
|
36
|
+
require 'archimate/data_model/property_definition'
|
|
37
|
+
require 'archimate/data_model/property'
|
|
38
|
+
require 'archimate/data_model/concept'
|
|
39
|
+
require 'archimate/data_model/organization'
|
|
40
|
+
require 'archimate/data_model/element'
|
|
41
|
+
require 'archimate/data_model/relationship'
|
|
42
|
+
require 'archimate/data_model/concern'
|
|
43
|
+
require 'archimate/data_model/viewpoint'
|
|
44
|
+
require 'archimate/data_model/view'
|
|
45
|
+
require 'archimate/data_model/view_concept'
|
|
46
|
+
require 'archimate/data_model/location'
|
|
47
|
+
require 'archimate/data_model/connection'
|
|
48
|
+
require 'archimate/data_model/view_node'
|
|
49
|
+
require 'archimate/data_model/container'
|
|
50
|
+
require 'archimate/data_model/diagram'
|
|
51
|
+
require 'archimate/data_model/label'
|
|
52
|
+
require 'archimate/data_model/model'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archimate
|
|
4
|
+
module Diff
|
|
5
|
+
class ArchimateArrayReference < ArchimateNodeReference
|
|
6
|
+
using DataModel::DiffableArray
|
|
7
|
+
using DataModel::DiffablePrimitive
|
|
8
|
+
|
|
9
|
+
attr_reader :array_index
|
|
10
|
+
|
|
11
|
+
def initialize(array, array_index)
|
|
12
|
+
unless array.is_a?(Array)
|
|
13
|
+
raise(
|
|
14
|
+
TypeError,
|
|
15
|
+
"array argument must be an Array, was #{array.class}"
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
unless array_index.is_a?(Integer)
|
|
19
|
+
raise(
|
|
20
|
+
TypeError,
|
|
21
|
+
"array_index argument must be a Integer, was #{array_index.class} #{array_index.inspect}"
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
unless array_index >= 0 && array_index < array.size
|
|
25
|
+
raise(
|
|
26
|
+
ArgumentError,
|
|
27
|
+
"array_index argument a valid index for array #{array_index.inspect}"
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
super(array)
|
|
31
|
+
@array_index = array_index
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def value
|
|
35
|
+
archimate_node[array_index]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_s
|
|
39
|
+
value.to_s
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def lookup_in_model(model)
|
|
43
|
+
result = lookup_parent_in_model(model)
|
|
44
|
+
raise TypeError, "result was #{result.class} expected Array" unless result.is_a?(Array)
|
|
45
|
+
result[array_index]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def path(options = {})
|
|
49
|
+
@array_ref_path ||= [
|
|
50
|
+
super,
|
|
51
|
+
case value
|
|
52
|
+
when DataModel::Referenceable
|
|
53
|
+
value.id
|
|
54
|
+
else
|
|
55
|
+
array_index
|
|
56
|
+
end
|
|
57
|
+
].map(&:to_s).reject(&:empty?).join("/")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# For inserts - we can't be sure of what is available (without an expensive sort)
|
|
61
|
+
# So lookup the first previous value that exists in to_model and insert it after that
|
|
62
|
+
# value instead of a fixed index.
|
|
63
|
+
def find_insert_index_in_ary(ary)
|
|
64
|
+
return -1 if array_index.zero?
|
|
65
|
+
my_idx = (array_index - 1).downto(0).find(-1) do |idx|
|
|
66
|
+
ary.smart_include?(archimate_node[idx])
|
|
67
|
+
end
|
|
68
|
+
ary.smart_find(archimate_node[my_idx])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def insert(to_model)
|
|
72
|
+
ary_in_model = lookup_parent_in_model(to_model)
|
|
73
|
+
insert_idx = find_insert_index_in_ary(ary_in_model) + 1
|
|
74
|
+
ary_in_model.insert(insert_idx, value)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def delete(to_model)
|
|
78
|
+
ary_in_model = lookup_parent_in_model(to_model)
|
|
79
|
+
if ary_in_model.nil?
|
|
80
|
+
$stderr.puts "lookup parent in model failed for path #{path}"
|
|
81
|
+
return nil
|
|
82
|
+
end
|
|
83
|
+
idx = ary_in_model.smart_find(value)
|
|
84
|
+
if idx
|
|
85
|
+
ary_in_model.delete_at(idx)
|
|
86
|
+
else
|
|
87
|
+
$stderr.puts "Couldn't find item #{value.inspect} in path #{path} to delete in to_model"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def change(to_model, from_value)
|
|
92
|
+
ary_in_model = lookup_parent_in_model(to_model)
|
|
93
|
+
idx = ary_in_model.smart_find(from_value)
|
|
94
|
+
if idx.nil?
|
|
95
|
+
$stderr.puts "Couldn't find value #{from_value.inspect} in path #{path} to change in to_model, adding to end of list"
|
|
96
|
+
idx = ary_in_model.size
|
|
97
|
+
end
|
|
98
|
+
ary_in_model[idx] = value
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def move(to_model, _from_ref)
|
|
102
|
+
ary_in_model = lookup_parent_in_model(to_model)
|
|
103
|
+
insert_idx = parent.previous_item_index(ary_in_model, value) + 1
|
|
104
|
+
current_idx = ary_in_model.smart_find(value)
|
|
105
|
+
deleted_value = ary_in_model.delete_at(current_idx)
|
|
106
|
+
ary_in_model.insert(
|
|
107
|
+
insert_idx,
|
|
108
|
+
deleted_value
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archimate
|
|
4
|
+
module Diff
|
|
5
|
+
class ArchimateReferenceableReference < ArchimateNodeReference
|
|
6
|
+
using DataModel::DiffableArray
|
|
7
|
+
|
|
8
|
+
def initialize(archimate_node)
|
|
9
|
+
unless archimate_node.is_a?(DataModel::Referenceable)
|
|
10
|
+
raise(
|
|
11
|
+
TypeError,
|
|
12
|
+
"archimate_node is a #{archimate_node.class}, Referenceable was expected"
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def lookup_in_model(model)
|
|
19
|
+
raise TypeError unless model.is_a?(DataModel::Model)
|
|
20
|
+
# There can be only one Model so return the model argument if
|
|
21
|
+
# this node reference is a Model. This escape is required in case
|
|
22
|
+
# the Model this is being applied to has a different id than the
|
|
23
|
+
# model of the attribute this reference refers to.
|
|
24
|
+
return model if archimate_node.is_a?(DataModel::Model)
|
|
25
|
+
model.lookup(archimate_node.id)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
archimate_node.to_s
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def value
|
|
33
|
+
archimate_node
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def parent
|
|
37
|
+
archimate_node.parent
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archimate
|
|
4
|
+
module Diff
|
|
5
|
+
class ArchimateNodeAttributeReference < ArchimateNodeReference
|
|
6
|
+
attr_reader :attribute
|
|
7
|
+
|
|
8
|
+
def initialize(archimate_node, attribute)
|
|
9
|
+
unless archimate_node.is_a?(DataModel::ArchimateNode)
|
|
10
|
+
raise(
|
|
11
|
+
TypeError,
|
|
12
|
+
"archimate_node must be an ArchimateNode, was #{archimate_node.class}"
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
unless attribute.is_a?(Symbol)
|
|
16
|
+
raise(
|
|
17
|
+
TypeError,
|
|
18
|
+
"Node #{archimate_node.class} attribute must be a sym, was a #{attribute.class} value #{attribute.inspect}"
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
unless archimate_node.class.schema.keys.include?(attribute)
|
|
22
|
+
raise(
|
|
23
|
+
ArgumentError,
|
|
24
|
+
"Attribute #{attribute} invalid for class #{archimate_node.class}"
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
super(archimate_node)
|
|
28
|
+
@attribute = attribute
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ==(other)
|
|
32
|
+
super && attribute == other.attribute
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def lookup_in_model(model)
|
|
36
|
+
recurse_lookup_in_model(archimate_node, model)[attribute]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_s
|
|
40
|
+
attribute.to_s
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def value
|
|
44
|
+
archimate_node[attribute]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def path(options = {})
|
|
48
|
+
@node_attribute_ref_path ||= [
|
|
49
|
+
super, @attribute
|
|
50
|
+
].map(&:to_s).reject(&:empty?).join("/")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def insert(to_model)
|
|
54
|
+
lookup_parent_in_model(to_model).set(attribute, value)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def delete(to_model)
|
|
58
|
+
lookup_parent_in_model(to_model).delete(attribute)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def change(to_model, _from_value)
|
|
62
|
+
lookup_parent_in_model(to_model).set(attribute, value)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def move(_to_model)
|
|
66
|
+
raise "Move is not valid for ArchimateNodes"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archimate
|
|
4
|
+
module Diff
|
|
5
|
+
class ArchimateNodeReference
|
|
6
|
+
using DataModel::DiffablePrimitive
|
|
7
|
+
using DataModel::DiffableArray
|
|
8
|
+
|
|
9
|
+
attr_reader :archimate_node
|
|
10
|
+
|
|
11
|
+
# There should be only a few things that are valid here:
|
|
12
|
+
# 1. An archimate node and a attribute name sym
|
|
13
|
+
# 2. An array and index
|
|
14
|
+
# Produces a NodeReference instance for the given parameters
|
|
15
|
+
def self.for_node(node, child_node)
|
|
16
|
+
case node
|
|
17
|
+
when DataModel::ArchimateNode
|
|
18
|
+
ArchimateNodeAttributeReference.new(node, child_node)
|
|
19
|
+
when Array
|
|
20
|
+
ArchimateArrayReference.new(node, child_node)
|
|
21
|
+
else
|
|
22
|
+
raise TypeError, "Node references need to be either an ArchimateNode or an Array"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(archimate_node)
|
|
27
|
+
unless archimate_node.is_a?(DataModel::ArchimateNode) || archimate_node.is_a?(Array)
|
|
28
|
+
raise(
|
|
29
|
+
TypeError,
|
|
30
|
+
"archimate_node must be an ArchimateNode or Array, was #{archimate_node.class}"
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
raise "new WTF? parent at path #{archimate_node.path} is a #{archimate_node.class} but isn't assigned a model" if archimate_node.in_model.nil? && !archimate_node.is_a?(DataModel::Model)
|
|
34
|
+
@archimate_node = archimate_node
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ==(other)
|
|
38
|
+
other.is_a?(self.class) &&
|
|
39
|
+
value == other.value
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
value.to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def lookup_in_model(model)
|
|
47
|
+
recurse_lookup_in_model(archimate_node, model)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def recurse_lookup_in_model(node, model)
|
|
51
|
+
return nil if node.nil?
|
|
52
|
+
raise TypeError, "node argument must be ArchimateNode or Array, was a #{node.class}" unless node.is_a?(Array) || node.is_a?(DataModel::ArchimateNode)
|
|
53
|
+
raise TypeError, "model argument must be a Model, was a #{model.class}" unless model.is_a?(DataModel::Model)
|
|
54
|
+
if node.is_a?(DataModel::Model)
|
|
55
|
+
return model
|
|
56
|
+
elsif node.is_a?(DataModel::Referenceable)
|
|
57
|
+
return model.lookup(node.id)
|
|
58
|
+
else
|
|
59
|
+
node_parent_in_model = recurse_lookup_in_model(node.parent, model)
|
|
60
|
+
node_parent_in_model[node.parent_attribute_name] unless node_parent_in_model.nil?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def lookup_parent_in_model(model)
|
|
65
|
+
raise "WTF? parent at path #{path} is a #{parent.class} but isn't assigned a model" if parent.in_model.nil? && !parent.is_a?(DataModel::Model)
|
|
66
|
+
result = recurse_lookup_in_model(parent, model)
|
|
67
|
+
$stderr.puts "Unable to lookup parent with path #{path}" if result.nil?
|
|
68
|
+
result
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parent
|
|
72
|
+
archimate_node
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def path(options = {})
|
|
76
|
+
@node_ref_path ||= archimate_node.path(options)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Archimate
|
|
3
|
+
module Diff
|
|
4
|
+
class Change < Difference
|
|
5
|
+
using DataModel::DiffableArray
|
|
6
|
+
|
|
7
|
+
# Create a new Change difference
|
|
8
|
+
#
|
|
9
|
+
# @param target [Archimate::Diff::ArchimateNodeReference] reference to
|
|
10
|
+
# ArchimateNode that was changed
|
|
11
|
+
# @param changed_from [Archimate::Diff::ArchimateNodeReference] Element
|
|
12
|
+
# that was changed
|
|
13
|
+
def initialize(target, changed_from)
|
|
14
|
+
super(target, changed_from)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s
|
|
18
|
+
# Note - the explicit to_s is required to access the DiffableArray
|
|
19
|
+
# implementation if the parent is an Array.
|
|
20
|
+
"#{diff_type} #{changed_from.parent&.to_s} #{Color.color(target.to_s, :change)} changed to #{target.value}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def apply(to_model)
|
|
24
|
+
unless to_model.is_a?(DataModel::Model)
|
|
25
|
+
throw(
|
|
26
|
+
TypeError,
|
|
27
|
+
"Expected a Archimate::DataModel::Model, was a #{to_model.class}"
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
target.change(to_model, changed_from.value)
|
|
31
|
+
to_model
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def change?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def kind
|
|
39
|
+
"Change"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def diff_type
|
|
45
|
+
Color.color('CHANGE:', :change)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Archimate
|
|
3
|
+
module Diff
|
|
4
|
+
class Conflict
|
|
5
|
+
attr_reader :base_local_diffs
|
|
6
|
+
attr_reader :base_remote_diffs
|
|
7
|
+
attr_reader :reason
|
|
8
|
+
attr_reader :diffs
|
|
9
|
+
|
|
10
|
+
def initialize(base_local_diffs, base_remote_diffs, reason)
|
|
11
|
+
@base_local_diffs = Array(base_local_diffs)
|
|
12
|
+
@base_remote_diffs = Array(base_remote_diffs)
|
|
13
|
+
@diffs = @base_local_diffs + @base_remote_diffs
|
|
14
|
+
@reason = reason
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s
|
|
18
|
+
"#{Color.color('CONFLICT:', [:black, :on_red])} #{reason}\n" \
|
|
19
|
+
"\tBase->Local Diff(s):\n\t\t#{base_local_diffs.map(&:to_s).join("\n\t\t")}" \
|
|
20
|
+
"\n\tBase->Remote Diffs(s):\n\t\t#{base_remote_diffs.map(&:to_s).join("\n\t\t")}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ==(other)
|
|
24
|
+
other.is_a?(self.class) &&
|
|
25
|
+
base_local_diffs == other.base_local_diffs &&
|
|
26
|
+
base_remote_diffs == other.base_remote_diffs &&
|
|
27
|
+
reason == other.reason
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Archimate
|
|
3
|
+
module Diff
|
|
4
|
+
class Conflicts
|
|
5
|
+
# BaseConflict
|
|
6
|
+
# @abstract
|
|
7
|
+
class BaseConflict
|
|
8
|
+
def initialize(base_local_diffs, base_remote_diffs)
|
|
9
|
+
@base_local_diffs = base_local_diffs
|
|
10
|
+
@base_remote_diffs = base_remote_diffs
|
|
11
|
+
@associative = false
|
|
12
|
+
@diff_iterations = nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def filter1
|
|
16
|
+
->(_diff) { true }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def filter2
|
|
20
|
+
->(_diff) { true }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def conflicts
|
|
24
|
+
progressbar = ProgressIndicator.new(total: diff_iterations.size, title: "Analyzing Conflicts")
|
|
25
|
+
diff_iterations.each_with_object([]) do |(md1, md2), conflicts|
|
|
26
|
+
progressbar.increment
|
|
27
|
+
conflicts.concat(
|
|
28
|
+
md1.map { |diff1| [diff1, md2.select(&method(:diff_conflicts).curry[diff1])] }
|
|
29
|
+
.reject { |_diff1, diff2| diff2.empty? }
|
|
30
|
+
.map { |diff1, diff2_ary| Conflict.new(diff1, diff2_ary, describe) }
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
ensure
|
|
34
|
+
progressbar.finish
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def diff_combinations
|
|
38
|
+
combos = [@base_local_diffs, @base_remote_diffs]
|
|
39
|
+
@associative ? [combos] : combos.permutation(2)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# By default our conflict tests are not associative to we need to run
|
|
43
|
+
# [local, remote] and [remote, local] through the tests.
|
|
44
|
+
def diff_iterations
|
|
45
|
+
@diff_iterations ||=
|
|
46
|
+
diff_combinations.map do |local_diffs, remote_diffs|
|
|
47
|
+
[local_diffs.select(&filter1), remote_diffs.select(&filter2)]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Archimate
|
|
3
|
+
module Diff
|
|
4
|
+
class Conflicts
|
|
5
|
+
class DeletedItemsChildUpdatedConflict < BaseConflict
|
|
6
|
+
def describe
|
|
7
|
+
"Checking for Deleted items in one change set have children that are inserted or changed in the other change set"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def filter1
|
|
11
|
+
->(diff) { diff.delete? }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def filter2
|
|
15
|
+
->(diff) { !diff.delete? }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# TODO: This is simple, but might be slow.
|
|
19
|
+
def diff_conflicts(diff1, diff2)
|
|
20
|
+
da1 = diff1.path.split("/")
|
|
21
|
+
da2 = diff2.path.split("/")
|
|
22
|
+
|
|
23
|
+
cmp_size = [da1, da2].map(&:size).min - 1
|
|
24
|
+
return false if da2.size == cmp_size + 1
|
|
25
|
+
da1[0..cmp_size] == da2[0..cmp_size]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Archimate
|
|
3
|
+
module Diff
|
|
4
|
+
class Conflicts
|
|
5
|
+
# DeletedItemsReferencedConflict
|
|
6
|
+
#
|
|
7
|
+
# This sort of conflict occurs when one change set has deleted an element
|
|
8
|
+
# that is referenced by id in the other change set.
|
|
9
|
+
#
|
|
10
|
+
# For example:
|
|
11
|
+
#
|
|
12
|
+
# In the local change set, an element with id "abc123" is deleted.
|
|
13
|
+
# In the remote change set, a child is inserted into a diagram with
|
|
14
|
+
# archimate_element = "abc123". These two changes are in conflict.
|
|
15
|
+
class DeletedItemsReferencedConflict < BaseConflict
|
|
16
|
+
using DataModel::DiffableArray
|
|
17
|
+
using DataModel::DiffablePrimitive
|
|
18
|
+
|
|
19
|
+
def describe
|
|
20
|
+
"Checking for Deleted items in one change set are referenced in the other change set"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Filters a changeset to potentially conflicting diffs (making the set
|
|
24
|
+
# of combinations to check smaller)
|
|
25
|
+
#
|
|
26
|
+
# @return [lambda] a filter to limit diffs to Delete type
|
|
27
|
+
def filter1
|
|
28
|
+
->(diff) { diff.delete? && diff.target.value.is_a?(DataModel::Referenceable) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Filters a changeset to potentially conflicting diffs (making the set
|
|
32
|
+
# of combinations to check smaller)
|
|
33
|
+
#
|
|
34
|
+
# @return [lambda] a filter to limit diffs to other
|
|
35
|
+
# than Delete type
|
|
36
|
+
def filter2
|
|
37
|
+
->(diff) { !diff.delete? }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Determine the set of conflicts between the given diffs
|
|
41
|
+
# def conflicts
|
|
42
|
+
# progressbar = ProgressIndicator.new(total: diff_iterations.size)
|
|
43
|
+
# diff_iterations.each_with_object([]) do |(md1, md2), a|
|
|
44
|
+
# progressbar.increment
|
|
45
|
+
# a.concat(
|
|
46
|
+
# md1.map { |diff1| [diff1, md2.select(&method(:diff_conflicts).curry[diff1])] }
|
|
47
|
+
# .reject { |_diff1, diff2| diff2.empty? }
|
|
48
|
+
# .map { |diff1, diff2_ary| Conflict.new(diff1, diff2_ary, describe) }
|
|
49
|
+
# )
|
|
50
|
+
# end
|
|
51
|
+
# ensure
|
|
52
|
+
# progressbar&.finish
|
|
53
|
+
# end
|
|
54
|
+
|
|
55
|
+
# TODO: This is simple, but might be slow. If it is, then override
|
|
56
|
+
# the conflicts method to prevent calculating referenced_identified_nodes methods
|
|
57
|
+
def diff_conflicts(diff1, diff2)
|
|
58
|
+
diff2.target.value.referenced_identified_nodes.include?(diff1.target.value.id)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|