opencdd 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Opencdd
4
+ module Parcel
5
+ # Reads historical versions of entities from a sharded
6
+ # per-version Parcel layout.
7
+ #
8
+ # The sharded layout stores every version of an entity in a
9
+ # per-UNID subfolder: +<entity_dir>/<UNID>/export_*.xls+. The
10
+ # +_entity.json+ sidecar lists every version and which UNID is
11
+ # current. ShardedDirReader reads only the current version;
12
+ # VersionedReader exposes the full history.
13
+ #
14
+ # Delegates to:
15
+ # - +Opencdd::Parcel::EntityManifest+ for version metadata.
16
+ # - +Opencdd::Parcel::FlatDirReader+ for xls parsing of one
17
+ # version's subfolder.
18
+ #
19
+ # Example:
20
+ # reader = Opencdd::Parcel::VersionedReader.new("downloads/iec63213")
21
+ # reader.versions_for("KEA012") # => 3 VersionHistory::Entry
22
+ # reader.load_version("KEA012", "ABC123...") # => Database with v002 content
23
+ class VersionedReader
24
+ attr_reader :path
25
+
26
+ def initialize(path)
27
+ @path = path
28
+ end
29
+
30
+ # All versions recorded for +code+, as
31
+ # +Opencdd::Entity::VersionHistory::Entry+ instances.
32
+ # Empty +VersionHistory+ if +code+ has no manifest.
33
+ def versions_for(code)
34
+ manifest = manifest_for(code)
35
+ return Opencdd::Entity::VersionHistory.new unless manifest
36
+ manifest.version_history
37
+ end
38
+
39
+ # Load a single historical version's content as a standalone
40
+ # Database. The +unid+ identifies which version's subfolder
41
+ # to read.
42
+ #
43
+ # Returns +nil+ if the version subfolder doesn't exist or has
44
+ # no +.xls+ files. The returned database is finalized but not
45
+ # cross-linked to other entities (historical context only).
46
+ def load_version(code, unid)
47
+ version_dir = version_dir_for(code, unid)
48
+ return nil unless version_dir && File.directory?(version_dir)
49
+ return nil unless Dir.children(version_dir).any? { |f| Opencdd::Parcel::LayoutDetector.legacy_export?(f) }
50
+
51
+ workbook = Opencdd::Parcel::FlatDirReader.new(version_dir).read_workbook
52
+ database = Opencdd::Database.new
53
+ database.add_workbook(workbook)
54
+ attach_version_history(database, code)
55
+ database.finalize!
56
+ database
57
+ end
58
+
59
+ # The entity subdirectory for +code+. Tries both the legacy
60
+ # +<path>/<code>+ layout and the manifest-driven
61
+ # +<path>/_entities/<code>+ layout.
62
+ def entity_dir_for(code)
63
+ flat = File.join(@path, code)
64
+ return flat if File.directory?(flat)
65
+ sharded = File.join(@path, "_entities", code)
66
+ return sharded if File.directory?(sharded)
67
+ nil
68
+ end
69
+
70
+ private
71
+
72
+ def manifest_for(code)
73
+ dir = entity_dir_for(code)
74
+ return nil unless dir
75
+ Opencdd::Parcel::EntityManifest.read(dir)
76
+ end
77
+
78
+ def version_dir_for(code, unid)
79
+ dir = entity_dir_for(code)
80
+ return nil unless dir
81
+ candidate = File.join(dir, unid)
82
+ return candidate if File.directory?(candidate)
83
+ nil
84
+ end
85
+
86
+ def attach_version_history(database, code)
87
+ manifest = manifest_for(code)
88
+ return unless manifest
89
+ return if manifest.versions_empty?
90
+ manifest.version_history.entries.each do |entry|
91
+ next unless entry.unid
92
+ target = database.find_by_code(code)
93
+ target&.attach_version_history(manifest.version_history)
94
+ break
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -12,6 +12,7 @@ module Opencdd
12
12
  autoload :WorkbookReader, "opencdd/parcel/workbook_reader"
13
13
  autoload :FlatDirReader, "opencdd/parcel/flat_dir_reader"
14
14
  autoload :ShardedDirReader, "opencdd/parcel/sharded_dir_reader"
