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