Class: Archimate::DataModel::ReferenceableCollection

Inherits:
Object
  • Object
show all
Defined in:
lib/archimate/data_model/referenceable_collection.rb

Overview

This class represents a collection of referenceable objects (i.e. have an ‘id`)

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#parent_attribute_nameObject



123
124
125
# File 'lib/archimate/data_model/referenceable_collection.rb', line 123

def parent_attribute_name
  @parent_attribute_name if defined?(@parent_attribute_name)
end

Instance Method Details

#after(idx) ⇒ Object



182
183
184
185
# File 'lib/archimate/data_model/referenceable_collection.rb', line 182

def after(idx)
  return [] if idx >= size - 1
  self[idx + 1..-1]
end

#build_index(hash_index = {}) ⇒ Object



127
128
129
# File 'lib/archimate/data_model/referenceable_collection.rb', line 127

def build_index(hash_index = {})
  reduce(hash_index) { |hi, array_item| array_item.build_index(hi) }
end

#cloneObject



138
139
140
# File 'lib/archimate/data_model/referenceable_collection.rb', line 138

def clone
  map(&:clone)
end

#compute_item_changes(other, other_enum, _myself, my_item) ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/archimate/data_model/referenceable_collection.rb', line 103

def compute_item_changes(other, other_enum, _myself, my_item)
  case my_item
  when DataModel::ArchimateNode
    my_item.diff(other_enum.peek[0])
  else
    my_item.diff(other_enum.peek[0], self, other, other_enum.peek[1], find_index(my_item))
  end
end

#diff(other) ⇒ Object

Raises:

  • (TypeError)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/archimate/data_model/referenceable_collection.rb', line 24

def diff(other)
  raise TypeError, "Expected other #{other.class} to be of type #{self.class}" unless other.is_a?(self.class)
  raise "Well Hell other #{other.path} in_model is nil" if other.in_model.nil?
  raise "Well Hell my path `#{path}` in_model is nil" if in_model.nil?

  result = []
  remaining_content = Array.new(self) # @todo I want a copy of the array, not a deep clone
  other_enum = other.each_with_index

  loop do
    if other_enum.peek[0] == remaining_content[0]
      other_enum.next
      remaining_content.shift
    elsif items_are_changed?(other, other_enum, remaining_content)
      result.concat(compute_item_changes(other, other_enum, self, remaining_content[0]))
      remaining_content.shift
      other_enum.next
    elsif !remaining_content.empty? && !other.smart_include?(remaining_content[0])
      result << Diff::Delete.new(Diff::ArchimateArrayReference.new(self, smart_find(remaining_content[0])))
      remaining_content.shift
    elsif !smart_include?(other_enum.peek[0])
      result << Diff::Insert.new(Diff::ArchimateArrayReference.new(other, other_enum.next[1]))
    elsif smart_include?(other_enum.peek[0])
      result << Diff::Move.new(
        Diff::ArchimateArrayReference.new(other, other_enum.peek[1]),
        Diff::ArchimateArrayReference.new(self, smart_find(other_enum.peek[0]))
      )
      remaining_item_idx = remaining_content.smart_find(other_enum.peek[0])
      if remaining_item_idx
        result.concat(compute_item_changes(other, other_enum, self, remaining_content[remaining_item_idx]))
        remaining_content.delete_at(remaining_item_idx) if remaining_content.smart_include?(other_enum.peek[0])
      end
      other_enum.next
    else
      raise "Unhandled diff case for remaining_content: #{remaining_content[0]} and #{other_enum.peek[0]}"
    end
  end

  result.concat(
    remaining_content
      .reject { |item| other.include?(item) }
      .map do |item|
        Diff::Delete.new(Diff::ArchimateArrayReference.new(self, find_index(item)))
      end
  )
end

#dupObject



142
143
144
# File 'lib/archimate/data_model/referenceable_collection.rb', line 142

def dup
  map(&:dup)
end

#find_by_id(an_id) ⇒ Object



156
157
158
# File 'lib/archimate/data_model/referenceable_collection.rb', line 156

def find_by_id(an_id)
  find { |el| el.id == an_id }
end

#idObject



16
17
18
# File 'lib/archimate/data_model/referenceable_collection.rb', line 16

def id
  object_id.to_s
end

#in_modelObject



8
9
10
# File 'lib/archimate/data_model/referenceable_collection.rb', line 8

def in_model
  @in_model if defined?(@in_model)
end

#in_model=(model) ⇒ Object



112
113
114
115
116
# File 'lib/archimate/data_model/referenceable_collection.rb', line 112

def in_model=(model)
  puts "#{self.inspect} is frozen" if self.frozen?
  @in_model = model
  each { |item| item.in_model = model }
end

#items_are_changed?(other, other_enum, remaining) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
94
95
96
97
98
99
100
101
# File 'lib/archimate/data_model/referenceable_collection.rb', line 91

def items_are_changed?(other, other_enum, remaining)
  !remaining.empty? &&
    case remaining[0]
    when DataModel::Referenceable
      remaining[0].id == other_enum.peek[0].id
    when String, DataModel::ArchimateNode
      !other.include?(remaining[0]) && !include?(other_enum.peek[0])
    else
      raise "Unhandled type for #{remaining[0].class}"
    end
end

#parentObject



12
13
14
# File 'lib/archimate/data_model/referenceable_collection.rb', line 12

def parent
  @parent if defined?(@parent)
end

#parent=(par) ⇒ Object



118
119
120
121
# File 'lib/archimate/data_model/referenceable_collection.rb', line 118

def parent=(par)
  @parent = par
  each { |i| i.parent = self }
end

#patch(diffs) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/archimate/data_model/referenceable_collection.rb', line 72

def patch(diffs)
  # @todo Beware, order of diffs could break patching at the moment.
  Array(diffs).each do |diff|
    case diff
    when Diff::Delete
      delete_at(smart_find(diff.target.value))
    when Diff::Insert
      insert(diff.target.array_index, diff.target.value)
    when Diff::Change
      self[smart_find(diff.changed_from.value)] = diff.target.value
    when Diff::Move
      insert(diff.target.array_index, delete_at(smart_find(diff.target.value)))
    else
      raise "Unexpected diff type: #{diff.class}"
    end
  end
  self
end

#path(options = {}) ⇒ Object



131
132
133
134
135
136
# File 'lib/archimate/data_model/referenceable_collection.rb', line 131

def path(options = {})
  [
    parent&.path(options),
    parent_attribute_name
  ].compact.reject(&:empty?).join("/")
end

#previous_item_index(ary, node) ⇒ Object

Given a node in self and ary, return the idx of first node p in self that exists in both self and ary and is previous to node in self



190
191
192
193
194
195
196
197
198
# File 'lib/archimate/data_model/referenceable_collection.rb', line 190

def previous_item_index(ary, node)
  return -1 unless ary.smart_include?(node)
  initial_idx = smart_find(node)
  return -1 if initial_idx.nil?

  (initial_idx - 1).downto(0).find(-> { -1 }) do |idx|
    ary.smart_include?(at(idx))
  end
end

#primitive?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/archimate/data_model/referenceable_collection.rb', line 20

def primitive?
  false
end

#referenced_identified_nodesObject



150
151
152
153
154
# File 'lib/archimate/data_model/referenceable_collection.rb', line 150

def referenced_identified_nodes
  reduce([]) do |a, e|
    a.concat(e.referenced_identified_nodes)
  end
end

#smart_find(val = nil) ⇒ Object



160
161
162
163
164
165
166
167
# File 'lib/archimate/data_model/referenceable_collection.rb', line 160

def smart_find(val = nil)
  case val
  when Referenceable
    lazy.map(&:id).find_index(val.id)
  else
    find_index(val)
  end
end

#smart_include?(val) ⇒ Boolean

Returns:

  • (Boolean)


169
170
171
172
173
174
175
176
# File 'lib/archimate/data_model/referenceable_collection.rb', line 169

def smart_include?(val)
  case val
  when Referenceable
    lazy.map(&:id).include?(val.id)
  else
    include?(val)
  end
end

#smart_intersection(ary) ⇒ Object



178
179
180
# File 'lib/archimate/data_model/referenceable_collection.rb', line 178

def smart_intersection(ary)
  select { |item| ary.smart_include?(item) }
end

#to_sObject



146
147
148
# File 'lib/archimate/data_model/referenceable_collection.rb', line 146

def to_s
  "#{parent}/#{parent_attribute_name}"
end