archimate 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -1
  3. data/Gemfile +1 -0
  4. data/README.md +10 -55
  5. data/Rakefile +19 -1
  6. data/archimate.gemspec +16 -14
  7. data/bin/archimate +12 -0
  8. data/lib/archimate/cli/archi.rb +38 -19
  9. data/lib/archimate/cli/cleanup.rb +41 -25
  10. data/lib/archimate/cli/duper.rb +0 -1
  11. data/lib/archimate/cli/mapper.rb +53 -40
  12. data/lib/archimate/cli/svger.rb +33 -4
  13. data/lib/archimate/core_refinements.rb +41 -0
  14. data/lib/archimate/data_model/bounds.rb +14 -4
  15. data/lib/archimate/data_model/comparison.rb +3 -27
  16. data/lib/archimate/data_model/connection.rb +26 -11
  17. data/lib/archimate/data_model/diagram.rb +17 -10
  18. data/lib/archimate/data_model/element.rb +21 -9
  19. data/lib/archimate/data_model/elements.rb +24 -18
  20. data/lib/archimate/data_model/lang_string.rb +34 -10
  21. data/lib/archimate/data_model/layer.rb +6 -0
  22. data/lib/archimate/data_model/location.rb +10 -13
  23. data/lib/archimate/data_model/model.rb +55 -43
  24. data/lib/archimate/data_model/organization.rb +21 -5
  25. data/lib/archimate/data_model/property.rb +0 -6
  26. data/lib/archimate/data_model/referenceable.rb +29 -3
  27. data/lib/archimate/data_model/referenceable_list.rb +34 -14
  28. data/lib/archimate/data_model/relationship.rb +29 -8
  29. data/lib/archimate/data_model/relationship_references.rb +115 -6
  30. data/lib/archimate/data_model/relationships.rb +15 -0
  31. data/lib/archimate/data_model/view_node.rb +20 -13
  32. data/lib/archimate/data_model/viewpoint.rb +13 -1
  33. data/lib/archimate/data_model/viewpoints.rb +416 -0
  34. data/lib/archimate/data_model.rb +7 -1
  35. data/lib/archimate/derived_relations.rb +2 -11
  36. data/lib/archimate/export/cypher.rb +6 -5
  37. data/lib/archimate/file_format.rb +1 -0
  38. data/lib/archimate/file_formats/archi_file_reader.rb +11 -1
  39. data/lib/archimate/file_formats/archi_file_writer.rb +15 -46
  40. data/lib/archimate/file_formats/archi_file_writer_4.rb +14 -0
  41. data/lib/archimate/file_formats/model_exchange_file_reader.rb +2 -1
  42. data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +1 -0
  43. data/lib/archimate/file_formats/sax/archi/diagram.rb +53 -13
  44. data/lib/archimate/file_formats/sax/archi/location.rb +1 -3
  45. data/lib/archimate/file_formats/sax/model_exchange_file/diagram.rb +13 -2
  46. data/lib/archimate/file_formats/sax.rb +1 -0
  47. data/lib/archimate/file_formats/serializer/archi/archi_file_writer.rb +63 -0
  48. data/lib/archimate/file_formats/serializer/archi/archi_file_writer_3.rb +18 -0
  49. data/lib/archimate/file_formats/serializer/archi/archi_file_writer_4.rb +18 -0
  50. data/lib/archimate/file_formats/serializer/archi/bounds.rb +2 -2
  51. data/lib/archimate/file_formats/serializer/archi/connection.rb +24 -13
  52. data/lib/archimate/file_formats/serializer/archi/diagram.rb +3 -3
  53. data/lib/archimate/file_formats/serializer/archi/element.rb +2 -2
  54. data/lib/archimate/file_formats/serializer/archi/organization.rb +1 -1
  55. data/lib/archimate/file_formats/serializer/archi/property.rb +1 -1
  56. data/lib/archimate/file_formats/serializer/archi/relationship.rb +2 -2
  57. data/lib/archimate/file_formats/serializer/archi/view_node.rb +20 -22
  58. data/lib/archimate/file_formats/serializer/archi/viewpoint3.rb +43 -0
  59. data/lib/archimate/file_formats/serializer/archi/viewpoint4.rb +41 -0
  60. data/lib/archimate/file_formats/serializer/model_exchange_file/style.rb +3 -7
  61. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/diagram.rb +3 -3
  62. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/model.rb +9 -2
  63. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/view_node.rb +1 -1
  64. data/lib/archimate/file_formats/serializer/model_exchange_file/v21/viewpoint.rb +23 -0
  65. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/diagram.rb +3 -3
  66. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/model.rb +5 -7
  67. data/lib/archimate/file_formats/serializer/model_exchange_file/v30/view_node.rb +3 -3
  68. data/lib/archimate/file_formats/serializer/writer.rb +0 -5
  69. data/lib/archimate/file_formats/serializer.rb +6 -2
  70. data/lib/archimate/lint/duplicate_entities.rb +5 -5
  71. data/lib/archimate/lint/linter.rb +4 -4
  72. data/lib/archimate/maybe_io.rb +3 -2
  73. data/lib/archimate/svg/archimate.css +19 -21
  74. data/lib/archimate/svg/connection.rb +1 -1
  75. data/lib/archimate/svg/diagram.rb +1 -6
  76. data/lib/archimate/svg/entity/application_component.rb +9 -3
  77. data/lib/archimate/svg/entity/constraint.rb +0 -1
  78. data/lib/archimate/svg/entity/contract.rb +9 -0
  79. data/lib/archimate/svg/entity/data_entity.rb +1 -1
  80. data/lib/archimate/svg/entity/device.rb +1 -1
  81. data/lib/archimate/svg/entity/event_entity.rb +24 -7
  82. data/lib/archimate/svg/entity/group.rb +23 -4
  83. data/lib/archimate/svg/entity/grouping.rb +37 -0
  84. data/lib/archimate/svg/entity/interface_entity.rb +1 -1
  85. data/lib/archimate/svg/entity/node.rb +1 -1
  86. data/lib/archimate/svg/entity/outcome.rb +0 -1
  87. data/lib/archimate/svg/entity/principle.rb +0 -1
  88. data/lib/archimate/svg/entity/process_entity.rb +1 -1
  89. data/lib/archimate/svg/entity/requirement.rb +0 -1
  90. data/lib/archimate/svg/entity/service_entity.rb +6 -13
  91. data/lib/archimate/svg/entity.rb +1 -0
  92. data/lib/archimate/svg/entity_factory.rb +9 -5
  93. data/lib/archimate/svg/path.rb +57 -46
  94. data/lib/archimate/svg/point.rb +4 -0
  95. data/lib/archimate/svg/segment.rb +30 -0
  96. data/lib/archimate/svg/svg_template.svg.erb +11 -3
  97. data/lib/archimate/svg/view_node.rb +22 -0
  98. data/lib/archimate/version.rb +1 -1
  99. data/lib/archimate.rb +3 -2
  100. metadata +54 -54
  101. data/exe/archidiff +0 -7
  102. data/exe/archidiff-summary +0 -7
  103. data/exe/archimerge +0 -7
  104. data/exe/fmtxml +0 -7
  105. data/lib/archimate/data_model/viewpoint_type.rb +0 -389
  106. data/lib/archimate/file_formats/serializer/archi/location.rb +0 -26
  107. data/lib/archimate/file_formats/serializer/archi/viewpoint_type.rb +0 -45
  108. data/lib/archimate/svg/child.rb +0 -29