15
+ autoload :VersionedReader, "opencdd/parcel/versioned_reader"
15
16
  autoload :LayoutDetector, "opencdd/parcel/layout_detector"
16
17
  autoload :EntityManifest, "opencdd/parcel/entity_manifest"
17
18
  autoload :ReferencedIrdis, "opencdd/parcel/referenced_irdis"
@@ -77,7 +77,7 @@ module Opencdd
77
77
  base = column_iri.to_s.split(".").first
78
78
  entry = Opencdd::PropertyIds::REGISTRY[base]
79
79
  kind = entry&.value_kind
80
- column_schema = schema&.column_for(base)
80
+ column_schema = schema&.find_by_property_id(base)
81
81
  RuleContext.new(
82
82
  database: database,
83
83
  entity: entity,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Opencdd
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/opencdd.rb CHANGED
@@ -36,6 +36,7 @@ module Opencdd
36
36
  autoload :Reader, "opencdd/reader"
37
37
  autoload :ClassTree, "opencdd/class_tree"
38
38
  autoload :Visitor, "opencdd/visitor"
39
+ autoload :EntityDiff, "opencdd/entity_diff"
39
40
 
40
41
  autoload :Parcel, "opencdd/parcel"
41
42
 
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opencdd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenCDD contributors
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-07-22 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: roo
@@ -229,11 +230,18 @@ files:
229
230
  - lib/opencdd/condition.rb
230
231
  - lib/opencdd/data_type.rb
231
232
  - lib/opencdd/database.rb
233
+ - lib/opencdd/database/finalization.rb
234
+ - lib/opencdd/database/mutations.rb
235
+ - lib/opencdd/database/parcel_integration.rb
236
+ - lib/opencdd/database/persistence.rb
237
+ - lib/opencdd/database/queries.rb
232
238
  - lib/opencdd/effective_properties.rb
233
239
  - lib/opencdd/entity.rb
234
240
  - lib/opencdd/entity/field_reader.rb
235
241
  - lib/opencdd/entity/field_registry.rb
236
242
  - lib/opencdd/entity/version_history.rb
243
+ - lib/opencdd/entity/yaml.rb
244
+ - lib/opencdd/entity_diff.rb
237
245
  - lib/opencdd/exporters.rb
238
246
  - lib/opencdd/exporters/json.rb
239
247
  - lib/opencdd/exporters/mermaid.rb
@@ -247,7 +255,6 @@ files:
247
255
  - lib/opencdd/model.rb
248
256
  - lib/opencdd/model/entity_store.rb
249
257
  - lib/opencdd/model/yaml_database.rb
250
- - lib/opencdd/model/yaml_entity.rb
251
258
  - lib/opencdd/parcel.rb
252
259
  - lib/opencdd/parcel/csv_reader.rb
253
260
  - lib/opencdd/parcel/csv_writer.rb
@@ -262,6 +269,7 @@ files:
262
269
  - lib/opencdd/parcel/sheet.rb
263
270
  - lib/opencdd/parcel/sheet_emitter.rb
264
271
  - lib/opencdd/parcel/sheet_schema.rb
272
+ - lib/opencdd/parcel/versioned_reader.rb
265
273
  - lib/opencdd/parcel/workbook.rb
266
274
  - lib/opencdd/parcel/workbook_reader.rb
267
275
  - lib/opencdd/parcel/writer.rb
@@ -305,6 +313,7 @@ metadata:
305
313
  homepage_uri: https://github.com/opencdd/opencdd-ruby
306
314
  source_code_uri: https://github.com/opencdd/opencdd-ruby
307
315
  changelog_uri: https://github.com/opencdd/opencdd-ruby/releases
316
+ post_install_message:
308
317
  rdoc_options: []
309
318
  require_paths:
310
319
  - lib
@@ -319,7 +328,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
319
328
  - !ruby/object:Gem::Version
320
329
  version: '0'
321
330
  requirements: []
322
- rubygems_version: 3.6.9
331
+ rubygems_version: 3.5.22
332
+ signing_key:
323
333
  specification_version: 4
324
334
  summary: Ruby model and Parcel-format importer for the IEC Common Data Dictionary
325
335
  test_files: []