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