@@ -22,6 +22,15 @@ module Archimate
22
22
  Archimate::DataModel::Bounds.new(x: 0, y: 0, width: 0, height: 0)
23
23
  end
24
24
 
25
+ def self.from_location(location)
26
+ DataModel::Bounds.new(
27
+ x: location.x,
28
+ y: location.y,
29
+ width: 0,
30
+ height: 0
31
+ )
32
+ end
33
+
25
34
  def initialize(x: nil, y: nil, width:, height:)
26
35
  raise "Width expected" unless width
27
36
  raise "Height expected" unless height
@@ -68,19 +77,19 @@ module Archimate
68
77
  )
69
78
  end
70
79
 
71
- def is_above?(other)
80
+ def above?(other)
72
81
  bottom < other.top
73
82
  end
74
83
 
75
- def is_below?(other)
84
+ def below?(other)
76
85
  top > other.bottom
77
86
  end
78
87
 
79
- def is_right_of?(other)
88
+ def right_of?(other)
80
89
  left > other.right
81
90
  end
82
91
 
83
- def is_left_of?(other)
92
+ def left_of?(other)
84
93
  right < other.left
85
94
  end
86
95
 
@@ -88,6 +97,7 @@ module Archimate
88
97
  Bounds.new(x: left + val, y: top + val, width: width - val * 2, height: height - val * 2)
