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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8b8d5f63a78b5e98d3791d8d58ea7474ad874325
4
- data.tar.gz: 3cfc66538c6cbaf0792e96ca208712deff1ea194
3
+ metadata.gz: 37d66a474e8d614dd2ccbbf746511e3c4b769ef7
4
+ data.tar.gz: 50e1139f2d69beb50da6e702bd0e20d226f615fa
5
5
  SHA512:
6
- metadata.gz: fe459d02990c355cd440e1460ec8bfac1019a6c3984918d4ee5ea53e9cb8709fd16bcfdf3f29ea3de5b7dbfaca01459143ec6de1294a9d402137e59fafcef1f2
7
- data.tar.gz: 1d91a6c7e3cf0f0e0d7aaba0ba1068f0b74c5d08eca30d9e7541e5f15c066b237552eaab001bfa0cc6510459b07d754036bdd18825016213cd55ceca331d10d9
6
+ metadata.gz: e406c34a0b01b3f839f2ff8e9a688e7a5222ed02203bb0db45fdb03a71f6db5a9d8f9b9c575fa661ae3ce12ed8c7448cc340acea05c042097418eab8bffc498b
7
+ data.tar.gz: 64c3e07d73f2b053c790fb37a3d8f32129f35da594a03fc4a7fe4b6cb66ed15e4e27d1ef83fcd4d5b0e66bd4ce56962aa82bc567717ddaef4878d52eac109d84
data/.gitignore CHANGED
@@ -12,6 +12,7 @@
12
12
  /tmp/
13
13
  /vendor/
14
14
  .DS_Store
15
+ *.bak
15
16
  *.tags
16
17
  tags
17
18
  .srclib-cache/
@@ -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"
@@ -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 'archimate/data_model'
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: weight(rel.type)
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
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Archimate
3
- VERSION = "2.0.0"
3
+ VERSION = "2.0.1"
4
4
  end
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.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-19 00:00:00.000000000 Z
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