archimate 2.0.0 → 2.0.1
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 +4 -4
- data/.gitignore +1 -0
- data/archimate.gemspec +0 -1
- data/lib/archimate.rb +2 -1
- data/lib/archimate/data_model/element.rb +3 -0
- data/lib/archimate/data_model/model.rb +6 -6
- data/lib/archimate/data_model/relationship.rb +110 -1
- data/lib/archimate/data_model/relationship_type.rb +2 -0
- data/lib/archimate/derived_relations.rb +95 -0
- data/lib/archimate/export/cypher.rb +1 -22
- data/lib/archimate/export/n_quads.rb +1 -0
- data/lib/archimate/file_formats/sax/archi/connection.rb +1 -1
- data/lib/archimate/version.rb +1 -1
- metadata +3 -3
- data/lib/archimate/data_model/referenceable_collection.rb +0 -201
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37d66a474e8d614dd2ccbbf746511e3c4b769ef7
|
4
|
+
data.tar.gz: 50e1139f2d69beb50da6e702bd0e20d226f615fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e406c34a0b01b3f839f2ff8e9a688e7a5222ed02203bb0db45fdb03a71f6db5a9d8f9b9c575fa661ae3ce12ed8c7448cc340acea05c042097418eab8bffc498b
|
7
|
+
data.tar.gz: 64c3e07d73f2b053c790fb37a3d8f32129f35da594a03fc4a7fe4b6cb66ed15e4e27d1ef83fcd4d5b0e66bd4ce56962aa82bc567717ddaef4878d52eac109d84
|
data/.gitignore
CHANGED
data/archimate.gemspec
CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_runtime_dependency "ruby-progressbar", "~>1.8.1"
|
28
28
|
spec.add_runtime_dependency "parallel", "~> 1.11"
|
29
29
|
spec.add_runtime_dependency "ruby-enum", "~> 0.7.1"
|
30
|
-
# spec.add_runtime_dependency "diff-lcs", "~> 1.3"
|
31
30
|
|
32
31
|
spec.add_development_dependency "bundler"
|
33
32
|
spec.add_development_dependency "rake"
|
data/lib/archimate.rb
CHANGED
@@ -66,12 +66,13 @@ module Archimate
|
|
66
66
|
autoload :FileFormat, 'archimate/file_format'
|
67
67
|
autoload :MaybeIO, 'archimate/maybe_io'
|
68
68
|
autoload :ProgressIndicator, 'archimate/progress_indicator'
|
69
|
+
autoload :DerivedRelations, 'archimate/derived_relations'
|
69
70
|
|
70
71
|
require "archimate/version"
|
71
72
|
require "archimate/config"
|
72
73
|
require "archimate/logging"
|
73
74
|
require "archimate/color"
|
74
|
-
require
|
75
|
+
require "archimate/data_model"
|
75
76
|
|
76
77
|
# Reads the given file and returns the Archimate model
|
77
78
|
#
|
@@ -52,6 +52,7 @@ module Archimate
|
|
52
52
|
end
|
53
53
|
|
54
54
|
# Diagrams that this element is referenced in.
|
55
|
+
# @todo this implementation is broken - in_model no longer exists
|
55
56
|
def diagrams
|
56
57
|
@diagrams ||= in_model.diagrams.select do |diagram|
|
57
58
|
diagram.element_ids.include?(id)
|
@@ -59,6 +60,7 @@ module Archimate
|
|
59
60
|
end
|
60
61
|
|
61
62
|
# Relationships that this element is referenced in.
|
63
|
+
# @todo this implementation is broken - in_model no longer exists
|
62
64
|
def relationships
|
63
65
|
@relationships ||= in_model.relationships.select do |relationship|
|
64
66
|
relationship.source == id || relationship.target == id
|
@@ -70,6 +72,7 @@ module Archimate
|
|
70
72
|
# 2. Child `documentation` (and different `xml:lang` attribute values)
|
71
73
|
# 3. Child `properties`
|
72
74
|
# 4. Any other elements
|
75
|
+
# @todo this implementation is broken - in_model no longer exists
|
73
76
|
def merge(element)
|
74
77
|
super
|
75
78
|
element.diagrams.each { |diagram| diagram.replace(element, self) }
|
@@ -170,6 +170,12 @@ module Archimate
|
|
170
170
|
# end
|
171
171
|
# end
|
172
172
|
|
173
|
+
def make_unique_id
|
174
|
+
unique_id = random_id
|
175
|
+
unique_id = random_id while @index_hash.key?(unique_id)
|
176
|
+
unique_id
|
177
|
+
end
|
178
|
+
|
173
179
|
private
|
174
180
|
|
175
181
|
# Only used by [#find_default_organization]
|
@@ -261,12 +267,6 @@ module Archimate
|
|
261
267
|
ref
|
262
268
|
end
|
263
269
|
|
264
|
-
def make_unique_id
|
265
|
-
unique_id = random_id
|
266
|
-
unique_id = random_id while @index_hash.key?(unique_id)
|
267
|
-
unique_id
|
268
|
-
end
|
269
|
-
|
270
270
|
def random_id
|
271
271
|
@random ||= Random.new
|
272
272
|
format("%08x", @random.rand(0xffffffff))
|
@@ -11,6 +11,26 @@ module Archimate
|
|
11
11
|
# by having a tag name of "relationship" and an attribute of xsi:type="AccessRelationship" where AccessRelationship is
|
12
12
|
# a derived type from RelationshipType.
|
13
13
|
class Relationship
|
14
|
+
# @todo: this should be removed once concrete Relationships are used.
|
15
|
+
# @deprecated
|
16
|
+
WEIGHTS = {
|
17
|
+
'GroupingRelationship' => 0,
|
18
|
+
'JunctionRelationship' => 0,
|
19
|
+
'AssociationRelationship' => 0,
|
20
|
+
'SpecialisationRelationship' => 1,
|
21
|
+
'FlowRelationship' => 2,
|
22
|
+
'TriggeringRelationship' => 3,
|
23
|
+
'InfluenceRelationship' => 4,
|
24
|
+
'AccessRelationship' => 5,
|
25
|
+
'ServingRelationship' => 6,
|
26
|
+
'UsedByRelationship' => 6,
|
27
|
+
'RealizationRelationship' => 7,
|
28
|
+
'RealisationRelationship' => 7,
|
29
|
+
'AssignmentRelationship' => 8,
|
30
|
+
'AggregationRelationship' => 9,
|
31
|
+
'CompositionRelationship' => 10
|
32
|
+
}
|
33
|
+
|
14
34
|
include Comparison
|
15
35
|
|
16
36
|
# @!attribute [r] id
|
@@ -44,9 +64,13 @@ module Archimate
|
|
44
64
|
# @!attribute [r] access_type
|
45
65
|
# @return [AccessTypeEnum, NilClass]
|
46
66
|
model_attr :access_type
|
67
|
+
# @!attribute [r] derived
|
68
|
+
# @return [Boolean] this is a derived relation if true
|
69
|
+
model_attr :derived
|
47
70
|
|
48
71
|
def initialize(id:, name: nil, documentation: nil, type: nil,
|
49
|
-
properties: [], source:, target:, access_type: nil
|
72
|
+
properties: [], source:, target:, access_type: nil,
|
73
|
+
derived: false)
|
50
74
|
@id = id
|
51
75
|
@name = name
|
52
76
|
@documentation = documentation
|
@@ -55,6 +79,7 @@ module Archimate
|
|
55
79
|
@source = source
|
56
80
|
@target = target
|
57
81
|
@access_type = access_type
|
82
|
+
@derived = derived
|
58
83
|
end
|
59
84
|
|
60
85
|
def replace(entity, with_entity)
|
@@ -99,6 +124,90 @@ module Archimate
|
|
99
124
|
super
|
100
125
|
access_type ||= relationship.access_type
|
101
126
|
end
|
127
|
+
|
128
|
+
def weight
|
129
|
+
WEIGHTS.fetch(type, 0)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Relationship Classifications: Structural, Dynamic, Dependency, Other
|
134
|
+
# • No relationships are allowed between two relationships
|
135
|
+
# • All relationships connected with relationship connectors must be of
|
136
|
+
# the same type
|
137
|
+
# • A chain of relationships of the same type that connects two elements,
|
138
|
+
# and is in turn connected via relationship connectors, is valid only if
|
139
|
+
# a direct relationship of that same type between those two elements is
|
140
|
+
# valid
|
141
|
+
# • A relationship connecting an element with a second relationship can
|
142
|
+
# only be an aggregation, composition, or association; aggregation or
|
143
|
+
# composition are valid only from a composite element to that second
|
144
|
+
# relationship
|
145
|
+
#
|
146
|
+
# Aggregation, composition, and specialization relationships are always
|
147
|
+
# permitted between two elements of the same type, and association is
|
148
|
+
# always allowed between any two elements, and between any element and
|
149
|
+
# relationship.
|
150
|
+
|
151
|
+
class Composition < Relationship
|
152
|
+
CLASSIFICATION = :structural
|
153
|
+
WEIGHT = 10
|
154
|
+
end
|
155
|
+
|
156
|
+
class Aggregation < Relationship
|
157
|
+
CLASSIFICATION = :structural
|
158
|
+
WEIGHT = 9
|
159
|
+
end
|
160
|
+
|
161
|
+
class Assignment < Relationship
|
162
|
+
CLASSIFICATION = :structural
|
163
|
+
WEIGHT = 8
|
164
|
+
end
|
165
|
+
|
166
|
+
class Realization < Relationship
|
167
|
+
CLASSIFICATION = :structural
|
168
|
+
WEIGHT = 7
|
169
|
+
end
|
170
|
+
|
171
|
+
class Serving < Relationship
|
172
|
+
CLASSIFICATION = :dependency
|
173
|
+
WEIGHT = 6
|
174
|
+
end
|
175
|
+
|
176
|
+
class Access < Relationship
|
177
|
+
CLASSIFICATION = :dependency
|
178
|
+
WEIGHT = 5
|
179
|
+
end
|
180
|
+
|
181
|
+
class Influence < Relationship
|
182
|
+
CLASSIFICATION = :dependency
|
183
|
+
WEIGHT = 4
|
184
|
+
end
|
185
|
+
|
186
|
+
class Triggering < Relationship
|
187
|
+
CLASSIFICATION = :dynamic
|
188
|
+
WEIGHT = 3
|
189
|
+
end
|
190
|
+
|
191
|
+
class Flow < Relationship
|
192
|
+
CLASSIFICATION = :dynamic
|
193
|
+
WEIGHT = 2
|
194
|
+
end
|
195
|
+
|
196
|
+
class Specialization < Relationship
|
197
|
+
CLASSIFICATION = :other
|
198
|
+
WEIGHT = 1
|
199
|
+
end
|
200
|
+
|
201
|
+
class Association < Relationship
|
202
|
+
CLASSIFICATION = :other
|
203
|
+
WEIGHT = 0
|
204
|
+
end
|
205
|
+
|
206
|
+
# Junction is a relationship connector
|
207
|
+
# • All relationships connected with relationship connectors must be of the same type
|
208
|
+
class Junction < Relationship
|
209
|
+
CLASSIFICATION = :other
|
210
|
+
WEIGHT = 0
|
102
211
|
end
|
103
212
|
end
|
104
213
|
end
|
@@ -12,6 +12,7 @@ module Archimate
|
|
12
12
|
"FlowRelationship" => "flows to",
|
13
13
|
"InfluenceRelationship" => "influenecs",
|
14
14
|
"RealisationRelationship" => "realizes",
|
15
|
+
"RealizationRelationship" => "realizes",
|
15
16
|
"SpecialisationRelationship" => "specializes",
|
16
17
|
"TriggeringRelationship" => "triggers",
|
17
18
|
"UsedByRelationship" => "is used by"
|
@@ -28,6 +29,7 @@ module Archimate
|
|
28
29
|
define :FlowRelationship, "FlowRelationship"
|
29
30
|
define :InfluenceRelationship, "InfluenceRelationship"
|
30
31
|
define :RealisationRelationship, "RealisationRelationship"
|
32
|
+
define :RealizationRelationship, "RealizationRelationship"
|
31
33
|
define :SpecialisationRelationship, "SpecialisationRelationship"
|
32
34
|
define :SpecializationRelationship, "SpecializationRelationship"
|
33
35
|
define :TriggeringRelationship, "TriggeringRelationship"
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Archimate
|
2
|
+
class DerivedRelations
|
3
|
+
PASS_ALL = lambda { |_item| true }
|
4
|
+
FAIL_ALL = lambda { |_item| false }
|
5
|
+
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
end
|
9
|
+
|
10
|
+
# This returns a set of derived relationships in this model between the
|
11
|
+
# elements in the `start_elements` argument, including relationships that
|
12
|
+
# pass the `relationship_filter` recursively until either a target_filter
|
13
|
+
# is matched and/or the stop_filter is matched.
|
14
|
+
#
|
15
|
+
# TODO: Rules for derived relations
|
16
|
+
#
|
17
|
+
# Assumptions:
|
18
|
+
#
|
19
|
+
# 1. If an existing relation exists for found "derived" relation, it shouldn't
|
20
|
+
# be included in the results.
|
21
|
+
# 2. Any path of length 1 inherently identifies an instance of #1 so they can
|
22
|
+
# be skipped.
|
23
|
+
#
|
24
|
+
# @param start_elements [Array<Element>] collection of starting nodes
|
25
|
+
# @param relationship_filter [Boolean, lambda(Relationship) => Boolean]
|
26
|
+
# filter for the kinds of relationships to follow.
|
27
|
+
# @param target_filter [lambda(Element) => Boolean] if true, then a derived
|
28
|
+
# relationship is added to the results
|
29
|
+
# @param stop_filter [lambda(Element) => Boolean] if true, then relationships
|
30
|
+
# below this element are not followed
|
31
|
+
def derived_relations(start_elements, relationship_filter, target_filter, stop_filter = FAIL_ALL)
|
32
|
+
traverse(start_elements, relationship_filter, stop_filter)
|
33
|
+
.reject { |path| Array(path).size <= 1 } # See #2 above
|
34
|
+
.select { |path| target_filter.call(path.last.target) }
|
35
|
+
.map { |path|
|
36
|
+
DataModel::Relationship.new(
|
37
|
+
id: @model.make_unique_id,
|
38
|
+
type: derived_relationship_type(path),
|
39
|
+
source: path.first.source,
|
40
|
+
target: path.last.target,
|
41
|
+
derived: true
|
42
|
+
)
|
43
|
+
}
|
44
|
+
.uniq { |rel| [rel.type, rel.source, rel.target] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def derived_relationship_type(path)
|
48
|
+
DataModel::Relationship::WEIGHTS.rassoc(
|
49
|
+
path
|
50
|
+
.map(&:weight)
|
51
|
+
.min
|
52
|
+
).first
|
53
|
+
end
|
54
|
+
|
55
|
+
# traverse returns an Array of paths (Array<Relationship>)
|
56
|
+
# between each of the start elements and elements that pass the
|
57
|
+
# relation_filter.
|
58
|
+
#
|
59
|
+
# @param start_elements [Array<Element>] initial elements to start the
|
60
|
+
# model traversal
|
61
|
+
# @param relation_filter [Proc(Relationship) => Boolean] only relationships
|
62
|
+
# that pass the relation_filter will be followed
|
63
|
+
# @param stop_filter [Proc(Element) => Boolean] the traversal will not
|
64
|
+
# proceed further than relationship targets that the stop_filter
|
65
|
+
# returns true for.
|
66
|
+
def traverse(start_elements, relation_filter, stop_filter, from_path = [])
|
67
|
+
return [] if from_path.size > 100
|
68
|
+
start_elements.each_with_object([]) do |el, result|
|
69
|
+
immediate_rels = element_relationships(el)
|
70
|
+
.select(&relation_filter)
|
71
|
+
.reject { |rel| from_path.include?(rel) }
|
72
|
+
|
73
|
+
result.concat(immediate_rels)
|
74
|
+
result.concat(
|
75
|
+
*immediate_rels
|
76
|
+
.reject { |rel| rel.target.nil? || (stop_filter && stop_filter.call(rel)) }
|
77
|
+
.map { |rel|
|
78
|
+
traverse([rel.target], relation_filter, stop_filter, from_path + [rel])
|
79
|
+
.map { |path| Array(path).unshift(rel) }
|
80
|
+
}
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def element_by_name(name)
|
86
|
+
@model.elements.find { |el| el.name.to_s == name.to_s }
|
87
|
+
end
|
88
|
+
|
89
|
+
def element_relationships(el)
|
90
|
+
@model
|
91
|
+
.relationships
|
92
|
+
.select { |rel| rel.source.id == el.id }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -46,22 +46,6 @@ module Archimate
|
|
46
46
|
class Cypher
|
47
47
|
attr_reader :output_io
|
48
48
|
|
49
|
-
WEIGHTS = {
|
50
|
-
'GroupingRelationship' => 0,
|
51
|
-
'JunctionRelationship' => 0,
|
52
|
-
'AssociationRelationship' => 0,
|
53
|
-
'SpecialisationRelationship' => 1,
|
54
|
-
'FlowRelationship' => 2,
|
55
|
-
'TriggeringRelationship' => 3,
|
56
|
-
'InfluenceRelationship' => 4,
|
57
|
-
'AccessRelationship' => 5,
|
58
|
-
'UsedByRelationship' => 6,
|
59
|
-
'RealisationRelationship' => 7,
|
60
|
-
'AssignmentRelationship' => 8,
|
61
|
-
'AggregationRelationship' => 9,
|
62
|
-
'CompositionRelationship' => 10
|
63
|
-
}
|
64
|
-
|
65
49
|
def initialize(output_io)
|
66
50
|
@output_io = output_io
|
67
51
|
end
|
@@ -136,11 +120,6 @@ module Archimate
|
|
136
120
|
"(s #{props(nodeId: rel.source)})"
|
137
121
|
end
|
138
122
|
|
139
|
-
def weight(t)
|
140
|
-
return 0 unless WEIGHTS.include?(t)
|
141
|
-
WEIGHTS[t]
|
142
|
-
end
|
143
|
-
|
144
123
|
def add_docs(h, l)
|
145
124
|
t = l.map(&:text).join("\n").strip
|
146
125
|
return h if t.empty?
|
@@ -153,7 +132,7 @@ module Archimate
|
|
153
132
|
name: rel.name.to_s,
|
154
133
|
relationshipId: rel.id,
|
155
134
|
accessType: rel.access_type,
|
156
|
-
weight:
|
135
|
+
weight: rel.weight
|
157
136
|
}, rel.documentation
|
158
137
|
)
|
159
138
|
"[r:#{rel.type} #{props(h)}]"
|
@@ -115,6 +115,7 @@ module Archimate
|
|
115
115
|
"UsedByRelationship" => %w(used_by uses),
|
116
116
|
"ServingRelationship" => %w(serving served_by),
|
117
117
|
"RealisationRelationship" => %w(realizes realized_by),
|
118
|
+
"RealizationRelationship" => %w(realizes realized_by),
|
118
119
|
"AssignmentRelationship" => %w(assigned_to assigned_from),
|
119
120
|
"AggregationRelationship" => %w(aggregates aggregated_by),
|
120
121
|
"CompositionRelationship" => %w(composes composed_by),
|
@@ -32,7 +32,7 @@ module Archimate
|
|
32
32
|
event(:on_referenceable, connection),
|
33
33
|
event(:on_future, Sax::FutureReference.new(connection, :source, @attrs["source"])),
|
34
34
|
event(:on_future, Sax::FutureReference.new(connection, :target, @attrs["target"])),
|
35
|
-
event(:on_future, Sax::FutureReference.new(connection, :relationship, @attrs["relationship"]))
|
35
|
+
event(:on_future, Sax::FutureReference.new(connection, :relationship, @attrs["relationship"] || @attrs["archimateRelationship"]))
|
36
36
|
]
|
37
37
|
end
|
38
38
|
|
data/lib/archimate/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: archimate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Morga
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -445,7 +445,6 @@ files:
|
|
445
445
|
- lib/archimate/data_model/property.rb
|
446
446
|
- lib/archimate/data_model/property_definition.rb
|
447
447
|
- lib/archimate/data_model/referenceable.rb
|
448
|
-
- lib/archimate/data_model/referenceable_collection.rb
|
449
448
|
- lib/archimate/data_model/relationship.rb
|
450
449
|
- lib/archimate/data_model/relationship_type.rb
|
451
450
|
- lib/archimate/data_model/schema_info.rb
|
@@ -453,6 +452,7 @@ files:
|
|
453
452
|
- lib/archimate/data_model/view_node.rb
|
454
453
|
- lib/archimate/data_model/viewpoint.rb
|
455
454
|
- lib/archimate/data_model/viewpoint_type.rb
|
455
|
+
- lib/archimate/derived_relations.rb
|
456
456
|
- lib/archimate/export/csv_export.rb
|
457
457
|
- lib/archimate/export/cypher.rb
|
458
458
|
- lib/archimate/export/graph_ml.rb
|
@@ -1,201 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module Archimate
|
3
|
-
module DataModel
|
4
|
-
# This class represents a collection of referenceable objects (i.e. have an `id`)
|
5
|
-
class ReferenceableCollection
|
6
|
-
attr_writer :parent_attribute_name
|
7
|
-
|
8
|
-
def in_model
|
9
|
-
@in_model if defined?(@in_model)
|
10
|
-
end
|
11
|
-
|
12
|
-
def parent
|
13
|
-
@parent if defined?(@parent)
|
14
|
-
end
|
15
|
-
|
16
|
-
def id
|
17
|
-
object_id.to_s
|
18
|
-
end
|
19
|
-
|
20
|
-
def primitive?
|
21
|
-
false
|
22
|
-
end
|
23
|
-
|
24
|
-
def diff(other)
|
25
|
-
raise TypeError, "Expected other #{other.class} to be of type #{self.class}" unless other.is_a?(self.class)
|
26
|
-
raise "Well Hell other #{other.path} in_model is nil" if other.in_model.nil?
|
27
|
-
raise "Well Hell my path `#{path}` in_model is nil" if in_model.nil?
|
28
|
-
|
29
|
-
result = []
|
30
|
-
remaining_content = Array.new(self) # @todo I want a copy of the array, not a deep clone
|
31
|
-
other_enum = other.each_with_index
|
32
|
-
|
33
|
-
loop do
|
34
|
-
if other_enum.peek[0] == remaining_content[0]
|
35
|
-
other_enum.next
|
36
|
-
remaining_content.shift
|
37
|
-
elsif items_are_changed?(other, other_enum, remaining_content)
|
38
|
-
result.concat(compute_item_changes(other, other_enum, self, remaining_content[0]))
|
39
|
-
remaining_content.shift
|
40
|
-
other_enum.next
|
41
|
-
elsif !remaining_content.empty? && !other.smart_include?(remaining_content[0])
|
42
|
-
result << Diff::Delete.new(Diff::ArchimateArrayReference.new(self, smart_find(remaining_content[0])))
|
43
|
-
remaining_content.shift
|
44
|
-
elsif !smart_include?(other_enum.peek[0])
|
45
|
-
result << Diff::Insert.new(Diff::ArchimateArrayReference.new(other, other_enum.next[1]))
|
46
|
-
elsif smart_include?(other_enum.peek[0])
|
47
|
-
result << Diff::Move.new(
|
48
|
-
Diff::ArchimateArrayReference.new(other, other_enum.peek[1]),
|
49
|
-
Diff::ArchimateArrayReference.new(self, smart_find(other_enum.peek[0]))
|
50
|
-
)
|
51
|
-
remaining_item_idx = remaining_content.smart_find(other_enum.peek[0])
|
52
|
-
if remaining_item_idx
|
53
|
-
result.concat(compute_item_changes(other, other_enum, self, remaining_content[remaining_item_idx]))
|
54
|
-
remaining_content.delete_at(remaining_item_idx) if remaining_content.smart_include?(other_enum.peek[0])
|
55
|
-
end
|
56
|
-
other_enum.next
|
57
|
-
else
|
58
|
-
raise "Unhandled diff case for remaining_content: #{remaining_content[0]} and #{other_enum.peek[0]}"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
result.concat(
|
63
|
-
remaining_content
|
64
|
-
.reject { |item| other.include?(item) }
|
65
|
-
.map do |item|
|
66
|
-
Diff::Delete.new(Diff::ArchimateArrayReference.new(self, find_index(item)))
|
67
|
-
end
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
# @todo This may not continue to live here. Only used by testing.
|
72
|
-
def patch(diffs)
|
73
|
-
# @todo Beware, order of diffs could break patching at the moment.
|
74
|
-
Array(diffs).each do |diff|
|
75
|
-
case diff
|
76
|
-
when Diff::Delete
|
77
|
-
delete_at(smart_find(diff.target.value))
|
78
|
-
when Diff::Insert
|
79
|
-
insert(diff.target.array_index, diff.target.value)
|
80
|
-
when Diff::Change
|
81
|
-
self[smart_find(diff.changed_from.value)] = diff.target.value
|
82
|
-
when Diff::Move
|
83
|
-
insert(diff.target.array_index, delete_at(smart_find(diff.target.value)))
|
84
|
-
else
|
85
|
-
raise "Unexpected diff type: #{diff.class}"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
self
|
89
|
-
end
|
90
|
-
|
91
|
-
def items_are_changed?(other, other_enum, remaining)
|
92
|
-
!remaining.empty? &&
|
93
|
-
case remaining[0]
|
94
|
-
when DataModel::Referenceable
|
95
|
-
remaining[0].id == other_enum.peek[0].id
|
96
|
-
when String, DataModel::ArchimateNode
|
97
|
-
!other.include?(remaining[0]) && !include?(other_enum.peek[0])
|
98
|
-
else
|
99
|
-
raise "Unhandled type for #{remaining[0].class}"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def compute_item_changes(other, other_enum, _myself, my_item)
|
104
|
-
case my_item
|
105
|
-
when DataModel::ArchimateNode
|
106
|
-
my_item.diff(other_enum.peek[0])
|
107
|
-
else
|
108
|
-
my_item.diff(other_enum.peek[0], self, other, other_enum.peek[1], find_index(my_item))
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def in_model=(model)
|
113
|
-
puts "#{self.inspect} is frozen" if self.frozen?
|
114
|
-
@in_model = model
|
115
|
-
each { |item| item.in_model = model }
|
116
|
-
end
|
117
|
-
|
118
|
-
def parent=(par)
|
119
|
-
@parent = par
|
120
|
-
each { |i| i.parent = self }
|
121
|
-
end
|
122
|
-
|
123
|
-
def parent_attribute_name
|
124
|
-
@parent_attribute_name if defined?(@parent_attribute_name)
|
125
|
-
end
|
126
|
-
|
127
|
-
def build_index(hash_index = {})
|
128
|
-
reduce(hash_index) { |hi, array_item| array_item.build_index(hi) }
|
129
|
-
end
|
130
|
-
|
131
|
-
def path(options = {})
|
132
|
-
[
|
133
|
-
parent&.path(options),
|
134
|
-
parent_attribute_name
|
135
|
-
].compact.reject(&:empty?).join("/")
|
136
|
-
end
|
137
|
-
|
138
|
-
def clone
|
139
|
-
map(&:clone)
|
140
|
-
end
|
141
|
-
|
142
|
-
def dup
|
143
|
-
map(&:dup)
|
144
|
-
end
|
145
|
-
|
146
|
-
def to_s
|
147
|
-
"#{parent}/#{parent_attribute_name}"
|
148
|
-
end
|
149
|
-
|
150
|
-
def referenced_identified_nodes
|
151
|
-
reduce([]) do |a, e|
|
152
|
-
a.concat(e.referenced_identified_nodes)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def find_by_id(an_id)
|
157
|
-
find { |el| el.id == an_id }
|
158
|
-
end
|
159
|
-
|
160
|
-
def smart_find(val = nil)
|
161
|
-
case val
|
162
|
-
when Referenceable
|
163
|
-
lazy.map(&:id).find_index(val.id)
|
164
|
-
else
|
165
|
-
find_index(val)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def smart_include?(val)
|
170
|
-
case val
|
171
|
-
when Referenceable
|
172
|
-
lazy.map(&:id).include?(val.id)
|
173
|
-
else
|
174
|
-
include?(val)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def smart_intersection(ary)
|
179
|
-
select { |item| ary.smart_include?(item) }
|
180
|
-
end
|
181
|
-
|
182
|
-
def after(idx)
|
183
|
-
return [] if idx >= size - 1
|
184
|
-
self[idx + 1..-1]
|
185
|
-
end
|
186
|
-
|
187
|
-
# Given a node in self and ary,
|
188
|
-
# return the idx of first node p in self that exists in both self and ary
|
189
|
-
# and is previous to node in self
|
190
|
-
def previous_item_index(ary, node)
|
191
|
-
return -1 unless ary.smart_include?(node)
|
192
|
-
initial_idx = smart_find(node)
|
193
|
-
return -1 if initial_idx.nil?
|
194
|
-
|
195
|
-
(initial_idx - 1).downto(0).find(-> { -1 }) do |idx|
|
196
|
-
ary.smart_include?(at(idx))
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|