89
98
  end
90
99
 
100
+ # Tests if this bounds is inside the argument Bounds
91
101
  def inside?(other)
92
102
  left > other.left &&
93
103
  right < other.right &&
@@ -78,18 +78,12 @@ module Archimate
78
78
  end
79
79
  end
80
80
 
81
- # @todo implement inspect as a more normal inspect with correct handling for
82
- # attr_info values for comparison_attr
83
81
  def inspect
84
82
  "#<#{self.class.to_s.split('::').last}\n " +
85
83
  self.class.attr_info
86
84
  .map { |sym, info| info.attr_inspect(self, sym) }
87
85
  .compact
88
- .join("\n ") + "\n >"
89
- end
90
-
91
- def brief_inspect
92
- "#<#{self.class.to_s.split('::').last}#{" id=#{id}" if respond_to?(:id)}#{" #{name.brief_inspect}" if respond_to?(:name) && name}>"
86
+ .join(" ") + ">"
93
87
  end
94
88
 
95
89
  def self.included(base)
@@ -103,29 +97,11 @@ module Archimate
103
97
  when :no_compare
104
98
  nil
105
99
  when nil
106
- "#{sym}: #{attr_value_inspect(obj.send(sym))}"
100
+ "#{sym}: #{obj.send(sym).inspect}"
107
101
  else
108
102
  val = obj.send(sym)
109
103
  cval = val&.send(comparison_attr)
110
- "#{sym}: #<#{val.class.to_s.split('::').last} #{comparison_attr}=#{attr_value_inspect(cval)}>"
111
- end
112
- end
113
-
114
- def attr_value_inspect(val)
115
- case val
116
- when Comparison
117
- val.brief_inspect
118
- when Array
119
- vals = val.first(3).map do |v|
120
- if v.is_a?(Comparison)
121
- v.brief_inspect
122
- else
123
- v.inspect
124
- end
125
- end
126
- "[#{vals.join(', ')}#{"...#{val.size}" if val.size > 3}]"
127
- else
128
- val.inspect
104
+ "#{sym}: #<#{val.class.to_s.split('::').last} #{comparison_attr}=#{cval.inspect}>"
129
105
  end
130
106
  end
131
107
  end
@@ -92,8 +92,20 @@ module Archimate
92
92
  ].compact.join(" ")
93
93
  end
94
94
 
95
- def referenced_identified_nodes
96
- [@source, @target, @relationship].compact
95
+ def start_location
96
+ source_attachment || source_bounds.center
97
+ end
98
+
99
+ def end_location
100
+ target_attachment || target_bounds.center
101
+ end
102
+
103
+ def source_bounds
104
+ source.absolute_position
105
+ end
106
+
107
+ def target_bounds
108
+ target.absolute_position
97
109
  end
98
110
 
99
111
  # This is used when rendering a connection to connection relationship.
@@ -101,17 +113,20 @@ module Archimate
101
113
  []
102
114
  end
103
115
 
104
- # TODO: Is this true for all or only Archi models?
105
116
  def absolute_position
106
- # offset = bounds || Archimate::DataModel::Bounds.zero
107
- offset = Archimate::DataModel::Bounds.zero
108
- el = parent.parent
109
- while el.respond_to?(:bounds) && el.bounds
110
- bounds = el.bounds
111
- offset = offset.with(x: (offset.x || 0) + (bounds.x || 0), y: (offset.y || 0) + (bounds.y || 0))
112
- el = el.parent.parent
117
+ pt = Svg::Path.new(self).midpoint
118
+ Bounds.new(x: pt.x, y: pt.y, width: 0, height: 0)
119
+ end
120
+
121
+ def replace_item_with(item, replacement)
122
+ super
123
+ item.remove_reference(self)
124
+ case item
125
+ when relationship
126
+ @relationship = replacement
127
+ else
128
+ raise "Trying to replace #{item} that I don't reference"
113
129
  end
114
- offset
115
130
  end
116
131
  end
117
132
  end
@@ -26,10 +26,6 @@ module Archimate
26
26
  # @!attribute [rw] properties
27
27
  # @return [Array<Property>]
28
28
  model_attr :properties, writable: true, default: []
