chemicalml 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +21 -0
- data/CLAUDE.md +198 -0
- data/Gemfile +14 -0
- data/LICENSE +24 -0
- data/NOTICES.adoc +115 -0
- data/README.adoc +87 -0
- data/Rakefile +8 -0
- data/TODO.align/01-cml-base-mixins.md +122 -0
- data/TODO.align/02-real-schema-hierarchies.md +88 -0
- data/TODO.align/03-configuration.md +50 -0
- data/TODO.align/04-parse-entry-points.md +59 -0
- data/TODO.align/05-schema-aware-translator.md +33 -0
- data/TODO.align/06-no-respond-to.md +44 -0
- data/TODO.align/07-canon-xml-comparison.md +43 -0
- data/TODO.align/08-expand-fixtures.md +37 -0
- data/TODO.align/09-final-spec-lint.md +29 -0
- data/TODO.align/10-role-marker-modules.md +54 -0
- data/TODO.align/11-dry-configuration.md +63 -0
- data/TODO.align/12-wire-class-macro.md +51 -0
- data/TODO.align/13-wire-namespace.md +44 -0
- data/TODO.align/14-schema24-correctness.md +37 -0
- data/TODO.align/15-canon-fixture-roundtrip.md +38 -0
- data/TODO.align/16-schema24-convention-coverage.md +33 -0
- data/TODO.align/17-final-spec-lint.md +28 -0
- data/TODO.align/README.md +27 -0
- data/TODO.align/README.round2.md +24 -0
- data/TODO.cml-full/01-reference-docs.md +43 -0
- data/TODO.cml-full/02-schema-versioned-model.md +70 -0
- data/TODO.cml-full/03-fixtures-scrape.md +52 -0
- data/TODO.cml-full/04-convention-framework.md +69 -0
- data/TODO.cml-full/05-dictionary-layer.md +77 -0
- data/TODO.cml-full/06-extend-canonical-translator.md +60 -0
- data/TODO.cml-full/07-attribution-notices.md +42 -0
- data/TODO.cml-full/08-autoload-only.md +48 -0
- data/TODO.cml-full/09-spec-coverage.md +38 -0
- data/TODO.cml-full/README.md +23 -0
- data/chemicalml.gemspec +35 -0
- data/data/dictionaries/_index.yaml +14 -0
- data/data/dictionaries/compchem.yaml +481 -0
- data/data/dictionaries/unit_non_si.yaml +53 -0
- data/data/dictionaries/unit_si.yaml +87 -0
- data/data/dictionaries/unit_type.yaml +113 -0
- data/lib/chemicalml/cml/array.rb +10 -0
- data/lib/chemicalml/cml/atom.rb +10 -0
- data/lib/chemicalml/cml/atom_array.rb +10 -0
- data/lib/chemicalml/cml/atom_parity.rb +10 -0
- data/lib/chemicalml/cml/base/array.rb +36 -0
- data/lib/chemicalml/cml/base/atom.rb +38 -0
- data/lib/chemicalml/cml/base/atom_array.rb +22 -0
- data/lib/chemicalml/cml/base/atom_parity.rb +24 -0
- data/lib/chemicalml/cml/base/bond.rb +28 -0
- data/lib/chemicalml/cml/base/bond_array.rb +22 -0
- data/lib/chemicalml/cml/base/bond_stereo.rb +28 -0
- data/lib/chemicalml/cml/base/cml_module.rb +40 -0
- data/lib/chemicalml/cml/base/dictionary.rb +32 -0
- data/lib/chemicalml/cml/base/dictionary_entry.rb +34 -0
- data/lib/chemicalml/cml/base/document.rb +26 -0
- data/lib/chemicalml/cml/base/formula.rb +38 -0
- data/lib/chemicalml/cml/base/identifier.rb +26 -0
- data/lib/chemicalml/cml/base/label.rb +28 -0
- data/lib/chemicalml/cml/base/list.rb +36 -0
- data/lib/chemicalml/cml/base/matrix.rb +38 -0
- data/lib/chemicalml/cml/base/metadata.rb +30 -0
- data/lib/chemicalml/cml/base/metadata_list.rb +28 -0
- data/lib/chemicalml/cml/base/molecule.rb +40 -0
- data/lib/chemicalml/cml/base/name.rb +26 -0
- data/lib/chemicalml/cml/base/parameter.rb +34 -0
- data/lib/chemicalml/cml/base/parameter_list.rb +28 -0
- data/lib/chemicalml/cml/base/product.rb +22 -0
- data/lib/chemicalml/cml/base/product_list.rb +22 -0
- data/lib/chemicalml/cml/base/property.rb +34 -0
- data/lib/chemicalml/cml/base/property_list.rb +28 -0
- data/lib/chemicalml/cml/base/reactant.rb +22 -0
- data/lib/chemicalml/cml/base/reactant_list.rb +22 -0
- data/lib/chemicalml/cml/base/reaction.rb +32 -0
- data/lib/chemicalml/cml/base/reaction_list.rb +22 -0
- data/lib/chemicalml/cml/base/scalar.rb +32 -0
- data/lib/chemicalml/cml/base/substance.rb +30 -0
- data/lib/chemicalml/cml/base/unit.rb +38 -0
- data/lib/chemicalml/cml/base/unit_list.rb +30 -0
- data/lib/chemicalml/cml/base/unit_type.rb +28 -0
- data/lib/chemicalml/cml/base/unit_type_list.rb +30 -0
- data/lib/chemicalml/cml/base.rb +51 -0
- data/lib/chemicalml/cml/bond.rb +10 -0
- data/lib/chemicalml/cml/bond_array.rb +10 -0
- data/lib/chemicalml/cml/bond_stereo.rb +10 -0
- data/lib/chemicalml/cml/cml_module.rb +10 -0
- data/lib/chemicalml/cml/dictionary.rb +10 -0
- data/lib/chemicalml/cml/dictionary_entry.rb +10 -0
- data/lib/chemicalml/cml/document.rb +10 -0
- data/lib/chemicalml/cml/elements.rb +58 -0
- data/lib/chemicalml/cml/formula.rb +10 -0
- data/lib/chemicalml/cml/identifier.rb +10 -0
- data/lib/chemicalml/cml/label.rb +10 -0
- data/lib/chemicalml/cml/list.rb +10 -0
- data/lib/chemicalml/cml/matrix.rb +10 -0
- data/lib/chemicalml/cml/metadata.rb +10 -0
- data/lib/chemicalml/cml/metadata_list.rb +10 -0
- data/lib/chemicalml/cml/molecule.rb +10 -0
- data/lib/chemicalml/cml/name.rb +10 -0
- data/lib/chemicalml/cml/namespace.rb +17 -0
- data/lib/chemicalml/cml/parameter.rb +10 -0
- data/lib/chemicalml/cml/parameter_list.rb +10 -0
- data/lib/chemicalml/cml/product.rb +10 -0
- data/lib/chemicalml/cml/product_list.rb +10 -0
- data/lib/chemicalml/cml/property.rb +10 -0
- data/lib/chemicalml/cml/property_list.rb +10 -0
- data/lib/chemicalml/cml/reactant.rb +10 -0
- data/lib/chemicalml/cml/reactant_list.rb +10 -0
- data/lib/chemicalml/cml/reaction.rb +10 -0
- data/lib/chemicalml/cml/reaction_list.rb +10 -0
- data/lib/chemicalml/cml/role/array.rb +13 -0
- data/lib/chemicalml/cml/role/atom.rb +13 -0
- data/lib/chemicalml/cml/role/atom_array.rb +13 -0
- data/lib/chemicalml/cml/role/atom_parity.rb +13 -0
- data/lib/chemicalml/cml/role/bond.rb +13 -0
- data/lib/chemicalml/cml/role/bond_array.rb +13 -0
- data/lib/chemicalml/cml/role/bond_stereo.rb +13 -0
- data/lib/chemicalml/cml/role/cml_module.rb +14 -0
- data/lib/chemicalml/cml/role/dictionary.rb +13 -0
- data/lib/chemicalml/cml/role/dictionary_entry.rb +13 -0
- data/lib/chemicalml/cml/role/document.rb +13 -0
- data/lib/chemicalml/cml/role/formula.rb +13 -0
- data/lib/chemicalml/cml/role/identifier.rb +13 -0
- data/lib/chemicalml/cml/role/label.rb +13 -0
- data/lib/chemicalml/cml/role/list.rb +13 -0
- data/lib/chemicalml/cml/role/matrix.rb +13 -0
- data/lib/chemicalml/cml/role/metadata.rb +13 -0
- data/lib/chemicalml/cml/role/metadata_list.rb +13 -0
- data/lib/chemicalml/cml/role/molecule.rb +13 -0
- data/lib/chemicalml/cml/role/name.rb +13 -0
- data/lib/chemicalml/cml/role/parameter.rb +13 -0
- data/lib/chemicalml/cml/role/parameter_list.rb +13 -0
- data/lib/chemicalml/cml/role/product.rb +13 -0
- data/lib/chemicalml/cml/role/product_list.rb +13 -0
- data/lib/chemicalml/cml/role/property.rb +13 -0
- data/lib/chemicalml/cml/role/property_list.rb +13 -0
- data/lib/chemicalml/cml/role/reactant.rb +13 -0
- data/lib/chemicalml/cml/role/reactant_list.rb +13 -0
- data/lib/chemicalml/cml/role/reaction.rb +13 -0
- data/lib/chemicalml/cml/role/reaction_list.rb +13 -0
- data/lib/chemicalml/cml/role/scalar.rb +13 -0
- data/lib/chemicalml/cml/role/substance.rb +13 -0
- data/lib/chemicalml/cml/role/unit.rb +13 -0
- data/lib/chemicalml/cml/role/unit_list.rb +13 -0
- data/lib/chemicalml/cml/role/unit_type.rb +13 -0
- data/lib/chemicalml/cml/role/unit_type_list.rb +13 -0
- data/lib/chemicalml/cml/role.rb +54 -0
- data/lib/chemicalml/cml/scalar.rb +10 -0
- data/lib/chemicalml/cml/schema24/configuration.rb +19 -0
- data/lib/chemicalml/cml/schema24.rb +40 -0
- data/lib/chemicalml/cml/schema3/configuration.rb +17 -0
- data/lib/chemicalml/cml/schema3.rb +40 -0
- data/lib/chemicalml/cml/substance.rb +10 -0
- data/lib/chemicalml/cml/translator/value_translations.rb +265 -0
- data/lib/chemicalml/cml/translator.rb +233 -0
- data/lib/chemicalml/cml/unit.rb +10 -0
- data/lib/chemicalml/cml/unit_list.rb +10 -0
- data/lib/chemicalml/cml/unit_type.rb +10 -0
- data/lib/chemicalml/cml/unit_type_list.rb +10 -0
- data/lib/chemicalml/cml/visitable.rb +65 -0
- data/lib/chemicalml/cml/wire_class_macro.rb +45 -0
- data/lib/chemicalml/cml.rb +55 -0
- data/lib/chemicalml/context_configuration.rb +127 -0
- data/lib/chemicalml/convention/base.rb +48 -0
- data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +33 -0
- data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +38 -0
- data/lib/chemicalml/convention/compchem/constraints.rb +14 -0
- data/lib/chemicalml/convention/compchem.rb +28 -0
- data/lib/chemicalml/convention/constraint.rb +79 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +33 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +34 -0
- data/lib/chemicalml/convention/dictionary/constraints.rb +14 -0
- data/lib/chemicalml/convention/dictionary.rb +28 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +30 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +42 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +54 -0
- data/lib/chemicalml/convention/molecular/constraints.rb +19 -0
- data/lib/chemicalml/convention/molecular.rb +29 -0
- data/lib/chemicalml/convention/registry.rb +50 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_symbol_and_unit_type.rb +46 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints.rb +12 -0
- data/lib/chemicalml/convention/unit_dictionary.rb +27 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +34 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints.rb +12 -0
- data/lib/chemicalml/convention/unit_type_dictionary.rb +27 -0
- data/lib/chemicalml/convention/violation.rb +36 -0
- data/lib/chemicalml/convention.rb +39 -0
- data/lib/chemicalml/dictionary/entry.rb +59 -0
- data/lib/chemicalml/dictionary/enum.rb +51 -0
- data/lib/chemicalml/dictionary/link.rb +32 -0
- data/lib/chemicalml/dictionary/loader.rb +60 -0
- data/lib/chemicalml/dictionary/model.rb +64 -0
- data/lib/chemicalml/dictionary/registry.rb +75 -0
- data/lib/chemicalml/dictionary.rb +26 -0
- data/lib/chemicalml/errors.rb +7 -0
- data/lib/chemicalml/model/atom.rb +40 -0
- data/lib/chemicalml/model/bond.rb +33 -0
- data/lib/chemicalml/model/cml_array.rb +27 -0
- data/lib/chemicalml/model/cml_module.rb +45 -0
- data/lib/chemicalml/model/document.rb +29 -0
- data/lib/chemicalml/model/formula.rb +34 -0
- data/lib/chemicalml/model/identifier.rb +21 -0
- data/lib/chemicalml/model/label.rb +21 -0
- data/lib/chemicalml/model/matrix.rb +29 -0
- data/lib/chemicalml/model/metadata.rb +23 -0
- data/lib/chemicalml/model/metadata_list.rb +25 -0
- data/lib/chemicalml/model/molecule.rb +38 -0
- data/lib/chemicalml/model/name.rb +21 -0
- data/lib/chemicalml/model/node.rb +45 -0
- data/lib/chemicalml/model/parameter.rb +27 -0
- data/lib/chemicalml/model/parameter_list.rb +25 -0
- data/lib/chemicalml/model/product.rb +21 -0
- data/lib/chemicalml/model/product_list.rb +21 -0
- data/lib/chemicalml/model/property.rb +28 -0
- data/lib/chemicalml/model/property_list.rb +25 -0
- data/lib/chemicalml/model/reactant.rb +21 -0
- data/lib/chemicalml/model/reactant_list.rb +21 -0
- data/lib/chemicalml/model/reaction.rb +41 -0
- data/lib/chemicalml/model/reaction_list.rb +23 -0
- data/lib/chemicalml/model/scalar.rb +25 -0
- data/lib/chemicalml/model/substance.rb +25 -0
- data/lib/chemicalml/model.rb +38 -0
- data/lib/chemicalml/schema/definition.rb +41 -0
- data/lib/chemicalml/schema/registry.rb +30 -0
- data/lib/chemicalml/schema.rb +35 -0
- data/lib/chemicalml/version.rb +5 -0
- data/lib/chemicalml/versioned_parser.rb +43 -0
- data/lib/chemicalml.rb +47 -0
- data/lib/tasks/reference_fetch.rake +105 -0
- data/lib/tasks/scrape_fixtures.rake +133 -0
- data/reference-docs/conventions/compchem.md +141 -0
- data/reference-docs/conventions/dictionary.md +119 -0
- data/reference-docs/conventions/index.md +56 -0
- data/reference-docs/conventions/molecular.md +115 -0
- data/reference-docs/conventions/unit-dictionary.md +92 -0
- data/reference-docs/conventions/unitType-dictionary.md +51 -0
- data/reference-docs/dictionaries/compchem.md +335 -0
- data/reference-docs/dictionaries/index.md +52 -0
- data/reference-docs/examples/schema24-index.md +50 -0
- data/reference-docs/examples/schema3-compchem-index.md +14 -0
- data/reference-docs/examples/schema3-molecular-index.md +28 -0
- data/reference-docs/schemas/schema24/schema.xsd +10624 -0
- data/reference-docs/schemas/schema3/schema.xsd +11459 -0
- metadata +306 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 07b63ae96c1ef6187081c9f14ab76722b91f4438516a46c993abadac25f37a8f
|
|
4
|
+
data.tar.gz: 5130f3b5538741239be68d6632eaeecc0175ecb44f7a85cdf88e9414657c1689
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 29433a22bbfd290ce7146fefda2d4e68944bda3098902e3d8c6f282d05c7b99ee95de9097685ed55e9ff365799e17eee785bb3b5414dff39076616c65db87189
|
|
7
|
+
data.tar.gz: 300c20a1df5cf4cbad657ce97fc0b26b6aec9f2ecb84ac524ab4f30a209636aeebbf6756637ee0e3fc6dec96685f4334aa8ee90e34a1058078ea2ccba4d2f4a8
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop
|
|
3
|
+
|
|
4
|
+
AllCops:
|
|
5
|
+
NewCops: enable
|
|
6
|
+
TargetRubyVersion: 3.3
|
|
7
|
+
Exclude:
|
|
8
|
+
- "pkg/**/*"
|
|
9
|
+
- "vendor/**/*"
|
|
10
|
+
- "coverage/**/*"
|
|
11
|
+
- "reference-docs/**/*"
|
|
12
|
+
- "spec/fixtures/**/*"
|
|
13
|
+
|
|
14
|
+
Metrics/BlockLength:
|
|
15
|
+
Exclude:
|
|
16
|
+
- "spec/**/*"
|
|
17
|
+
- "*.gemspec"
|
|
18
|
+
|
|
19
|
+
Style/Documentation:
|
|
20
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ChemML are documented here.
|
|
4
|
+
This project follows [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- Initial gem scaffold: autoload tree, version, errors.
|
|
10
|
+
- CML namespace declaration (`Chemicalml::Cml::Namespace`) for the CML
|
|
11
|
+
default XML namespace.
|
|
12
|
+
- CML model classes for the core CML element set:
|
|
13
|
+
`Document`, `Molecule`, `AtomArray`, `Atom`, `BondArray`, `Bond`,
|
|
14
|
+
`Reaction`, `ReactantList`, `Reactant`, `ProductList`, `Product`,
|
|
15
|
+
`ReactionList`, `Name`, `Identifier`.
|
|
16
|
+
- AsciiChem extension namespace (`Chemicalml::Ext::Namespace`) for
|
|
17
|
+
attributes CML doesn't natively cover (lone pairs, radical
|
|
18
|
+
electrons, stereochemistry).
|
|
19
|
+
- Round-trip specs covering canonical CML fragments.
|
|
20
|
+
|
|
21
|
+
[Unreleased]: https://github.com/lutaml/chemicalml/commits/main
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What this gem is
|
|
6
|
+
|
|
7
|
+
Chemicalml is a Ruby object model for the Chemical Markup Language (CML),
|
|
8
|
+
the XML standard published at http://www.xml-cml.org/. It is a sibling
|
|
9
|
+
model layer to other chemistry tooling (AsciiChem consumes it via the
|
|
10
|
+
translator adapter) and is built on
|
|
11
|
+
[lutaml-model](https://github.com/lutaml/lutaml-model) — there is no
|
|
12
|
+
hand-rolled XML serialization anywhere in this library.
|
|
13
|
+
|
|
14
|
+
The repo targets **two schema versions** simultaneously:
|
|
15
|
+
`reference-docs/schemas/schema24/schema.xsd` and
|
|
16
|
+
`reference-docs/schemas/schema3/schema.xsd`. Both XSDs ship in-tree;
|
|
17
|
+
they are the source of truth for element/attribute names.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
bundle install # one-time
|
|
23
|
+
bundle exec rspec # full suite
|
|
24
|
+
bundle exec rspec spec/chemicalml/cml/molecule_spec.rb # one file
|
|
25
|
+
bundle exec rspec -e "round-trips" # by name match
|
|
26
|
+
bundle exec rake # alias for rspec
|
|
27
|
+
bundle exec rubocop # lint
|
|
28
|
+
bundle exec rubocop -A # autocorrect
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`spec/examples.txt` and `Gemfile.lock` are gitignored — `spec/examples.txt`
|
|
32
|
+
is regenerated by RSpec on every run, and `Gemfile.lock` is development-only.
|
|
33
|
+
|
|
34
|
+
## Architecture (big picture)
|
|
35
|
+
|
|
36
|
+
There are **five namespaces** under `Chemicalml`, deliberately kept
|
|
37
|
+
independent:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Chemicalml
|
|
41
|
+
├── parse(xml, schema: :schema3) # top-level entry point
|
|
42
|
+
├── Model # canonical, format-agnostic chemistry objects
|
|
43
|
+
├── Cml # CML XML wire-format classes
|
|
44
|
+
│ ├── Base::* # shared attribute+mapping mixins
|
|
45
|
+
│ ├── Schema3::* # Schema 3 wire classes
|
|
46
|
+
│ ├── Schema24::* # Schema 2.4 wire classes
|
|
47
|
+
│ └── Translator # the only adapter between Model and Cml
|
|
48
|
+
├── Schema # version registry
|
|
49
|
+
├── Convention # 5 conventions + constraint framework
|
|
50
|
+
└── Dictionary # dictionary model + YAML store
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Schema-versioned wire classes (mirrors `mml` V3/V4 pattern)
|
|
54
|
+
|
|
55
|
+
Both Schema 3 and Schema 2.4 have **real, distinct** class hierarchies
|
|
56
|
+
at `Chemicalml::Cml::Schema3::*` and `Chemicalml::Cml::Schema24::*`.
|
|
57
|
+
They share attribute and XML-mapping declarations via
|
|
58
|
+
`Chemicalml::Cml::Base::*` mixins (each Base module declares
|
|
59
|
+
attributes and an `xml do ... end` block inside a `self.included`
|
|
60
|
+
hook). Schema-specific deviations would live in additional
|
|
61
|
+
`Base::Schema3Only::*` / `Base::Schema24Only::*` modules included
|
|
62
|
+
only by the relevant version's classes — Open/Closed Principle.
|
|
63
|
+
|
|
64
|
+
Each schema owns a `Configuration` sub-module that registers its
|
|
65
|
+
wire classes with `Lutaml::Model::GlobalContext` under a context id
|
|
66
|
+
(`:chemicalml_schema3`, `:chemicalml_schema24`). Each wire class
|
|
67
|
+
declares `def self.lutaml_default_register` returning its context id,
|
|
68
|
+
which lets `from_xml(xml, register: ctx)` correctly resolve child
|
|
69
|
+
element types.
|
|
70
|
+
|
|
71
|
+
The top-level `Chemicalml::Cml::*` constants (e.g. `Cml::Atom`,
|
|
72
|
+
`Cml::Molecule`) are **backward-compatible aliases** pointing at the
|
|
73
|
+
Schema3 versions. New code should prefer the versioned namespaces
|
|
74
|
+
directly.
|
|
75
|
+
|
|
76
|
+
### Top-level entry points
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
Chemicalml.parse(xml) # → Schema3::Document (default)
|
|
80
|
+
Chemicalml.parse(xml, schema: :schema24) # → Schema24::Document
|
|
81
|
+
Chemicalml.serialize(document) # → XML string
|
|
82
|
+
Chemicalml::Cml::Schema3.parse(xml) # version-specific
|
|
83
|
+
Chemicalml::Cml::Schema24.parse(xml) # version-specific
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### The canonical model (`Chemicalml::Model::*`)
|
|
87
|
+
|
|
88
|
+
Plain Ruby `Node` subclasses. **No XML, no JSON, no YAML**. Format-agnostic.
|
|
89
|
+
Every adapter speaks this model; adapters never talk to each other directly.
|
|
90
|
+
`Node` provides `accept(visitor)`, `value_attributes`, `children`, and
|
|
91
|
+
class-level `short_name` so visitors written against the canonical model
|
|
92
|
+
work across every adapter.
|
|
93
|
+
|
|
94
|
+
### The CML wire layer (`Chemicalml::Cml::*`)
|
|
95
|
+
|
|
96
|
+
Every CML element is a `Lutaml::Model::Serializable` subclass that
|
|
97
|
+
includes three mixins: a `Base::*` module (shared declarations +
|
|
98
|
+
xml mapping + `namespace Chemicalml::Cml::Namespace`), a
|
|
99
|
+
`Role::*` marker module (type identity used by constraints and the
|
|
100
|
+
translator — independent of which schema version's class it is), and
|
|
101
|
+
`Cml::Visitable` (uniform interface for the constraint walker —
|
|
102
|
+
`wire_children`, `node_id`, `element_name`).
|
|
103
|
+
|
|
104
|
+
Wire classes are generated in-place by each schema module from the
|
|
105
|
+
shared `Chemicalml::Cml::Elements::ALL` table — no 70+ boilerplate
|
|
106
|
+
files. Adding a new CML element = adding one entry to `Elements::ALL`,
|
|
107
|
+
one `Base::*` mixin, and one `Role::*` module. Both `Schema3::*` and
|
|
108
|
+
`Schema24::*` pick up the new element automatically (unless it's
|
|
109
|
+
listed in `Elements::SCHEMA3_ONLY`).
|
|
110
|
+
|
|
111
|
+
The framework handles (de)serialization; **never** add `def to_xml` /
|
|
112
|
+
`def from_xml` /
|
|
113
|
+
`def to_h` to these classes.
|
|
114
|
+
|
|
115
|
+
### The translator (`Chemicalml::Cml::Translator`)
|
|
116
|
+
|
|
117
|
+
Pure transformation. `to_canonical(wire_doc)` accepts either Schema3
|
|
118
|
+
or Schema24 wire documents (dispatches via `is_a?`).
|
|
119
|
+
`from_canonical(model_doc, schema: :schema3)` produces the requested
|
|
120
|
+
schema's wire format. It is the **only** place that imports both
|
|
121
|
+
`Chemicalml::Model` and `Chemicalml::Cml`. Adding a new CML element
|
|
122
|
+
means updating translator rules — the two namespaces stay decoupled.
|
|
123
|
+
|
|
124
|
+
### Schema versions
|
|
125
|
+
|
|
126
|
+
`Chemicalml::Schema::Registry` is the registry for schema versions
|
|
127
|
+
(`schema24`, `schema3`). The schema XSDs are **archival source** —
|
|
128
|
+
they must never be deleted, edited, or regenerated from code.
|
|
129
|
+
|
|
130
|
+
### Conventions
|
|
131
|
+
|
|
132
|
+
`Chemicalml::Convention` is a registry of named constraint sets
|
|
133
|
+
(`molecular`, `compchem`, `dictionary`, `unit-dictionary`,
|
|
134
|
+
`unitType-dictionary`). Each convention owns:
|
|
135
|
+
|
|
136
|
+
- a namespace URI (e.g. `http://www.xml-cml.org/convention/molecular`)
|
|
137
|
+
- a set of constraint classes registered against it
|
|
138
|
+
|
|
139
|
+
Constraints are **registered**, not switch-statement'd — adding a new
|
|
140
|
+
rule = registering a new constraint class, not editing existing
|
|
141
|
+
renderer code (Open/Closed Principle).
|
|
142
|
+
|
|
143
|
+
The constraint walker uses `Cml::Visitable#wire_children` to traverse
|
|
144
|
+
the tree — no `respond_to?` duck typing.
|
|
145
|
+
|
|
146
|
+
### Dictionaries
|
|
147
|
+
|
|
148
|
+
`Chemicalml::Dictionary` is the model; entries have `id`, `term`,
|
|
149
|
+
`definition`, `description`, `dataType`, `unitType`, `units`, optional
|
|
150
|
+
`enum` (open or closed set), `links`, and `source_code`. Built-in
|
|
151
|
+
dictionaries ship as YAML under `data/dictionaries/` and are loaded
|
|
152
|
+
into a registry at startup.
|
|
153
|
+
|
|
154
|
+
## Coding standards (project-specific)
|
|
155
|
+
|
|
156
|
+
These are non-negotiable and apply in addition to the user's global rules:
|
|
157
|
+
|
|
158
|
+
1. **No `require_relative` and no intra-library `require`** anywhere in
|
|
159
|
+
`lib/`. Use Ruby `autoload`, declared in the immediate parent
|
|
160
|
+
namespace's file (create the file if it doesn't exist). Example:
|
|
161
|
+
`lib/chemicalml/foo.rb` declares `autoload :Bar, "chemicalml/foo/bar"`.
|
|
162
|
+
|
|
163
|
+
2. **Never hand-roll serialization.** No `def to_h`, `def from_h`,
|
|
164
|
+
`def to_xml`, `def from_xml`, `def to_json`, `def from_json` on
|
|
165
|
+
model classes. Wire names live in `mapping` blocks; round-trips go
|
|
166
|
+
through lutaml-model.
|
|
167
|
+
|
|
168
|
+
3. **Never use `double` in specs.** Use real model instances or
|
|
169
|
+
`Struct.new` for plain data.
|
|
170
|
+
|
|
171
|
+
4. **Never use `send` to call private methods, `instance_variable_set`/`get`,
|
|
172
|
+
or `respond_to?` for type checks.** Use `is_a?` or design the type
|
|
173
|
+
hierarchy so the check isn't needed.
|
|
174
|
+
|
|
175
|
+
5. **One concern, one place (MECE).** Adding a CML element = adding one
|
|
176
|
+
model class + one Cml class + one translator rule + specs. Don't
|
|
177
|
+
entangle them.
|
|
178
|
+
|
|
179
|
+
## Reference docs (in-tree)
|
|
180
|
+
|
|
181
|
+
`reference-docs/` holds archival source material downloaded from
|
|
182
|
+
xml-cml.org:
|
|
183
|
+
|
|
184
|
+
- `schemas/schema24/schema.xsd`, `schemas/schema3/schema.xsd` — the XSDs
|
|
185
|
+
- `conventions/` — convention specs (molecular, compchem, dictionary, etc.)
|
|
186
|
+
- `cmllite.html` — the CMLLite paper
|
|
187
|
+
|
|
188
|
+
These files are **source material, not derived output**. Never delete
|
|
189
|
+
or edit them. Treat them as canonical references when designing model
|
|
190
|
+
classes.
|
|
191
|
+
|
|
192
|
+
## Fixtures
|
|
193
|
+
|
|
194
|
+
`spec/fixtures/` holds CML example documents scraped from
|
|
195
|
+
xml-cml.org/examples/, organized by schema version and category
|
|
196
|
+
(`schema3/molecular/`, `schema3/compchem/`, `schema24/`). The scrape
|
|
197
|
+
is one-shot via `bundle exec rake fixtures:scrape` — re-run only when
|
|
198
|
+
the upstream examples change.
|
data/Gemfile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
group :development do
|
|
8
|
+
gem "canon"
|
|
9
|
+
gem "nokogiri"
|
|
10
|
+
gem "rake", "~> 13.2"
|
|
11
|
+
gem "rspec", "~> 3.13"
|
|
12
|
+
gem "rubocop", "~> 1.66", require: false
|
|
13
|
+
gem "simplecov", "~> 0.22", require: false
|
|
14
|
+
end
|
data/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Ribose Inc.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
19
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/NOTICES.adoc
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
= Chemicalml — Third-Party Notices
|
|
2
|
+
|
|
3
|
+
Chemicalml is distributed under the BSD-2-Clause license. See
|
|
4
|
+
link:LICENSE[LICENSE] for the full text.
|
|
5
|
+
|
|
6
|
+
== Acknowledgements
|
|
7
|
+
|
|
8
|
+
Chemicalml builds directly on the Chemical Markup Language (CML), a
|
|
9
|
+
long-running community project hosted at http://www.xml-cml.org/. The
|
|
10
|
+
CML schema, conventions, dictionaries, and example documents are the
|
|
11
|
+
work of many people over more than two decades. We acknowledge with
|
|
12
|
+
gratitude the people who built CML and continue to maintain it.
|
|
13
|
+
|
|
14
|
+
=== Editors and authors of the convention specifications
|
|
15
|
+
|
|
16
|
+
* **Sam Adams** (University of Cambridge) — editor of the molecular,
|
|
17
|
+
compchem, dictionary, unit-dictionary, and unitType-dictionary
|
|
18
|
+
convention specifications
|
|
19
|
+
* **Joe Townsend** (University of Cambridge) — editor of the molecular,
|
|
20
|
+
compchem, dictionary, unit-dictionary, and unitType-dictionary
|
|
21
|
+
convention specifications
|
|
22
|
+
* **Weerapong Phadungsukanan** (University of Cambridge) — editor of
|
|
23
|
+
the CompChem convention; author of the CompChem dictionary
|
|
24
|
+
* **Jens Thomas** (STFC Daresbury Laboratory) — editor of the CompChem
|
|
25
|
+
convention
|
|
26
|
+
* **Peter Murray-Rust** (University of Cambridge) — originator of CML,
|
|
27
|
+
author of the CompChem dictionary, driving force behind CML's
|
|
28
|
+
evolution
|
|
29
|
+
* **Alex Wade**, **Nick England**, **Daniel Lowe**, **Hannah Barjat**,
|
|
30
|
+
**Egon Willighagen** — contributors to the convention specifications
|
|
31
|
+
and dictionaries
|
|
32
|
+
|
|
33
|
+
=== The xml-cml.org project
|
|
34
|
+
|
|
35
|
+
The http://www.xml-cml.org/[xml-cml.org] website is the canonical home
|
|
36
|
+
of CML — schema files, convention specifications, dictionaries, example
|
|
37
|
+
documents, and validation tooling. We are grateful to the entire CML
|
|
38
|
+
community for keeping the project alive and openly licensed.
|
|
39
|
+
|
|
40
|
+
== Third-party content redistributed in this repository
|
|
41
|
+
|
|
42
|
+
The following files derive from upstream sources at xml-cml.org and are
|
|
43
|
+
licensed under the
|
|
44
|
+
http://creativecommons.org/licenses/by/3.0/[Creative Commons Attribution
|
|
45
|
+
3.0 Unported License (CC-BY-3.0)]:
|
|
46
|
+
|
|
47
|
+
=== CML schema XSDs
|
|
48
|
+
|
|
49
|
+
* `reference-docs/schemas/schema3/schema.xsd` — the official CML
|
|
50
|
+
Schema 3 XSD
|
|
51
|
+
* `reference-docs/schemas/schema24/schema.xsd` — the official CML
|
|
52
|
+
Schema 2.4 XSD
|
|
53
|
+
|
|
54
|
+
=== Convention specifications (HTML originals archived as Markdown)
|
|
55
|
+
|
|
56
|
+
* `reference-docs/conventions/index.md`
|
|
57
|
+
* `reference-docs/conventions/molecular.md`
|
|
58
|
+
* `reference-docs/conventions/compchem.md`
|
|
59
|
+
* `reference-docs/conventions/dictionary.md`
|
|
60
|
+
* `reference-docs/conventions/unit-dictionary.md`
|
|
61
|
+
* `reference-docs/conventions/unitType-dictionary.md`
|
|
62
|
+
|
|
63
|
+
=== Dictionary source content
|
|
64
|
+
|
|
65
|
+
* `reference-docs/dictionaries/index.md` — landing page
|
|
66
|
+
* `reference-docs/dictionaries/compchem.md` — CompChem dictionary
|
|
67
|
+
source content
|
|
68
|
+
|
|
69
|
+
The YAML representation of the CompChem dictionary at
|
|
70
|
+
`data/dictionaries/compchem.yaml` is derived from the upstream XML at
|
|
71
|
+
http://www.xml-cml.org/dictionary/compchem/[xml-cml.org/dictionary/compchem/].
|
|
72
|
+
|
|
73
|
+
=== Example CML documents
|
|
74
|
+
|
|
75
|
+
Example CML files under `spec/fixtures/` are derived from
|
|
76
|
+
http://www.xml-cml.org/examples/[xml-cml.org/examples/]. Each
|
|
77
|
+
subdirectory corresponds to an upstream category:
|
|
78
|
+
|
|
79
|
+
* `spec/fixtures/schema3/molecular/` — Schema 3 molecular examples
|
|
80
|
+
* `spec/fixtures/schema3/compchem/` — Schema 3 compchem examples
|
|
81
|
+
* `spec/fixtures/schema24/` — Schema 2.4 examples
|
|
82
|
+
|
|
83
|
+
Some seed fixtures in this directory are synthetic (created for this
|
|
84
|
+
gem) and are not subject to the upstream license; the BSD-2-Clause
|
|
85
|
+
license of this gem applies to those.
|
|
86
|
+
|
|
87
|
+
== Creative Commons Attribution 3.0 Unported License
|
|
88
|
+
|
|
89
|
+
For the upstream content listed above:
|
|
90
|
+
|
|
91
|
+
----
|
|
92
|
+
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
|
|
93
|
+
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
|
|
94
|
+
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
|
|
95
|
+
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
|
|
96
|
+
PROHIBITED.
|
|
97
|
+
|
|
98
|
+
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
|
|
99
|
+
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS
|
|
100
|
+
LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU
|
|
101
|
+
THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH
|
|
102
|
+
TERMS AND CONDITIONS.
|
|
103
|
+
|
|
104
|
+
Full license text: http://creativecommons.org/licenses/by/3.0/legalcode
|
|
105
|
+
----
|
|
106
|
+
|
|
107
|
+
== Attribution for derived works
|
|
108
|
+
|
|
109
|
+
The Ruby wire-format classes in `lib/chemicalml/cml/`, the canonical
|
|
110
|
+
model in `lib/chemicalml/model/`, the convention framework in
|
|
111
|
+
`lib/chemicalml/convention/`, and the dictionary layer in
|
|
112
|
+
`lib/chemicalml/dictionary/` are original work of the Chemicalml gem
|
|
113
|
+
authors, distributed under the BSD-2-Clause license of this gem. They
|
|
114
|
+
implement the semantics described by the upstream CML specifications
|
|
115
|
+
but contain no upstream source code or text.
|
data/README.adoc
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
= ChemML
|
|
2
|
+
|
|
3
|
+
ChemML provides a https://www.xml-cml.org/[Chemical Markup Language (CML)]
|
|
4
|
+
object model for Ruby, built on
|
|
5
|
+
{lutaml-model}[https://github.com/lutaml/lutaml-model].
|
|
6
|
+
|
|
7
|
+
== Purpose
|
|
8
|
+
|
|
9
|
+
CML is the established XML standard for chemistry. Existing Ruby
|
|
10
|
+
libraries either don't exist or use hand-rolled XML manipulation that
|
|
11
|
+
drifts from the CML schema. ChemML gives CML a proper model layer
|
|
12
|
+
with declarative attribute/mapping definitions and framework-backed
|
|
13
|
+
serialization.
|
|
14
|
+
|
|
15
|
+
== Install
|
|
16
|
+
|
|
17
|
+
Add to your Gemfile:
|
|
18
|
+
|
|
19
|
+
[source,ruby]
|
|
20
|
+
----
|
|
21
|
+
gem "chemicalml"
|
|
22
|
+
----
|
|
23
|
+
|
|
24
|
+
Or install directly:
|
|
25
|
+
|
|
26
|
+
[source,sh]
|
|
27
|
+
----
|
|
28
|
+
$ gem install chemicalml
|
|
29
|
+
----
|
|
30
|
+
|
|
31
|
+
== Usage
|
|
32
|
+
|
|
33
|
+
Parse a CML document:
|
|
34
|
+
|
|
35
|
+
[source,ruby]
|
|
36
|
+
----
|
|
37
|
+
require "chemicalml"
|
|
38
|
+
|
|
39
|
+
doc = Chemicalml::Cml::Document.from_xml(File.read("ethanol.cml"))
|
|
40
|
+
doc.molecules.first.atoms.first.element_type # => "C"
|
|
41
|
+
----
|
|
42
|
+
|
|
43
|
+
Build a document programmatically:
|
|
44
|
+
|
|
45
|
+
[source,ruby]
|
|
46
|
+
----
|
|
47
|
+
atom = Chemicalml::Cml::Atom.new(id: "a1", element_type: "C")
|
|
48
|
+
mol = Chemicalml::Cml::Molecule.new(id: "m1", atoms: [atom])
|
|
49
|
+
doc = Chemicalml::Cml::Document.new(molecules: [mol])
|
|
50
|
+
|
|
51
|
+
doc.to_xml # => well-formed CML XML
|
|
52
|
+
----
|
|
53
|
+
|
|
54
|
+
== Design
|
|
55
|
+
|
|
56
|
+
Each CML element is a `Lutaml::Model::Serializable` subclass with
|
|
57
|
+
declared attributes and an XML mapping block. Serialization goes
|
|
58
|
+
through lutaml-model — no hand-rolled XML.
|
|
59
|
+
|
|
60
|
+
The library is designed as a sibling model layer to other chemistry
|
|
61
|
+
tooling. AsciiChem (https://www.asciichem.org) uses ChemML for CML
|
|
62
|
+
round-trip support via a translator adapter.
|
|
63
|
+
|
|
64
|
+
Both Schema 2.4 and Schema 3 are supported via
|
|
65
|
+
`Chemicalml::Cml::Schema3` and `Chemicalml::Cml::Schema24` namespaces
|
|
66
|
+
(see `lib/chemicalml/schema.rb`).
|
|
67
|
+
|
|
68
|
+
The CML conventions (molecular, compchem, dictionary, unit-dictionary,
|
|
69
|
+
unitType-dictionary) are implemented as registered constraint sets in
|
|
70
|
+
`Chemicalml::Convention`. Built-in dictionaries ship as YAML under
|
|
71
|
+
`data/dictionaries/`.
|
|
72
|
+
|
|
73
|
+
== Acknowledgements
|
|
74
|
+
|
|
75
|
+
CML is the work of the http://www.xml-cml.org/[xml-cml.org] community,
|
|
76
|
+
edited by Sam Adams, Joe Townsend, Weerapong Phadungsukanan, and Jens
|
|
77
|
+
Thomas, with originator Peter Murray-Rust and contributors Alex Wade,
|
|
78
|
+
Nick England, Daniel Lowe, Hannah Barjat, and Egon Willighagen. The
|
|
79
|
+
schema, conventions, dictionaries, and examples are licensed by
|
|
80
|
+
xml-cml.org under
|
|
81
|
+
http://creativecommons.org/licenses/by/3.0/[CC-BY-3.0]. See
|
|
82
|
+
link:NOTICES.adoc[NOTICES.adoc] for full attribution of upstream
|
|
83
|
+
content redistributed in this gem.
|
|
84
|
+
|
|
85
|
+
== License
|
|
86
|
+
|
|
87
|
+
BSD-2-Clause. See link:LICENSE[LICENSE].
|
data/Rakefile
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# 01 — Cml::Base shared mixins
|
|
2
|
+
|
|
3
|
+
**Status:** complete
|
|
4
|
+
**Depends on:** —
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
|
|
8
|
+
Extract every CML element's `attribute` + `xml do ... end` declarations
|
|
9
|
+
into a reusable mixin under `Chemicalml::Cml::Base::*`. Each schema
|
|
10
|
+
version's wire class then includes the relevant Base module and adds
|
|
11
|
+
only its version-specific deviations.
|
|
12
|
+
|
|
13
|
+
This mirrors `mml`'s `lib/mml/base/` directory: shared declarations
|
|
14
|
+
live in modules, version namespaces consume them via `include`.
|
|
15
|
+
|
|
16
|
+
## Why
|
|
17
|
+
|
|
18
|
+
Without this factoring:
|
|
19
|
+
|
|
20
|
+
- Adding a new schema version means duplicating every class body.
|
|
21
|
+
- Schema-specific deviations touch the shared class — violates OCP.
|
|
22
|
+
- Constraint code can't reason about a uniform interface.
|
|
23
|
+
|
|
24
|
+
With Base mixins:
|
|
25
|
+
|
|
26
|
+
- Adding Schema5 later = new namespace that includes the same Base
|
|
27
|
+
modules plus its own additions.
|
|
28
|
+
- Schema24-specific behavior is added in `Base::Schema24Only::*`
|
|
29
|
+
modules, included only by Schema24 classes.
|
|
30
|
+
|
|
31
|
+
## Deliverables
|
|
32
|
+
|
|
33
|
+
- [ ] `lib/chemicalml/cml/base.rb` — namespace file with autoloads
|
|
34
|
+
- [ ] `lib/chemicalml/cml/base/atom.rb` — `Base::Atom` mixin
|
|
35
|
+
- [ ] `lib/chemicalml/cml/base/atom_array.rb`
|
|
36
|
+
- [ ] `lib/chemicalml/cml/base/bond.rb`
|
|
37
|
+
- [ ] `lib/chemicalml/cml/base/bond_array.rb`
|
|
38
|
+
- [ ] `lib/chemicalml/cml/base/document.rb`
|
|
39
|
+
- [ ] `lib/chemicalml/cml/base/formula.rb`
|
|
40
|
+
- [ ] `lib/chemicalml/cml/base/identifier.rb`
|
|
41
|
+
- [ ] `lib/chemicalml/cml/base/label.rb`
|
|
42
|
+
- [ ] `lib/chemicalml/cml/base/list.rb`
|
|
43
|
+
- [ ] `lib/chemicalml/cml/base/matrix.rb`
|
|
44
|
+
- [ ] `lib/chemicalml/cml/base/metadata.rb`
|
|
45
|
+
- [ ] `lib/chemicalml/cml/base/metadata_list.rb`
|
|
46
|
+
- [ ] `lib/chemicalml/cml/base/module.rb`
|
|
47
|
+
- [ ] `lib/chemicalml/cml/base/molecule.rb`
|
|
48
|
+
- [ ] `lib/chemicalml/cml/base/name.rb`
|
|
49
|
+
- [ ] `lib/chemicalml/cml/base/parameter.rb`
|
|
50
|
+
- [ ] `lib/chemicalml/cml/base/parameter_list.rb`
|
|
51
|
+
- [ ] `lib/chemicalml/cml/base/product.rb`
|
|
52
|
+
- [ ] `lib/chemicalml/cml/base/product_list.rb`
|
|
53
|
+
- [ ] `lib/chemicalml/cml/base/property.rb`
|
|
54
|
+
- [ ] `lib/chemicalml/cml/base/property_list.rb`
|
|
55
|
+
- [ ] `lib/chemicalml/cml/base/reaction.rb`
|
|
56
|
+
- [ ] `lib/chemicalml/cml/base/reaction_list.rb`
|
|
57
|
+
- [ ] `lib/chemicalml/cml/base/reactant.rb`
|
|
58
|
+
- [ ] `lib/chemicalml/cml/base/reactant_list.rb`
|
|
59
|
+
- [ ] `lib/chemicalml/cml/base/scalar.rb`
|
|
60
|
+
- [ ] `lib/chemicalml/cml/base/array.rb`
|
|
61
|
+
- [ ] `lib/chemicalml/cml/base/substance.rb`
|
|
62
|
+
- [ ] `lib/chemicalml/cml/base/atom_parity.rb`
|
|
63
|
+
- [ ] `lib/chemicalml/cml/base/bond_stereo.rb`
|
|
64
|
+
- [ ] `lib/chemicalml/cml/base/dictionary.rb`
|
|
65
|
+
- [ ] `lib/chemicalml/cml/base/dictionary_entry.rb`
|
|
66
|
+
- [ ] `lib/chemicalml/cml/base/unit.rb`
|
|
67
|
+
- [ ] `lib/chemicalml/cml/base/unit_list.rb`
|
|
68
|
+
- [ ] `lib/chemicalml/cml/base/unit_type.rb`
|
|
69
|
+
- [ ] `lib/chemicalml/cml/base/unit_type_list.rb`
|
|
70
|
+
|
|
71
|
+
## Pattern
|
|
72
|
+
|
|
73
|
+
Each Base module follows the same shape:
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
# lib/chemicalml/cml/base/atom.rb
|
|
77
|
+
module Chemicalml
|
|
78
|
+
module Cml
|
|
79
|
+
module Base
|
|
80
|
+
module Atom
|
|
81
|
+
def self.included(klass)
|
|
82
|
+
klass.class_eval do
|
|
83
|
+
attribute :id, :string
|
|
84
|
+
attribute :element_type, :string
|
|
85
|
+
# ...
|
|
86
|
+
|
|
87
|
+
xml do
|
|
88
|
+
root "atom"
|
|
89
|
+
map_attribute "id", to: :id
|
|
90
|
+
map_attribute "elementType", to: :element_type
|
|
91
|
+
# ...
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The schema-versioned wire class is then a thin shell:
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
# lib/chemicalml/cml/schema3/atom.rb
|
|
105
|
+
module Chemicalml
|
|
106
|
+
module Cml
|
|
107
|
+
module Schema3
|
|
108
|
+
class Atom < Lutaml::Model::Serializable
|
|
109
|
+
include Base::Atom
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Acceptance
|
|
117
|
+
|
|
118
|
+
- All 36 Base mixin files exist, one per CML element.
|
|
119
|
+
- Existing `Chemicalml::Cml::*` classes still load (they will be
|
|
120
|
+
refactored in task 02 to include the Base modules).
|
|
121
|
+
- No `require_relative` — Base autoloads declared in
|
|
122
|
+
`lib/chemicalml/cml/base.rb`.
|