Module: Opencdd::Parcel
- Defined in:
- lib/opencdd/parcel.rb,
lib/opencdd/parcel/sheet.rb,
lib/opencdd/parcel/writer.rb,
lib/opencdd/parcel/metadata.rb,
lib/opencdd/parcel/selector.rb,
lib/opencdd/parcel/workbook.rb,
lib/opencdd/parcel/csv_reader.rb,
lib/opencdd/parcel/csv_writer.rb,
lib/opencdd/parcel/sheet_schema.rb,
lib/opencdd/parcel/sheet_emitter.rb,
lib/opencdd/parcel/entity_manifest.rb,
lib/opencdd/parcel/flat_dir_reader.rb,
lib/opencdd/parcel/layout_detector.rb,
lib/opencdd/parcel/scrape_verifier.rb,
lib/opencdd/parcel/workbook_reader.rb,
lib/opencdd/parcel/referenced_irdis.rb,
lib/opencdd/parcel/sharded_dir_reader.rb
Defined Under Namespace
Modules: CsvReader, CsvWriter, LayoutDetector Classes: EntityManifest, FlatDirReader, Metadata, ReferencedIrdis, ScrapeVerifier, Selector, ShardedDirReader, Sheet, SheetEmitter, SheetSchema, Workbook, WorkbookReader, Writer
Constant Summary collapse
- META_CLASS_TYPES =
Opencdd::MetaClasses::TYPE_BY_META_CLASS
- TYPE_TO_META_CLASS =
META_CLASS_TYPES.invert.freeze
Class Method Summary collapse
-
.aggregate(*paths) ⇒ Object
Aggregate multiple Parcel-shaped paths into a single Database.
- .build_partition(_database, entities) ⇒ Object
- .collect_root_subtree(database, root) ⇒ Object
-
.deep_copy_entity(entity) ⇒ Object
Returns a detached copy of
entity— sameirdi,properties,schema,meta_class_irdi, but no@databaseback-reference and empty Klass-specific state (+@children+,@declared_property_irdis). -
.lift_for(database, classes) ⇒ Object
Lifts cross-type dependencies for the given set of classes: declared properties, value_lists those properties reference, units those properties use, and relations where the class is in domain or codomain.
-
.split(database, by:, lift_dependencies: true) ⇒ Object
Split
databaseinto multiple sub-databases partitioned alongby:. - .split_by_callable(database, callable) ⇒ Object
- .split_by_each_class(database, lift_dependencies: true) ⇒ Object
- .split_by_root_class(database, lift_dependencies: true) ⇒ Object
- .split_by_type(database) ⇒ Object
Class Method Details
.aggregate(*paths) ⇒ Object
Aggregate multiple Parcel-shaped paths into a single Database.
The paths array may contain .xlsx files, .xls files, flat .xls
directories, or sharded per-class subdirs. Each is read
polymorphically via Opencdd::Reader.detect and merged into a
single target database.
Returns the populated Opencdd::Database.
34 35 36 37 38 |
# File 'lib/opencdd/parcel.rb', line 34 def aggregate(*paths) paths.flatten .map { |p| Opencdd::Database.load(p) } .reduce(Opencdd::Database.new) { |acc, db| acc.merge(db) } end |
.build_partition(_database, entities) ⇒ Object
149 150 151 152 153 154 |
# File 'lib/opencdd/parcel.rb', line 149 def build_partition(_database, entities) db = Opencdd::Database.new entities.each { |e| db.add_entity(deep_copy_entity(e)) } db.finalize! db end |
.collect_root_subtree(database, root) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/opencdd/parcel.rb', line 108 def collect_root_subtree(database, root) collected = [root] queue = [root] seen = { root.irdi => true } until queue.empty? current = queue.shift children = current.children children.each do |c| next if seen[c.irdi] seen[c.irdi] = true collected << c queue << c end end collected end |
.deep_copy_entity(entity) ⇒ Object
Returns a detached copy of entity — same irdi, properties,
schema, meta_class_irdi, but no @database back-reference and
empty Klass-specific state (+@children+, @declared_property_irdis).
The destination partition Database reattaches the entity and
rebuilds class-tree state via add_entity and finalize!.
We can't use Marshal here because Entity indirectly references its source Database, which uses Hash.new { ... } (a default proc) for its indexes — Marshal refuses to dump hashes with default procs.
166 167 168 169 170 171 172 173 |
# File 'lib/opencdd/parcel.rb', line 166 def deep_copy_entity(entity) entity.class.new( irdi: entity.irdi, properties: entity.properties.dup, schema: entity.schema, meta_class_irdi: entity., ) end |
.lift_for(database, classes) ⇒ Object
Lifts cross-type dependencies for the given set of classes: declared properties, value_lists those properties reference, units those properties use, and relations where the class is in domain or codomain. This makes a per-tree partition self-sufficient when written out.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/opencdd/parcel.rb', line 130 def lift_for(database, classes) entities = classes.dup classes.each do |klass| database.properties_of(klass).each { |p| entities << p unless entities.include?(p) } database.relations_for(domain: klass.irdi).each { |r| entities << r unless entities.include?(r) } database.relations_for(codomain: klass.irdi).each { |r| entities << r unless entities.include?(r) } database.properties_of(klass).each do |prop| next unless prop.is_a?(Opencdd::Property) if prop.unit_irdi unit = database.find(prop.unit_irdi) entities << unit if unit.is_a?(Opencdd::Unit) && !entities.include?(unit) end vl = database.value_list_of(prop) entities << vl if vl && !entities.include?(vl) end end entities.uniq end |
.split(database, by:, lift_dependencies: true) ⇒ Object
Split database into multiple sub-databases partitioned along
by:
:entity_type — one partition per entity type
(the legacy .xls layout, one file per type).
:root_class — one partition per root class
(full tree per parcel, lifted cross-type deps).
:each_class — one partition per class
(the class + its declared properties / value_lists /
relations / units).
callable — partition key is +callable.call(entity)+;
the result is a +Hash{ key => Database }+.
Returns Hash{ key => Opencdd::Database }.
54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/opencdd/parcel.rb', line 54 def split(database, by:, lift_dependencies: true) partitions = case by when :entity_type then split_by_type(database) when :root_class then split_by_root_class(database, lift_dependencies: lift_dependencies) when :each_class then split_by_each_class(database, lift_dependencies: lift_dependencies) when Proc then split_by_callable(database, by) else raise ArgumentError, "split `by:` must be :entity_type, :root_class, :each_class, or a Proc" end partitions end |
.split_by_callable(database, callable) ⇒ Object
102 103 104 105 106 |
# File 'lib/opencdd/parcel.rb', line 102 def split_by_callable(database, callable) database.entities.group_by { |e| callable.call(e) }.each_with_object({}) do |(key, entities), h| h[key] = build_partition(database, entities) end end |
.split_by_each_class(database, lift_dependencies: true) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/opencdd/parcel.rb', line 81 def split_by_each_class(database, lift_dependencies: true) database.classes.each_with_object({}) do |klass, h| entities = [klass] if lift_dependencies klass_props = database.properties_of(klass) entities.concat(klass_props) entities.concat(database.relations_for(domain: klass.irdi)) klass_props.each do |prop| next unless prop.is_a?(Opencdd::Property) if prop.unit_irdi unit = database.find(prop.unit_irdi) entities << unit if unit.is_a?(Opencdd::Unit) end vl = database.value_list_of(prop) entities << vl if vl end end h[klass.code || klass.irdi.to_s] = build_partition(database, entities) end end |
.split_by_root_class(database, lift_dependencies: true) ⇒ Object
72 73 74 75 76 77 78 79 |
# File 'lib/opencdd/parcel.rb', line 72 def split_by_root_class(database, lift_dependencies: true) roots = database.root_classes roots.each_with_object({}) do |root, h| tree = collect_root_subtree(database, root) entities = lift_dependencies ? lift_for(database, tree) : tree h[root.code || root.irdi.to_s] = build_partition(database, entities) end end |
.split_by_type(database) ⇒ Object
66 67 68 69 70 |
# File 'lib/opencdd/parcel.rb', line 66 def split_by_type(database) database.entities.group_by(&:type).each_with_object({}) do |(type, entities), h| h[type] = build_partition(database, entities) end end |