29
- # @todo make this a ViewpointType is better but is Archimate specification version dependent
30
- # @!attribute [r] viewpoint_type
31
- # @return [String, NilClass]
32
- model_attr :viewpoint_type, default: nil
33
29
  # @!attribute [r] viewpoint
34
30
  # @return [Viewpoint, NilClass]
35
31
  model_attr :viewpoint, default: nil
@@ -73,14 +69,25 @@ module Archimate
73
69
  end
74
70
 
75
71
  def total_viewpoint?
76
- viewpoint_type.nil? || viewpoint_type.empty?
72
+ viewpoint.nil?
77
73
  end
78
74
 
79
- def referenced_identified_nodes
80
- (nodes.to_ary + connections)
81
- .map(&:referenced_identified_nodes)
82
- .flatten
83
- .uniq
75
+ def viewpoint_description
76
+ case viewpoint
77
+ when Symbol
78
+ viewpoint.to_s
79
+ when Viewpoint
80
+ viewpoint.name.to_s
81
+ else
82
+ case type
83
+ when "canvas:CanvasModel"
84
+ "Canvas"
85
+ when "archimate:SketchModel"
86
+ "Sketch"
87
+ else
88
+ "Total"
89
+ end
90
+ end
84
91
  end
85
92
  end
86
93
  end
@@ -22,10 +22,12 @@ module Archimate
22
22
  # @!attribute [rw] documentation
23
23
  # @return [PreservedLangString, NilClass]
24
24
  model_attr :documentation, writable: true, default: nil
25
- # # @return [Array<AnyElement>]
26
- # model_attr :other_elements
27
- # # @return [Array<AnyAttribute>]
28
- # model_attr :other_attributes
25
+ # @!attribute [r] other_elements
26
+ # @return [Array<AnyElement>]
27
+ model_attr :other_elements, default: []
28
+ # @!attribute [r] other_attributes
29
+ # @return [Array<AnyAttribute>]
30
+ model_attr :other_attributes, default: []
29
31
  # @!attribute [r] properties
30
32
  # @return [Array<Property>]
31
33
  model_attr :properties, default: []
@@ -51,12 +53,22 @@ module Archimate
51
53
  # 2. Child `documentation` (and different `xml:lang` attribute values)
52
54
  # 3. Child `properties`
53
55
  # 4. Any other elements
54
- # @todo this implementation is broken - in_model no longer exists
55
56
  def merge(element)
56
- super
57
- element.diagrams.each { |diagram| diagram.replace(element, self) }
58
- element.relationships.each { |relationship| relationship.replace(element, self) }
59
- element.organization.remove(element.id)
57
+ if !documentation
58
+ self.documentation = element.documentation
59
+ elsif documentation != element.documentation
60
+ documentation.merge(element.documentation)
61
+ end
62
+ element.properties.each do |property|
63
+ unless properties.find { |my_prop| my_prop.property_definition.name == property.property_definition.name && my_prop.value == property.value}
64
+ properties << property
65
+ end
66
+ end
67
+ end
68
+
69
+ # Diagrams that this entity is referenced in.
70
+ def diagrams
71
+ references.select { |ref| ref.is_a?(Diagram) }
60
72
  end
61
73
  end
62
74
  end
@@ -115,15 +115,6 @@ module Archimate
115
115
  end
116
116
  end
117
117
 
118
- class Meaning < Element
119
- CLASSIFICATION = :passive_structure
120
- LAYER = Layers::Business
121
-
122
- def initialize(args)
123
- super
124
- end
125
- end
126
-
127
118
  class Product < Element
128
119
  CLASSIFICATION = :passive_structure
129
120
  LAYER = Layers::Business
@@ -142,15 +133,6 @@ module Archimate
142
133
  end
143
134
  end
144
135
 
145
- class Value < Element
146
- CLASSIFICATION = :passive_structure
147
- LAYER = Layers::Business
148
-
149
- def initialize(args)
150
- super
151
- end
152
- end
153
-
154
136
  #############################################################
155
137
  # Application Layer
156
138
  #############################################################
@@ -491,6 +473,15 @@ module Archimate
491
473
  end
492
474
  end
493
475
 
476
+ class Meaning < Element
477
+ CLASSIFICATION = :passive_structure
478
+ LAYER = Layers::Motivation
479
+
480
+ def initialize(args)
481
+ super
482
+ end
483
+ end
484
+
494
485
  class Outcome < Element
