archimate 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/archimate.gemspec +2 -1
  3. data/lib/archimate/color.rb +2 -2
  4. data/lib/archimate/data_model/any_attribute.rb +4 -10
  5. data/lib/archimate/data_model/any_element.rb +9 -17
  6. data/lib/archimate/data_model/bounds.rb +6 -6
  7. data/lib/archimate/data_model/color.rb +6 -6
  8. data/lib/archimate/data_model/comparison.rb +101 -5
  9. data/lib/archimate/data_model/concern.rb +5 -13
  10. data/lib/archimate/data_model/connection.rb +39 -48
  11. data/lib/archimate/data_model/connector_type.rb +1 -0
  12. data/lib/archimate/data_model/diagram.rb +27 -42
  13. data/lib/archimate/data_model/diagram_type.rb +1 -0
  14. data/lib/archimate/data_model/element.rb +14 -35
  15. data/lib/archimate/data_model/elements.rb +681 -0
  16. data/lib/archimate/data_model/font.rb +8 -8
  17. data/lib/archimate/data_model/lang_string.rb +10 -36
  18. data/lib/archimate/data_model/layer.rb +4 -5
  19. data/lib/archimate/data_model/layers.rb +45 -49
  20. data/lib/archimate/data_model/location.rb +6 -6
  21. data/lib/archimate/data_model/metadata.rb +2 -6
  22. data/lib/archimate/data_model/model.rb +50 -62
  23. data/lib/archimate/data_model/modeling_note.rb +3 -8
  24. data/lib/archimate/data_model/organization.rb +18 -27
  25. data/lib/archimate/data_model/property.rb +9 -8
  26. data/lib/archimate/data_model/property_definition.rb +15 -21
  27. data/lib/archimate/data_model/referenceable.rb +14 -9
  28. data/lib/archimate/data_model/referenceable_list.rb +82 -0
  29. data/lib/archimate/data_model/relationship.rb +41 -152
  30. data/lib/archimate/data_model/relationship_references.rb +29 -0
  31. data/lib/archimate/data_model/relationships.rb +214 -0
  32. data/lib/archimate/data_model/schema_info.rb +6 -12
  33. data/lib/archimate/data_model/style.rb +14 -25
  34. data/lib/archimate/data_model/view_node.rb +38 -66
  35. data/lib/archimate/data_model/viewpoint.rb +23 -38
  36. data/lib/archimate/data_model/viewpoint_type.rb +347 -387
  37. data/lib/archimate/data_model.rb +7 -6
  38. data/lib/archimate/derived_relations.rb +106 -31
  39. data/lib/archimate/export/cypher.rb +0 -18
  40. data/lib/archimate/export/jsonl.rb +16 -45
  41. data/lib/archimate/export/n_quads.rb +1 -24
  42. data/lib/archimate/file_formats/archi_file_reader.rb +2 -1
  43. data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +9 -1
  44. data/lib/archimate/file_formats/sax/archi/archi_handler_factory.rb +2 -2
  45. data/lib/archimate/file_formats/sax/archi/connection.rb +2 -1
  46. data/lib/archimate/file_formats/sax/archi/element.rb +7 -5
  47. data/lib/archimate/file_formats/sax/archi/relationship.rb +1 -1
  48. data/lib/archimate/file_formats/sax/model_exchange_file/connection.rb +2 -1
  49. data/lib/archimate/file_formats/sax/model_exchange_file/element.rb +1 -1
  50. data/lib/archimate/file_formats/sax/model_exchange_file/relationship.rb +1 -1
  51. data/lib/archimate/file_formats/sax/model_exchange_file/view_node.rb +0 -1
  52. data/lib/archimate/file_formats/serializer/archi/relationship.rb +1 -1
  53. data/lib/archimate/lint/duplicate_entities.rb +46 -42
  54. data/lib/archimate/svg/archimate.css +12 -2
  55. data/lib/archimate/svg/entity/base_entity.rb +6 -29
  56. data/lib/archimate/svg/entity/location.rb +1 -0
  57. data/lib/archimate/svg/entity_factory.rb +3 -3
  58. data/lib/archimate/svg/point.rb +3 -3
  59. data/lib/archimate/svg/svg_template.svg.erb +5 -5
  60. data/lib/archimate/version.rb +2 -1
  61. metadata +20 -6
  62. data/TODOs.org +0 -505
  63. data/lib/archimate/data_model/differentiable.rb +0 -142
  64. data/lib/archimate/data_model/element_type.rb +0 -89
  65. data/lib/archimate/data_model/relationship_type.rb +0 -45