495
486
  CLASSIFICATION = :active_structure
496
487
  LAYER = Layers::Motivation
@@ -527,6 +518,15 @@ module Archimate
527
518
  end
528
519
  end
529
520
 
521
+ class Value < Element
522
+ CLASSIFICATION = :passive_structure
523
+ LAYER = Layers::Motivation
524
+
525
+ def initialize(args)
526
+ super
527
+ end
528
+ end
529
+
530
530
  #############################################################
531
531
  # Implementation and Migration Layer
532
532
  #############################################################
@@ -676,6 +676,12 @@ module Archimate
676
676
  def self.classes
677
677
  constants.map { |cls_name| const_get(cls_name) }
678
678
  end
679
+
680
+ def self.core_elements
681
+ classes.select do |el|
682
+ [Layers::Business, Layers::Application, Layers::Technology].include?(el::LAYER)
683
+ end
684
+ end
679
685
  end
680
686
  end
681
687
  end
@@ -6,6 +6,7 @@ module Archimate
6
6
  module DataModel
7
7
  # A base string type for multi-language strings.
8
8
  class LangString
9
+ include Comparable
9
10
  include Comparison
10
11
  extend Forwardable
11
12
 
@@ -23,16 +24,18 @@ module Archimate
23
24
 
24
25
  def self.string(str, lang = nil)
25
26
  return nil if !str || str.strip.empty?
26
- new(str, lang)
27
+ new(str, default_lang: lang)
27
28
  end
28
29
 
29
- # @param [Hash{Symbol => Object},LangString, String] attributes
30
+ # @param str [String, LangString] optional shortcut to set define this LangString
31
+ # @param lang_hash [Hash{Symbol => Object}] attributes
32
+ # @param default_lang [String] optional setting of the default language
30
33
  # @raise [Struct::Error] if the given attributes don't conform {#schema}
31
34
  # with given {# # constructor_type}
32
- def initialize(str = nil, lang = nil, lang_hash: {}, default_lang: nil, default_text: nil)
35
+ def initialize(str = nil, lang_hash: {}, default_lang: nil)
33
36
  @lang_hash = lang_hash
34
- @default_lang = default_lang || lang
35
- @default_text = default_text
37
+ @default_lang = default_lang || lang_hash.keys.first
38
+ @default_text = str || lang_hash.fetch(@default_lang, nil)
36
39
  case str
37
40
  when String
38
41
  @lang_hash[@default_lang] = @default_text = str.strip
@@ -41,7 +44,7 @@ module Archimate
41
44
  @default_lang = str.default_lang
42
45
  @default_text = str.default_text
43
46
  else
44
- @lang_hash[default_lang] = default_text if default_text
47
+ @lang_hash[default_lang] = @default_text if @default_text
45
48
  end
46
49
  end
47
50
 
@@ -59,10 +62,6 @@ module Archimate
59
62
  end
60
63
  end
61
64
 
62
- def brief_inspect
63
- "#{to_s.slice(0, 40).inspect}#{'...' if to_s.size > 40}"
64
- end
65
-
66
65
  def by_lang(lang)
67
66
  lang_hash.fetch(lang, nil)
68
67
  end
@@ -75,6 +74,14 @@ module Archimate
75
74
  default_lang
76
75
  end
77
76
 
77
+ def ==(other)
78
+ if other.is_a?(String)
79
+ to_s == other
80
+ else
81
+ super
82
+ end
83
+ end
84
+
78
85
  def =~(other)
79
86
  str = to_s
80
87
  if other.is_a?(Regexp)
@@ -83,6 +90,23 @@ module Archimate
83
90
  Regexp.new(Regexp.escape(str)) =~ other
84
91
  end
85
92
  end
93
+
94
+ def <=>(other)
95
+ to_s <=> other.to_s
96
+ end
97
+
98
+ def merge(other)
99
+ return unless other
100
+ other.lang_hash.each do |k, v|
101
+ if @lang_hash.include?(k)
102
+ @lang_hash[k] = [@lang_hash[k], v].join("\n") if @lang_hash[k] != other.lang_hash[k]
103
+ else
104
+ @lang_hash[k] = v
105
+ end
106
+ end
107
+ @default_lang = @default_lang || other.default_lang || @lang_hash.keys.first
108
+ @default_text = @lang_hash[@default_lang]
109
+ end
86
110
  end
87
111
  end
88
112
  end
@@ -5,6 +5,8 @@ require "ruby-enum"
5
5
  module Archimate
6
6
  module DataModel
7
7
  class Layer
8
+ include Comparable
9
+
8
10
  attr_reader :name
9
11
  attr_reader :background_class
10
12
 
@@ -37,6 +39,10 @@ module Archimate
37
39
  @symbol == other&.to_sym
38
40
  end
39
41
 
42
+ def <=>(other)
43
+ Layers.find_index(self) <=> Layers.find_index(other)
44
+ end
45
+
40
46
  def to_sym
41
47
  @symbol
42
48
  end
@@ -16,32 +16,29 @@ module Archimate
16
16
  # @note the XSD has this as a NonNegativeInteger
17
17
  # @!attribute [r] x
18
18
  # @return [Float]
19
- model_attr :x
19
+ model_attr :x, writable: true
20
20
  # The y (towards the bottom, associated with height) attribute from the Top,Left (i.e. 0,0)
21
21
  # corner of the diagram to the Top, Left corner of the bounding box of the concept.
22
22
  # @note the XSD has this as a NonNegativeInteger
23
23
  # @!attribute [r] y
24
24
  # @return [Float]
25
- model_attr :y
25
+ model_attr :y, writable: true
26
26
 
27
- # These are holdovers from the archi file format and are only maintained for compatability
28
- # @!attribute [r] end_x
29
- # @return [Int, NilClass]
30
- model_attr :end_x, default: nil
31
- # @!attribute [r] end_y
32
- # @return [Int, NilClass]
33
- model_attr :end_y, default: nil
34
-
35
- def initialize(x:, y:, end_x: nil, end_y: nil)
27
+ def initialize(x:, y:)
36
28
  @x = x.to_i
37
29
  @y = y.to_i
38
- @end_x = end_x.nil? ? nil : end_x.to_i
39
- @end_y = end_y.nil? ? nil : end_y.to_i
40
30
  end
41
31
 
42
32
  def to_s
43
33
  "Location(x: #{x}, y: #{y})"
44
34
  end
35
+
36
+ # Returns true if this location is inside the bounds argument
37
+ # @param bounds [Bounds]
38
+ def inside?(bounds)
39
+ bounds.x_range.cover?(x) &&
40
+ bounds.y_range.cover?(y)
41
+ end
45
42
  end
46
43
  end
47
44
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ using Archimate::CoreRefinements
4
+
3
5
  module Archimate
4
6
  module DataModel
5
7
  # This is the root model type.
@@ -116,45 +118,65 @@ module Archimate
116
118
  self
117
119
  end
118
120
 
119
- # Only used by [Diff::DeletedItemsReferencedConflict]
120
- def referenced_identified_nodes
121
- classes = [Diagram, ViewNode, Connection, Organization, Relationship].freeze
122
- @index_hash
123
- .values
124
- .select { |entity| classes.include?(entity.class) }
125
- .map(&:referenced_identified_nodes)
126
- .flatten
127
- .uniq
121
+ # @todo this should move into either Comparison or a Mergeable class
122
+ # Steps to merge
123
+ # merge attributes of each copy into master_entity
124
+ # update references of each copy to reference master_entity instead (where it makes sense)
125
+ # remove reference of each copy from its references
126
+ def merge_entities(master_entity, copies)
127
+ copies.delete(master_entity)
128
+ copies.each do |copy|
129
+ master_entity.merge(copy)
130
+ copy.replace_with(master_entity)
131
+ # if !copy.references.empty?
132
+ # puts "#{copy.class} still referenced by #{copy.references.map { |ref| ref.class.name }.join(", ")}"
133
+ # end
134
+ deregister(copy)
135
+ end
128
136
  end
129
137
 
130
- # This is used only by the model [Cli::Cleanup] class.
131
- def unreferenced_nodes
132
- identified_nodes - referenced_identified_nodes
138
+ def replace_item_with(item, replacement)
139
+ case item
140
+ when Organization
141
+ organizations.delete(item)
142
+ organizations << replacement
143
+ when Element
144
+ elements.delete(item)
145
+ elements << replacement
146
+ when Relationship
147
+ relationships.delete(item)
148
+ relationships << replacement
149
+ end
133
150
  end
134
151
 