data/TODOs.org DELETED
@@ -1,505 +0,0 @@
1
- * ArchiMate Tools TODO
2
-
3
- ** SVG Rendering
4
-
5
- *** DONE skip bendpoints inside source or target
6
- CLOSED: [2017-02-01 Wed 12:41]
7
- *** DONE badges for device, node, service (cosmetic)
8
- CLOSED: [2017-02-01 Wed 12:41]
9
- *** DONE trim space around diagram names (cosmetic)
10
- CLOSED: [2017-02-01 Wed 12:42]
11
- *** DONE badge position updates (cosmetic, legibility)
12
- CLOSED: [2017-02-01 Wed 12:42]
13
- *** DONE badge updates (cosmetic)
14
- CLOSED: [2017-02-01 Wed 12:42]
15
- *** DONE verify junctions
16
- CLOSED: [2017-02-01 Wed 12:42]
17
- *** DONE alternate figures (curved vs box & badge) selected by type="1" on Child (legibility)
18
- CLOSED: [2017-02-01 Wed 12:42]
19
- *** DONE text bounds in entities (cosmetic, legibility)
20
- CLOSED: [2017-02-01 Wed 12:42]
21
- *** DONE badge spacer settings (cosmetic, legibility) - artifact needs work.
22
- CLOSED: [2017-02-01 Wed 12:42]
23
- *** TODO text on lines (cosmetic, legibility)
24
- *** TODO bendpoint curves (cosmetic)
25
- *** TODO line crossing hops (cosmetic)
26
- *** DONE refactor
27
- CLOSED: [2017-02-01 Wed 12:42]
28
-
29
- ** Performance
30
-
31
- *** TODO Look into using Celluloid and/or jruby to improve performance
32
- Thinking about concurrency for performance improvements
33
-
34
- read base
35
- read local
36
- read remote
37
-
38
- base + local -> diff l
39
- base + remote -> diff b
40
-
41
- diff l + diff b -> conflict detection
42
-
43
- cd -> each conflict type
44
-
45
- conflicts -> conflict resolution
46
-
47
- cr (user response)
48
-
49
- serialize result (single)
50
-
51
-
52
- ** Diff/Merge
53
-
54
- *** Conflicts can happen on the same diff 2x. How to handle this?
55
- *** DONE In `Change.to_s` - deref args that point to other elements (like archimate_element)
56
- CLOSED: [2017-02-01 Wed 12:48]
57
- *** In Diagram children diffs - make to_s reference the parent diagram
58
- *** DONE Array diffs on non-id'd diffable elements should detect changes rather than delete/insert
59
- CLOSED: [2017-02-01 Wed 12:48]
60
- *** Archi file could have ids that conflict (i.e. 2 relationships with same id - this is bad!!! Was it a bad merge or something worse)
61
- *** Implement check for de-duplicated merges
62
- *** DONE Add a summary diff - elements added/changed/deleted, diagrams
63
- CLOSED: [2017-02-01 Wed 12:48]
64
-
65
- ** Lint
66
-
67
- *** DONE Basic Lint features (matching Archi)
68
- CLOSED: [2017-02-01 Wed 12:49]
69
- *** TODO Scorecard lint
70
-
71
- ** File Formats & Exports
72
-
73
- *** TODO Convert support for
74
- **** TODO Rdf
75
- **** TODO Gremlin
76
- **** DONE Neo4j CSV
77
- CLOSED: [2017-02-01 Wed 13:04]
78
- **** DONE Cypher
79
- CLOSED: [2017-02-01 Wed 13:04]
80
- **** DONE N-Quad
81
- CLOSED: [2017-02-01 Wed 13:04]
82
- **** DONE GraphML
83
- CLOSED: [2017-02-01 Wed 13:04]
84
-
85
- ** DSL
86
-
87
- *** TODO CLI DSL
88
- *** TODO DSL for relationships
89
- # type from to
90
- "AssociationRelationship", "associated_with", "associated_with"
91
- "AccessRelationship", "accesses", "accessed_by"
92
- "UsedByRelationship", "used_by", "uses"
93
- "RealisationRelationship", "realizes", "realized_by"
94
- "AssignmentRelationship", ""
95
- "AggregationRelationship"
96
- "CompositionRelationship"
97
- "FlowRelationship"
98
- "TriggeringRelationship"
99
- "GroupingRelationship"
100
- "SpecialisationRelationship"
101
- "InfluenceRelationship"
102
-
103
- # attributes that are references to other nodes in the model
104
-
105
- For any of these inserted or changed...
106
-
107
- * Property.key (only after PropertyDefs is introduced)
108
- - Property referenced deleted key
109
- * Child.target_connections -> Array of Connection ids
110
- - Connection.id deleted
111
- * Child.archimate_element -> Element.id
112
- - Element.id deleted
113
- * Folder.items -> Array of IdentifiedNode
114
- - *.id deleted
115
- * Relationship.source -> Element.id
116
- - Element.id deleted
117
- * Relationship.target -> Element.id
118
- - Element.id deleted
119
- * Connection.source -> Child.id
120
- - Child.id deleted
121
- * Connection.target -> Child.id
122
- - Child.id deleted
123
- * Connection.relationship -> Relationship.id
124
- - Relationship.id deleted
125
-
126
-
127
- ** Additional Features
128
-
129
- *** TODO Add Split file feature (extract say a diagram or set of elements)
130
- *** TODO Merge unrelated files (this is the intent of Merger)
131
- *** TODO Add a super strict mode to note when reader finds unexpected content
132
- *** DONE Stats (elements, relationships, diagrams)
133
- CLOSED: [2017-02-01 Wed 12:45]
134
- *** TODO Tool to query for dependencies
135
- *** TODO Tool to assign/validate/enforce metadata
136
-
137
- ** Code Quality/Refactoring
138
-
139
- *** TODO Consider breaking this into a number of gems (for example: base lib, diff/merge, other cmdline tools)
140
- *** TODO Consider making classes for each element and relationship type?
141
- *** DONE Figure out how to make rmagick optional and/or remove rmagick dependency
142
- CLOSED: [2017-02-01 Wed 12:45]
143
- *** TODO Data model items that reference something else by id should have the actual object available - not just the id
144
- *** DONE Convert all CLIs to use AIO - merge with OutputIO and MaybeIO (maybe)
145
- CLOSED: [2017-02-01 Wed 12:45]
146
- *** DONE figure out a better parent mechanism - it's really not fully cooked
147
- CLOSED: [2017-02-01 Wed 12:45]
148
- *** DONE remove parent_id from dry::struct objects - then can use class schema instead of comparison attributes
149
- CLOSED: [2017-02-01 Wed 12:45]
150
- *** TODO Not handling sketch diagram model in archi
151
- *** DONE Use one color method - currently using HighLine and Colorize
152
- CLOSED: [2017-02-01 Wed 12:45]
153
- *** TODO Refactor merge to pull conflict detection out
154
- *** DONE Clean up the way that the describe is done on data model
155
- CLOSED: [2017-02-01 Wed 12:45]
156
- *** DONE Permit model items to link back to their parent
157
- CLOSED: [2017-02-01 Wed 12:45]
158
- *** DONE Should be a master hash index of id to object in Model
159
- CLOSED: [2017-02-01 Wed 12:45]
160
- *** DONE Improve description of diffs for conflict display
161
- CLOSED: [2017-02-01 Wed 12:45]
162
- *** DONE Eliminate use of Document in favor of Model
163
- CLOSED: [2017-02-01 Wed 12:45]
164
- - [X] cli/archi.rb
165
- - [X] cli/cleanup.rb
166
- - [X] cli/convert.rb
167
- - [X] cli/svger.rb
168
- *** TODO Experiment with Ox, Oga, Sax-Machine for better performance on convert
169
- *** TODO Map conversion between archi and archimate diagram formats
170
- *** DONE Write a common clone for dry-struct classes
171
- CLOSED: [2017-02-01 Wed 12:45]
172
- *** DONE Make a format agnostic file reader (which delegates to appropriate file type readers)
173
- CLOSED: [2017-02-01 Wed 12:45]
174
- *** DONE Decide between ox and nokogiri and eliminate the alternate
175
- CLOSED: [2017-02-01 Wed 12:45]
176
- *** DONE See what can be done about performance
177
- CLOSED: [2017-02-01 Wed 12:46]
178
- - Reading file 11-12 secs
179
- - deleted relationships referenced in diagrams is slow
180
- *** DONE Refactor to better OO design where necessary (see all about names below)
181
- CLOSED: [2017-02-01 Wed 12:46]
182
- *** DONE Refactor merge to pull apply diffs out
183
- CLOSED: [2017-02-01 Wed 12:46]
184
- *** TODO Refactor Bendpoint to use a point (rather than Archi start/end points).
185
- *** TODO Refactor DataModel classes to use enumeration classes for appropriate values
186
- *** TODO Add a test to produce SVG output for the "everything.archimate" file
187
- *** TODO Add a test to produce a badges diagram
188
-
189
-
190
- * Refactor of data model for diff/merge purposes
191
-
192
- ** Validation
193
- *** Identifiable objects exist one place in model
194
- ***
195
- ** Join:
196
- - Organizable Id (An Organizable is an Identifiable that can be contained in a Folder
197
- - Folder
198
- - Position in Folder - index isn't good here ... should that position really be a linked list?
199
- * Introduce the idea of archimate modules
200
- - Allow creation of a focused model by including archimate modules - which are self-contained packages of elements and relationships
201
- - Allow inheritance of a module to permit showing changes to an existing model.
202
- ** How to implement?
203
- - Break things down automatically?
204
- - By Layer?
205
- - How to Deal with relationships across module boundaries?
206
- * Need to have model merge capability
207
- * TODO Refactor to use a Decorator approach using SimpleDelegator
208
- * TODO Remove Dry-Types dependency
209
- * TODO Scan git history and inject metadata for concepts created by git author
210
- * Changes for v3 have borked the model
211
- ** TODO Push through fixes focusing on the issues from factories to see if that works
212
- ** TODO Refactor model to eliminate a lot of cruft by removing things like in_model= and populating model with objects instead of ID refs
213
- ** TODO Refactor model to improve the diffing of arrays and by writing explicit diff decorators rather than domain model magic
214
- Both of the last two options risk breaking diffing/merging by making and becoming a long slog
215
-
216
- * TODO In mergetool - show diagrams that reference elements and relationships in diff conflicts
217
-
218
- * Notes
219
-
220
- Generic type - not used directly
221
- ReferenceType <xs:attribute name="ref" type="xs:IDREF
222
-
223
- ElementRefGroup <xs:attribute name="elementRef" type="xs:IDREF
224
- RelationshipRefGroup <xs:attribute name="relationshipRef" type="xs:IDREF
225
- ConceptRefGroup <xs:attribute name="ConceptRef" type="xs:IDREF
226
- PropertyDefinitionRefGroup <xs:attribute name="propertyDefinitionRef" type="xs:IDREF
227
- StereotypeRefGroup <xs:attribute name="stereotypeRef" type="xs:IDREF
228
- PropertyDefinitionRefAttributeGroup <xs:attribute name="propertyDefinitionRef" type="xs:IDREF
229
-
230
- RelationshipType <xs:attribute name="source" type="xs:IDREF
231
- RelationshipType <xs:attribute name="target" type="xs:IDREF
232
-
233
- OrganizationType <xs:attribute name="identifierRef" type="xs:IDREF
234
-
235
-
236
- RelationshipType.source -> ConceptType?
237
- RelationshipType.target -> ConceptType?
238
- ViewType.viewpointRef -> Viewpoint
239
-
240
- Label.conceptRef -> ConceptType
241
- Element (Diagram).elementRef -> ElementType
242
- ConnectionType.source -> ConceptType
243
- ConnectionType.target -> ConceptType
244
- Relationship (Diagram).relationshipRef -> RelationshipType
245
-
246
-
247
- ModelType
248
- PropertyDefinitionType
249
- ConceptType > [RelationshipType > Access, Influence], ElementType > RealElementType, RelationshipConnectorType, CompositeType
250
- ViewType > Diagram
251
-
252
-
253
- ViewConceptType > [ViewNodeType > Label, Container], [ConnectionType > Line, SourcedConnectionType > Relationship > NestingRelationship]
254
- Child is a ViewNodeType
255
-
256
-
257
-
258
- ViewpointType
259
-
260
- * More Notes
261
-
262
- background_class -> used by entity_shape
263
- badge -> entity_badge -> to_svg
264
- entity_shape
265
-
266
-
267
- text_bounds (I think this is only set in entity_shape)
268
- DiagramModelReference assigns the entity from the child.model_element
269
- badge_bounds in Gap, MotivationEntity, RectEntity, RoundedRectEntity
270
- text_align in Note
271
-
272
- some shapes are dependent on child.child_type
273
-
274
- badge should be controlled by the entity_shape method
275
- check that badge_bounds is set by shape (I think it is)
276
-
277
- text_bounds is controlled by entity_shape
278
-
279
- background_class : string (default: layer_background_class)
280
- badge : string option
281
- entity_shape : (child -> element_name_type -> bounds -> Svg.elt wrap)
282
- effective_entity : (child -> element_name_type)
283
-
284
- get effective entity
285
-
286
- that's used to match the rest:
287
-
288
- Intermittent Failure with test --seed 11297
289
-
290
- ---
291
-
292
- Remove Id references in preference to object references
293
-
294
- Done:
295
-
296
- Property (PropertyDefinitionId)
297
-
298
- TODO:
299
-
300
- Relationship (Source & Target)
301
- View (Viewpoint)
302
-
303
- Connection (For Source & Targets)
304
- Label (Not Currently Used)
305
- ViewConcept (View {Concept} list)
306
- ViewNode (model, targetConnections, archimateNode)
307
-
308
- ---
309
-
310
- Part of Better Diff/Merge redux
311
-
312
- What about the path? Need a way to describe diffs & conflicts back to meaningful user world terms. (not id oriented)
313
-
314
- Eliminate the use of DiffableArray by making a class for collections
315
- Eliminate the use of Diffable Primitive with a smarter context diff
316
-
317
- Referenceable Object Instance Classes
318
-
319
- Archimate::DataModel::Model < Archimate::DataModel::NamedReferenceable
320
- Archimate::DataModel::PropertyDefinition < Archimate::DataModel::NamedReferenceable,
321
- Archimate::DataModel::Element < Archimate::DataModel::Concept,
322
- Archimate::DataModel::Relationship < Archimate::DataModel::Concept,
323
- Archimate::DataModel::Diagram < Archimate::DataModel::View,
324
- Archimate::DataModel::ViewNode < Archimate::DataModel::Referenceable,
325
- Archimate::DataModel::Connection < Archimate::DataModel::Referenceable,
326
-
327
- What are the non-referenceable things that might be included by a less automated diff?
328
-
329
- Model
330
- (from Referenceable)
331
- id
332
- name
333
- documentation: Array of LangString - really should be a LangString type (I believe)
334
- type: String - TODO: need to handle US/UK spelling differences and naming differences between Archi/ArchiMate2.1/ArchiMate3
335
- properties
336
- metadata
337
- elements
338
- relationships
339
- organizations
340
- property_definitions
341
- version
342
- diagrams
343
- viewpoints
344
- filename
345
- file_format
346
- archimate_version
347
- namespaces
348
- schema_locations
349
-
350
- PropertyDefinition
351
- (from Referenceable)
352
- id
353
- name
354
- documentation: Array of LangString - really should be a LangString type (I believe)
355
- type: String
356
- (from PropertyDefinition)
357
- value_type (DataType)
358
-
359
- Element
360
- (from Referenceable)
361
- id
362
- name
363
- documentation: Array of LangString - really should be a LangString type (I believe)
364
- type: String
365
- properties (from Concept)
366
-
367
- Relationship
368
- (from Referenceable)
369
- id
370
- name
371
- documentation: Array of LangString - really should be a LangString type (I believe)
372
- type: String
373
- source
374
- target
375
- access_type
376
-
377
- Diagram
378
- (from Referenceable)
379
- id
380
- name
381
- documentation: Array of LangString - really should be a LangString type (I believe)
382
- type: String
383
- (from View)
384
- properties
385
- viewpoint_type
386
- viewpoint
387
- (from Diagram)
388
- nodes (ViewNode collection)
389
- connection_router_type (int - enum, Archi only)
390
- background (int Archi only)
391
- connections (Connection Collection)
392
-
393
- ViewNode
394
- (from Referenceable)
395
- id
396
- name
397
- documentation: Array of LangString - really should be a LangString type (I believe)
398
- type: String
399
- model: (identifier - what is this? Archi Only)
400
- content: string
401
- target_connections: (Archi only, identifiers, collection of ids of targets, TODO, probably not needed)
402
- archimate_element (Element)
403
- bounds
404
- nodes: (ViewNode collection)
405
- connections (Connection collection)
406
- style
407
- type
408
- child_type: (TODO: int this selects the shape of the object)
409
- properties
410
-
411
- There are some sub-classes here that might be valuable to implement?
412
- Connection
413
- (from Referenceable)
414
- id
415
- name
416
- documentation: Array of LangString - really should be a LangString type (I believe)
417
- type: String
418
- source_attachment (Location)
419
- bendpoints
420
- target_attachment (Location)
421
- source
422
- target
423
- relationship
424
- style
425
- properties
426
-
427
- What about Organizations - they are horrifically defined in ArchiMate 3. Need an internal model that isn't so insane and is diffable/mergable.
428
-
429
- ---
430
-
431
- Diff implementation
432
-
433
- The refinements implementation is hokey. A lot of code and makes thing fragile.
434
-
435
- Diff calculation
436
-
437
- In most collections (except ones under diagram), the order of items doesn't matter - except it helps make textual diffs of models smaller.
438
-
439
- insert and delete are probably only useful for collections
440
-
441
- change is typical
442
-
443
- how would move be implemented (i.e. move between collections)
444
- What's the best data structure for collections to make diffs and merges easier? Diff lcs?
445
-
446
- validation on demand rather than at creation of data model in absence of dry-struct? Switchable by global setting?
447
-
448
- How would we add archimate modules (new concept)? privacy? Timeline? Transitional architectures?
449
-
450
- ---
451
-
452
- Diff
453
-
454
- - [ ] User friendly text description
455
- - [ ] User friendly description includes location information in the model (I.e diagram it's located in, elements describing relationship, and so on)
456
- - [ ] Diffs can be compared to see if they are in conflict
457
- - [ ] Diff can be applied to a model to patch model
458
-
459
- * TODO Eliminate Documentation class - it's a LangString
460
- * TODO Make LangString be like a Hash with lang as key and string as value
461
- * TODO Make LangString use a default lang (stored in Archimate module)
462
-
463
- ---
464
-
465
- Strict::Array.member(AnyAttribute).default([])
466
- Strict::Array.member(AnyElement).default([])
467
- Strict::Array.member(Concern).default([])
468
- Strict::Array.member(Connection).default([])
469
- Strict::Array.member(Diagram).default([])
470
- Strict::Array.member(Element).default([])
471
- Strict::Array.member(ElementType).default([])
472
- Strict::Array.member(LangString)
473
- Strict::Array.member(Location).default([])
474
- Strict::Array.member(ModelingNote).default([])
475
- Strict::Array.member(Organization).default([])
476
- Strict::Array.member(Property).default([])
477
- Strict::Array.member(PropertyDefinition).default([])
478
- Strict::Array.member(Referenceable).default([])
479
- Strict::Array.member(Relationship).default([])
480
- Strict::Array.member(RelationshipType).default([])
481
- Strict::Array.member(SchemaInfo).default([])
482
- Strict::Array.member(Strict::String).default([])
483
- Strict::Array.member(ViewNode).default([])
484
- Strict::Array.member(Viewpoint).default([])
485
- Strict::Array.member(ViewpointContentEnum).default([])
486
- Strict::Array.member(ViewpointPurposeEnum).default([])
487
-
488
- ---
489
-
490
- Use locale for LangString
491
- IRB::Locale.new.lang
492
-
493
- ---
494
-
495
- referenced_identified_nodes
496
- Model->
497
-
498
- Diagram
499
- ViewNode
500
- Container
501
- Connection
502
- Element (Property->PropertyDefinition)
503
- Organization
504
- Relationship
505
-
@@ -1,142 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Archimate
4
- module DataModel
5
- # Let's talk about diff...
6
- #
7
- # Here are my expectations of diff:
8
- #
9
- # = Preconditions:
10
- #
11
- # 1. self is non-nil
12
- # 2. self is a class that includes Comparison
13
- #
14
- # = Requirements for other
15
- #
16
- # Not matching one of these is a programming error.
17
- #
18
- # 1. Other is nil
19
- # 2. Other is an instance of the same class as self
20
- #
21
- # = Diff results
22
- #
23
- # * Diffing results in a list of Diff instances between +self+ and +other+
24
- # * Patching the list of diffs against self results in an instance that == +other+
25
- #
26
- # = Diff Container
27
- #
28
- # A diff container is a top level entity that is meaningful in the user domain
29
- # for example: [Element], [Relationship], [Diagram]. It collects and groups
30
- # the smaller diffs into the things that changed by an entity tha makes sense
31
- # to the user.
32
- #
33
- # = Diff structure
34
- #
35
- # A diff contains a change to be applied in a particular context.
36
- #
37
- # Use cases:
38
- #
39
- # 1. Delete a value that is a member of this class. Example: Delete the
40
- # +a+ member of a [Color] instance.
41
- # 2. A non-reference value replacing a value in a class. Example:
42
- # Changing the +r+ value of a [Color] with a different value.
43
- # 3. Updating the value of an attribute of a child. (or child's child)
44
- # 4. Deleting the value of an attribute of a child. (or child's child)
45
- # 5. For Array attributes with non-referenceable contents
46
- # 1. Deleting a value from an array attribute
47
- # 2. Inserting a value into an array attribute
48
- # 3. Changing a value in an array attribute
49
- # 6. For Array attributes with referenceable contents
50
- # 1. Deleting a value from an array attribute (has an implication on
51
- # if the entity is deleted from the model entirely)
52
- # 2. Inserting a value into an array attribute (may need addtion to the
53
- # model)
54
- # 3. Changing a value in an array attribute (changing the entity id may
55
- # require the implications of deletion and insertion as above)
56
- #
57
- # When to stop?
58
- #
59
- # When digging down into a diff operation, there are some natural stopping
60
- # points:
61
- #
62
- # 1. When there is no more depth to dig
63
- # 2. When the objects being compared are references to other entities, but
64
- # do not belong to the current object being diffed.
65
- # 3. When the object being diffed is a Diff container unto itself. For
66
- # example: When diffing a model, the diff should include the order
67
- # of elements referenced in the +elements+ attribute, but shouldn't
68
- # continue with the diff of each element itself.
69
- #
70
- # = Complications
71
- #
72
- # == Object references
73
- #
74
- # Since a patch operation produces an new replacement object, object
75
- # references need to be handled. For example, given an +Element+ with +id=3+
76
- # if a patch changes this +Element+'s name, then the +Element+ in
77
- # the model under +Model#elements+ is replaced with a different instance,
78
- # but a +Relationship+ that references the +Element+ is still pointing at
79
- # a different instance and needs to be updated.
80
- Insert = Struct.new(:path, :value)
81
- Delete = Struct.new(:path)
82
- Change = Struct.new(:path, :from, :to)
83
-
84
- module Differentiable
85
- # Computes the diffs between this object and another object of the same type
86
- #
87
- # @param other [self.class] another object to compare
88
- # @return [Array<Diff::Difference>]
89
- # @raise
90
- def diff(other)
91
- return [] if other.nil?
92
- raise TypeError, "Expected other <#{other.class} to be of type #{self.class}" unless other.is_a?(self.class)
93
-
94
- self.class.attr_names.each_with_object([]) do |k, a|
95
- val = send(k)
96
- case val
97
- when NilClass
98
- a << Insert.new(k, other[k]) unless other[k].nil?
99
- when Integer, Float, Hash, String, Symbol
100
- a.concat(Differentiable.diff_primitive(val, other[k], self, other, k))
101
- when Differentiable
102
- a.concat(val.diff(other[k]))
103
- else
104
- raise "Unexpected Type for Diff don't know how to diff a #{val.class}"
105
- end
106
- end
107
- end
108
-
109
- def patch(diffs)
110
- ary = diffs.is_a?(Array) ? diffs : [diffs]
111
- self.class.new(
112
- ary.each_with_object(to_h) do |diff, args|
113
- case diff
114
- when Delete
115
- args[diff.path] = nil
116
- when Insert
117
- args[diff.path] = diff.value
118
- when Change
119
- args[diff.path] = diff.to
120
- else
121
- raise "Unexpected diff type #{diff.class} #{diff.inspect}"
122
- end
123
- end
124
- )
125
- end
126
-
127
- private
128
-
129
- def self.diff_primitive(val, other, from_parent, to_parent, attribute, from_attribute = nil)
130
- from_attribute = attribute if from_attribute.nil?
131
- if other.nil?
132
- return [Delete.new(attribute)]
133
- end
134
- raise TypeError, "Expected other #{other.class} to be of type #{val.class}" unless other.is_a?(val.class)
135
- unless val == other
136
- return [Change.new(attribute, val, other)]
137
- end
138
- []
139
- end
140
- end
141
- end
142
- end