135
- # def merge_entities(master_entity, copies)
136
- # copies.delete(master_entity)
137
- # copies.each do |copy|
138
- # entities.each do |entity|
139
- # case entity
140
- # when entity == master_entity
141
- # master_entity.merge(copy)
142
- # when Organization
143
- # entity.remove(copy.id)
144
- # when ViewNode, Relationship, Connection
145
- # entity.replace(copy, master_entity)
146
- # end
147
- # end
148
- # deregister(copy)
149
- # end
150
- # end
151
-
152
152
  def make_unique_id
153
- unique_id = random_id
154
- unique_id = random_id while @index_hash.key?(unique_id)
153
+ @random ||= Random.new
154
+ begin
155
+ unique_id = format("%08x", @random.rand(0xffffffff))
156
+ end until !@index_hash.key?(unique_id)
155
157
  unique_id
156
158
  end
157
159
 
160
+ def remove_reference(item)
161
+ case item
162
+ when Element
163
+ elements.delete(item)
164
+ when Relationship
165
+ relationships.delete(item)
166
+ when Diagram
167
+ diagrams.delete(item)
168
+ else
169
+ raise "Unhandled remove reference for type #{item.class}"
170
+ end
171
+ organizations.each { |org| org.remove_reference(item) }
172
+ end
173
+
174
+ Elements.classes.each do |el_cls|
175
+ define_method(el_cls.name.split("::").last.snake_case + "s") do
176
+ elements.select { |el| el.is_a?(el_cls) }
177
+ end
178
+ end
179
+
158
180
  private
159
181
 
160
182
  # Only used by [#find_default_organization]
@@ -233,12 +255,7 @@ module Archimate
233
255
  find_by_class(DataModel::Organization).select { |f| f.items.include?(item) }.first
234
256
  end
235
257
 
236
- # Only used by [#unreferenced_nodes]
237
- def identified_nodes
238
- @index_hash.values.select { |node| node.respond_to? :id }
239
- end
240
-
241
- # @todo make this private - maybe move to [Organization]
258
+ # @todo maybe move to [Organization]
242
259
  def index_organizations(ref)
243
260
  ref.organizations.each do |org|
244
261
  @index_hash[org.id] = index_organizations(org)
@@ -246,7 +263,7 @@ module Archimate
246
263
  ref
247
264
  end
248
265
 
249
- # @todo make this private - maybe move to [ViewNode]
266
+ # @todo maybe move to [ViewNode]
250
267
  def index_view_nodes(ref)
251
268
  ref.nodes.each do |node|
252
269
  @index_hash[node.id] = index_view_nodes(node)
@@ -255,11 +272,6 @@ module Archimate
255
272
  ref
256
273
  end
257
274
 
258
- def random_id
259
- @random ||= Random.new
260
- format("%08x", @random.rand(0xffffffff))
261
- end
262
-
263
275
  def register(node, _parent)
264
276
  @index_hash[node.id] = node
265
277
  end
@@ -48,14 +48,30 @@ module Archimate
48
48
  "#{Archimate::Color.data_model('Organization')}<#{id}>[#{Archimate::Color.color(name, %i[white underline])}]"
49
49
  end
50
50
 
51
- def referenced_identified_nodes
52
- organizations.reduce(items) do |a, e|
53
- a.to_ary + e.referenced_identified_nodes
51
+ def remove(id)
52
+ items.delete_if { |item| item.id == id }
53
+ end
54
+
55
+ def remove_reference(item)
56
+ super
57
+ case item
58
+ when Organization
59
+ organizations.delete(item)
60
+ else
61
+ items.delete(item)
62
+ organizations.each { |org| org.remove_reference(item) }
54
63
  end
55
64
  end
56
65
 
57
- def remove(id)
58
- items.delete_if { |item| item.id == id }
66
+ def replace_item_with(item, replacement)
67
+ case item
68
+ when Organization
69
+ organizations.delete(item)
70
+ organizations << replacement
71
+ else
72
+ items.delete(item)
73
+ items << replacement
74
+ end
59
75
  end
60
76
  end
61
77
  end
@@ -21,12 +21,6 @@ module Archimate
21
21
  def key
22
22
  property_definition.name
23
23
  end
24
-
25
- def brief_inspect
26
- cls_name = self.class.name.split('::').last
27
- val = "#{value.to_s.slice(0, 40).inspect}#{'...' if value.to_s.size > 40}"
28
- "#<#{cls_name} #{key} = #{val}>"
29
- end
30
24
  end
31
25
  end
32
26
  end