chemicalml 0.2.0 → 0.3.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 +4 -4
- data/.github/workflows/release.yml +7 -1
- data/.rubocop.yml +23 -0
- data/CLAUDE.md +95 -40
- data/README.adoc +154 -26
- data/TODO.align/36-molecular-convention-coverage.md +46 -0
- data/TODO.align/37-compchem-convention-coverage.md +55 -0
- data/TODO.align/38-dictionary-convention-coverage.md +34 -0
- data/TODO.align/39-unit-dictionary-convention-coverage.md +33 -0
- data/TODO.align/40-unit-type-dictionary-convention-coverage.md +28 -0
- data/TODO.align/41-expand-canonical-model-layer.md +43 -0
- data/TODO.align/42-translator-wire-new-models.md +31 -0
- data/TODO.align/43-dictionary-model-no-to-h.md +39 -0
- data/TODO.align/44-schema3-only-and-schema24-module.md +44 -0
- data/TODO.align/45-documentation-and-final-verification.md +23 -0
- data/TODO.align/46-lattice-vector-content.md +24 -0
- data/TODO.align/47-molecule-crystal-spectra-property-lists.md +23 -0
- data/TODO.align/48-model-list-and-module-lists.md +21 -0
- data/TODO.align/49-more-chemistry-models.md +34 -0
- data/TODO.align/50-validation-report.md +29 -0
- data/TODO.align/51-convention-auto-detection.md +30 -0
- data/TODO.align/52-schema24-legacy-elements.md +28 -0
- data/TODO.align/53-round-trip-integration-specs.md +30 -0
- data/TODO.align/54-document-versioned-parser-shim.md +38 -0
- data/TODO.align/55-molecule-missing-attributes.md +20 -0
- data/TODO.align/56-geometry-models.md +24 -0
- data/TODO.align/57-compchem-models.md +26 -0
- data/TODO.align/58-remaining-models.md +24 -0
- data/TODO.align/59-wire-new-models-translator.md +18 -0
- data/TODO.align/60-docs-and-final-verification.md +19 -0
- data/TODO.align/61-parallel-array-attrs.md +54 -0
- data/TODO.align/62-per-element-attribute-gaps.md +49 -0
- data/TODO.align/63-universal-children-mixin.md +42 -0
- data/TODO.align/64-per-element-child-gaps.md +81 -0
- data/TODO.align/65-simple-unit-convention.md +40 -0
- data/TODO.align/66-schema24-legacy-children.md +32 -0
- data/TODO.align/67-final-verification.md +32 -0
- data/TODO.align/68-detection-coverage.md +33 -0
- data/TODO.align/69-json-yaml-roundtrip.md +27 -0
- data/TODO.align/70-iterative-walker.md +40 -0
- data/TODO.align/71-violation-value.md +25 -0
- data/TODO.align/72-close-child-gaps.md +66 -0
- data/TODO.align/73-schema24-parse-limitation.md +64 -0
- data/TODO.align/74-final-verification-round18.md +15 -0
- data/TODO.align/75-key-value-mappings.md +43 -0
- data/TODO.align/76-schema24-workaround.md +57 -0
- data/TODO.align/77-convention-coverage-matrix.md +31 -0
- data/TODO.align/78-fixture-audit.md +23 -0
- data/TODO.align/79-final-verification-round19.md +15 -0
- data/TODO.align/80-xsd-enum-constants.md +35 -0
- data/TODO.align/81-enum-validation-constraints.md +29 -0
- data/TODO.align/82-reference-resolver.md +33 -0
- data/TODO.align/83-toml-roundtrip.md +20 -0
- data/TODO.align/84-final-verification-round21.md +16 -0
- data/TODO.align/85-bond-distinct-atoms.md +25 -0
- data/TODO.align/86-references-should-resolve.md +20 -0
- data/TODO.align/87-cli-utility.md +26 -0
- data/TODO.align/88-diverse-fixtures.md +26 -0
- data/TODO.align/89-final-verification-round22.md +15 -0
- data/TODO.align/90-bond-stereo-completeness.md +31 -0
- data/TODO.align/91-atomparity-distinct.md +21 -0
- data/TODO.align/92-unit-dictionary-completeness.md +28 -0
- data/TODO.align/93-yard-docs.md +23 -0
- data/TODO.align/94-final-verification-round23.md +15 -0
- data/TODO.align/README.round17.md +28 -0
- data/TODO.align/README.round18.md +37 -0
- data/TODO.align/README.round19.md +40 -0
- data/TODO.align/README.round20.md +49 -0
- data/TODO.align/README.round21.md +35 -0
- data/TODO.align/README.round22.md +48 -0
- data/TODO.align/README.round23.md +46 -0
- data/TODO.align/README.round24.md +53 -0
- data/TODO.align/README.round25.md +66 -0
- data/TODO.align/README.round26.md +55 -0
- data/TODO.align/README.round27.md +51 -0
- data/TODO.align/README.round28.md +61 -0
- data/TODO.align/README.round29.md +64 -0
- data/TODO.align/README.round30.md +50 -0
- data/TODO.align/README.round31.md +54 -0
- data/TODO.align/README.round32.md +67 -0
- data/TODO.align/README.round33.md +62 -0
- data/TODO.align/README.round34.md +70 -0
- data/docs/constraints.md +161 -0
- data/docs/generate_constraint_docs.rb +44 -0
- data/exe/chemicalml +6 -0
- data/lib/chemicalml/cli/base.rb +68 -0
- data/lib/chemicalml/cli/command.rb +43 -0
- data/lib/chemicalml/cli/constraints_command.rb +27 -0
- data/lib/chemicalml/cli/conventions_command.rb +14 -0
- data/lib/chemicalml/cli/dictionaries_command.rb +14 -0
- data/lib/chemicalml/cli/elements_command.rb +17 -0
- data/lib/chemicalml/cli/enums_command.rb +17 -0
- data/lib/chemicalml/cli/info_command.rb +77 -0
- data/lib/chemicalml/cli/inspect_command.rb +39 -0
- data/lib/chemicalml/cli/validate_command.rb +54 -0
- data/lib/chemicalml/cli.rb +43 -0
- data/lib/chemicalml/cml/base/abundance.rb +21 -5
- data/lib/chemicalml/cml/base/action.rb +44 -6
- data/lib/chemicalml/cml/base/action_list.rb +44 -8
- data/lib/chemicalml/cml/base/alternative.rb +37 -0
- data/lib/chemicalml/cml/base/amount.rb +15 -5
- data/lib/chemicalml/cml/base/angle.rb +34 -7
- data/lib/chemicalml/cml/base/annotation.rb +38 -0
- data/lib/chemicalml/cml/base/any_cml.rb +12 -5
- data/lib/chemicalml/cml/base/appinfo.rb +40 -0
- data/lib/chemicalml/cml/base/arg.rb +80 -0
- data/lib/chemicalml/cml/base/array.rb +51 -8
- data/lib/chemicalml/cml/base/array_list.rb +15 -5
- data/lib/chemicalml/cml/base/atom.rb +93 -19
- data/lib/chemicalml/cml/base/atom_array.rb +77 -2
- data/lib/chemicalml/cml/base/atom_parity.rb +18 -2
- data/lib/chemicalml/cml/base/atom_set.rb +15 -5
- data/lib/chemicalml/cml/base/atom_type.rb +27 -7
- data/lib/chemicalml/cml/base/atom_type_list.rb +23 -7
- data/lib/chemicalml/cml/base/atomic_basis_function.rb +35 -11
- data/lib/chemicalml/cml/base/band.rb +22 -7
- data/lib/chemicalml/cml/base/band_list.rb +15 -7
- data/lib/chemicalml/cml/base/basis_set.rb +26 -7
- data/lib/chemicalml/cml/base/bond.rb +39 -7
- data/lib/chemicalml/cml/base/bond_array.rb +41 -2
- data/lib/chemicalml/cml/base/bond_set.rb +15 -5
- data/lib/chemicalml/cml/base/bond_stereo.rb +25 -4
- data/lib/chemicalml/cml/base/bond_type.rb +24 -7
- data/lib/chemicalml/cml/base/bond_type_list.rb +23 -7
- data/lib/chemicalml/cml/base/cell_parameter.rb +30 -8
- data/lib/chemicalml/cml/base/cml_module.rb +36 -11
- data/lib/chemicalml/cml/base/common_children.rb +35 -0
- data/lib/chemicalml/cml/base/complex_object.rb +37 -0
- data/lib/chemicalml/cml/base/condition_list.rb +28 -8
- data/lib/chemicalml/cml/base/crystal.rb +27 -9
- data/lib/chemicalml/cml/base/definition.rb +12 -5
- data/lib/chemicalml/cml/base/description.rb +15 -5
- data/lib/chemicalml/cml/base/dictionary.rb +30 -7
- data/lib/chemicalml/cml/base/dictionary_entry.rb +67 -8
- data/lib/chemicalml/cml/base/dimension.rb +31 -7
- data/lib/chemicalml/cml/base/document.rb +18 -8
- data/lib/chemicalml/cml/base/documentation.rb +12 -5
- data/lib/chemicalml/cml/base/eigen.rb +33 -7
- data/lib/chemicalml/cml/base/electron.rb +29 -9
- data/lib/chemicalml/cml/base/enumeration.rb +41 -0
- data/lib/chemicalml/cml/base/expression.rb +47 -0
- data/lib/chemicalml/cml/base/float.rb +52 -0
- data/lib/chemicalml/cml/base/float_array.rb +55 -0
- data/lib/chemicalml/cml/base/formula.rb +31 -10
- data/lib/chemicalml/cml/base/fragment.rb +33 -9
- data/lib/chemicalml/cml/base/fragment_list.rb +26 -7
- data/lib/chemicalml/cml/base/gradient.rb +19 -6
- data/lib/chemicalml/cml/base/identifier.rb +22 -4
- data/lib/chemicalml/cml/base/integer.rb +52 -0
- data/lib/chemicalml/cml/base/integer_array.rb +55 -0
- data/lib/chemicalml/cml/base/isotope.rb +29 -8
- data/lib/chemicalml/cml/base/isotope_list.rb +18 -7
- data/lib/chemicalml/cml/base/join.rb +28 -6
- data/lib/chemicalml/cml/base/kpoint.rb +17 -6
- data/lib/chemicalml/cml/base/kpoint_list.rb +15 -7
- data/lib/chemicalml/cml/base/label.rb +15 -5
- data/lib/chemicalml/cml/base/lattice.rb +36 -9
- data/lib/chemicalml/cml/base/lattice_vector.rb +17 -6
- data/lib/chemicalml/cml/base/length.rb +31 -7
- data/lib/chemicalml/cml/base/line3.rb +21 -5
- data/lib/chemicalml/cml/base/link.rb +51 -10
- data/lib/chemicalml/cml/base/list.rb +23 -9
- data/lib/chemicalml/cml/base/map.rb +38 -5
- data/lib/chemicalml/cml/base/matrix.rb +38 -9
- data/lib/chemicalml/cml/base/mechanism.rb +20 -7
- data/lib/chemicalml/cml/base/mechanism_component.rb +14 -6
- data/lib/chemicalml/cml/base/metadata.rb +20 -6
- data/lib/chemicalml/cml/base/metadata_list.rb +30 -5
- data/lib/chemicalml/cml/base/molecule.rb +95 -21
- data/lib/chemicalml/cml/base/molecule_list.rb +27 -7
- data/lib/chemicalml/cml/base/name.rb +11 -3
- data/lib/chemicalml/cml/base/object.rb +20 -6
- data/lib/chemicalml/cml/base/observation.rb +18 -5
- data/lib/chemicalml/cml/base/operator.rb +40 -0
- data/lib/chemicalml/cml/base/parameter.rb +38 -8
- data/lib/chemicalml/cml/base/parameter_list.rb +30 -5
- data/lib/chemicalml/cml/base/particle.rb +23 -6
- data/lib/chemicalml/cml/base/peak.rb +86 -11
- data/lib/chemicalml/cml/base/peak_group.rb +81 -7
- data/lib/chemicalml/cml/base/peak_list.rb +25 -8
- data/lib/chemicalml/cml/base/peak_structure.rb +47 -6
- data/lib/chemicalml/cml/base/plane3.rb +15 -5
- data/lib/chemicalml/cml/base/point3.rb +15 -5
- data/lib/chemicalml/cml/base/potential.rb +17 -6
- data/lib/chemicalml/cml/base/potential_form.rb +31 -6
- data/lib/chemicalml/cml/base/potential_list.rb +15 -7
- data/lib/chemicalml/cml/base/product.rb +53 -2
- data/lib/chemicalml/cml/base/product_list.rb +36 -2
- data/lib/chemicalml/cml/base/property.rb +32 -8
- data/lib/chemicalml/cml/base/property_list.rb +26 -5
- data/lib/chemicalml/cml/base/reactant.rb +53 -2
- data/lib/chemicalml/cml/base/reactant_list.rb +36 -2
- data/lib/chemicalml/cml/base/reaction.rb +82 -12
- data/lib/chemicalml/cml/base/reaction_list.rb +29 -2
- data/lib/chemicalml/cml/base/reaction_scheme.rb +48 -8
- data/lib/chemicalml/cml/base/reaction_step.rb +33 -9
- data/lib/chemicalml/cml/base/reaction_step_list.rb +34 -7
- data/lib/chemicalml/cml/base/reactive_centre.rb +31 -6
- data/lib/chemicalml/cml/base/region.rb +24 -5
- data/lib/chemicalml/cml/base/related_entry.rb +34 -0
- data/lib/chemicalml/cml/base/sample.rb +32 -5
- data/lib/chemicalml/cml/base/scalar.rb +41 -6
- data/lib/chemicalml/cml/base/spectator.rb +26 -5
- data/lib/chemicalml/cml/base/spectator_list.rb +20 -7
- data/lib/chemicalml/cml/base/spectrum.rb +63 -12
- data/lib/chemicalml/cml/base/spectrum_data.rb +20 -8
- data/lib/chemicalml/cml/base/spectrum_list.rb +30 -7
- data/lib/chemicalml/cml/base/sphere3.rb +15 -5
- data/lib/chemicalml/cml/base/stmml.rb +12 -5
- data/lib/chemicalml/cml/base/string.rb +40 -0
- data/lib/chemicalml/cml/base/string_array.rb +52 -0
- data/lib/chemicalml/cml/base/substance.rb +42 -8
- data/lib/chemicalml/cml/base/substance_list.rb +32 -7
- data/lib/chemicalml/cml/base/symmetry.rb +33 -7
- data/lib/chemicalml/cml/base/system.rb +23 -8
- data/lib/chemicalml/cml/base/table.rb +43 -8
- data/lib/chemicalml/cml/base/table_cell.rb +12 -5
- data/lib/chemicalml/cml/base/table_content.rb +20 -8
- data/lib/chemicalml/cml/base/table_header.rb +15 -7
- data/lib/chemicalml/cml/base/table_header_cell.rb +27 -5
- data/lib/chemicalml/cml/base/table_row.rb +15 -7
- data/lib/chemicalml/cml/base/table_row_list.rb +15 -7
- data/lib/chemicalml/cml/base/tcell.rb +43 -0
- data/lib/chemicalml/cml/base/torsion.rb +34 -7
- data/lib/chemicalml/cml/base/transform3.rb +12 -5
- data/lib/chemicalml/cml/base/transition_state.rb +23 -5
- data/lib/chemicalml/cml/base/trow.rb +48 -0
- data/lib/chemicalml/cml/base/unit.rb +45 -10
- data/lib/chemicalml/cml/base/unit_list.rb +40 -6
- data/lib/chemicalml/cml/base/unit_type.rb +32 -5
- data/lib/chemicalml/cml/base/unit_type_list.rb +34 -6
- data/lib/chemicalml/cml/base/vector3.rb +15 -5
- data/lib/chemicalml/cml/base/xaxis.rb +33 -7
- data/lib/chemicalml/cml/base/yaxis.rb +33 -7
- data/lib/chemicalml/cml/base/z_matrix.rb +26 -5
- data/lib/chemicalml/cml/base.rb +139 -121
- data/lib/chemicalml/cml/canonical_comparison.rb +54 -0
- data/lib/chemicalml/cml/elements.rb +168 -124
- data/lib/chemicalml/cml/enums.rb +55 -0
- data/lib/chemicalml/cml/namespace.rb +2 -3
- data/lib/chemicalml/cml/patterns.rb +33 -0
- data/lib/chemicalml/cml/reference_resolver.rb +137 -0
- data/lib/chemicalml/cml/role/alternative.rb +10 -0
- data/lib/chemicalml/cml/role/annotation.rb +10 -0
- data/lib/chemicalml/cml/role/appinfo.rb +10 -0
- data/lib/chemicalml/cml/role/arg.rb +10 -0
- data/lib/chemicalml/cml/role/cml_module.rb +2 -3
- data/lib/chemicalml/cml/role/complex_object.rb +10 -0
- data/lib/chemicalml/cml/role/enumeration.rb +10 -0
- data/lib/chemicalml/cml/role/expression.rb +10 -0
- data/lib/chemicalml/cml/role/float.rb +10 -0
- data/lib/chemicalml/cml/role/float_array.rb +10 -0
- data/lib/chemicalml/cml/role/integer.rb +10 -0
- data/lib/chemicalml/cml/role/integer_array.rb +10 -0
- data/lib/chemicalml/cml/role/operator.rb +10 -0
- data/lib/chemicalml/cml/role/related_entry.rb +10 -0
- data/lib/chemicalml/cml/role/string.rb +10 -0
- data/lib/chemicalml/cml/role/string_array.rb +10 -0
- data/lib/chemicalml/cml/role/tcell.rb +10 -0
- data/lib/chemicalml/cml/role/trow.rb +10 -0
- data/lib/chemicalml/cml/role.rb +138 -121
- data/lib/chemicalml/cml/schema24/alternative.rb +14 -0
- data/lib/chemicalml/cml/schema24/annotation.rb +15 -0
- data/lib/chemicalml/cml/schema24/appinfo.rb +15 -0
- data/lib/chemicalml/cml/schema24/arg.rb +14 -0
- data/lib/chemicalml/cml/schema24/cml_module.rb +18 -0
- data/lib/chemicalml/cml/schema24/complex_object.rb +14 -0
- data/lib/chemicalml/cml/schema24/configuration.rb +15 -2
- data/lib/chemicalml/cml/schema24/enumeration.rb +16 -0
- data/lib/chemicalml/cml/schema24/expression.rb +14 -0
- data/lib/chemicalml/cml/schema24/float.rb +14 -0
- data/lib/chemicalml/cml/schema24/float_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/integer.rb +14 -0
- data/lib/chemicalml/cml/schema24/integer_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/operator.rb +14 -0
- data/lib/chemicalml/cml/schema24/related_entry.rb +14 -0
- data/lib/chemicalml/cml/schema24/string.rb +14 -0
- data/lib/chemicalml/cml/schema24/string_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/tcell.rb +14 -0
- data/lib/chemicalml/cml/schema24/trow.rb +14 -0
- data/lib/chemicalml/cml/schema24.rb +154 -126
- data/lib/chemicalml/cml/schema3.rb +123 -123
- data/lib/chemicalml/cml/visitable.rb +77 -3
- data/lib/chemicalml/cml/wire_class_registry.rb +3 -3
- data/lib/chemicalml/cml.rb +164 -132
- data/lib/chemicalml/context_configuration.rb +12 -4
- data/lib/chemicalml/convention/base.rb +17 -3
- data/lib/chemicalml/convention/cascade/constraints/reaction_scheme_must_have_content.rb +33 -0
- data/lib/chemicalml/convention/cascade/constraints/reaction_step_list_must_contain_steps.rb +31 -0
- data/lib/chemicalml/convention/cascade/constraints/reaction_step_must_have_reaction_or_lists.rb +33 -0
- data/lib/chemicalml/convention/cascade/constraints/reactive_centre_atom_refs_should_be_present.rb +34 -0
- data/lib/chemicalml/convention/cascade/constraints.rb +18 -0
- data/lib/chemicalml/convention/cascade.rb +43 -0
- data/lib/chemicalml/convention/compchem/constraints/array_rules.rb +44 -0
- data/lib/chemicalml/convention/compchem/constraints/calculation_requires_finalization.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +5 -4
- data/lib/chemicalml/convention/compchem/constraints/environment_at_most_one_property_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_must_have_content.rb +44 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_must_not_contain_parameter.rb +27 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_must_have_content.rb +54 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_must_not_contain_property.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/job_list_module_must_have_id.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_environment.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_must_have_id.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +7 -9
- data/lib/chemicalml/convention/compchem/constraints/matrix_rules.rb +48 -0
- data/lib/chemicalml/convention/compchem/constraints/module_predicates.rb +50 -0
- data/lib/chemicalml/convention/compchem/constraints/scalar_units.rb +42 -0
- data/lib/chemicalml/convention/compchem/constraints.rb +40 -2
- data/lib/chemicalml/convention/compchem.rb +20 -2
- data/lib/chemicalml/convention/constraint.rb +68 -24
- data/lib/chemicalml/convention/coordinator.rb +90 -0
- data/lib/chemicalml/convention/detection.rb +39 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace.rb +29 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash.rb +32 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern.rb +33 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +4 -4
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_contain_definition.rb +29 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +6 -6
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_unit_type.rb +31 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_units_co_constraints.rb +44 -0
- data/lib/chemicalml/convention/dictionary/constraints.rb +14 -2
- data/lib/chemicalml/convention/dictionary.rb +8 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula.rb +41 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +18 -9
- data/lib/chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired.rb +6 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_element_type_should_be_in_periodic_table.rb +39 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_id_must_match_pattern.rb +7 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +3 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_element_type.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_id.rb +5 -4
- data/lib/chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom.rb +65 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_array_must_be_child_of_molecule.rb +37 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_atom_refs2_should_be_distinct.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_id_should_match_pattern.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_ids_unique_within_molecule.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_order.rb +5 -4
- data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +4 -3
- data/lib/chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref.rb +34 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_should_be_in_enum.rb +39 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_should_not_be_numeric.rb +3 -3
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct.rb +43 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4.rb +45 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref.rb +33 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_should_be_in_enum.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb +45 -0
- data/lib/chemicalml/convention/molecular/constraints/dict_ref_should_resolve.rb +59 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_atom_array_mutually_exclusive_with_children.rb +33 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children.rb +32 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_chirality_should_be_in_enum.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb +35 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_id_should_match_pattern.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_must_have_id.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/property_must_have_dict_ref.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb +58 -0
- data/lib/chemicalml/convention/molecular/constraints/references_should_resolve.rb +37 -0
- data/lib/chemicalml/convention/molecular/constraints/scalar_must_have_data_type.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints.rb +59 -13
- data/lib/chemicalml/convention/molecular.rb +25 -2
- data/lib/chemicalml/convention/registry.rb +95 -10
- data/lib/chemicalml/convention/simple_unit/constraints/root_must_be_unit_list.rb +24 -0
- data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_power.rb +32 -0
- data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_symbol.rb +31 -0
- data/lib/chemicalml/convention/simple_unit/constraints.rb +16 -0
- data/lib/chemicalml/convention/simple_unit.rb +37 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/peak_list_must_contain_peaks.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/peak_should_have_values.rb +34 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_content.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_convention.rb +32 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_format.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints.rb +20 -0
- data/lib/chemicalml/convention/spectroscopy.rb +41 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_contain_at_least_one_unit.rb +29 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_have_namespace.rb +36 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_contain_definition.rb +28 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_id.rb +28 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_multiplier_or_constant_to_si.rb +34 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_parent_si.rb +32 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_symbol_and_unit_type.rb +4 -4
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_title.rb +32 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_parent_si_should_resolve.rb +45 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_unit_type_should_resolve.rb +46 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints.rb +19 -1
- data/lib/chemicalml/convention/unit_dictionary.rb +11 -2
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_id_must_match_pattern.rb +31 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_contain_at_least_one_unit_type.rb +28 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_have_namespace.rb +35 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_contain_definition.rb +28 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +6 -6
- data/lib/chemicalml/convention/unit_type_dictionary/constraints.rb +9 -1
- data/lib/chemicalml/convention/unit_type_dictionary.rb +6 -2
- data/lib/chemicalml/convention/validation_report.rb +90 -0
- data/lib/chemicalml/convention/violation.rb +9 -3
- data/lib/chemicalml/convention.rb +49 -11
- data/lib/chemicalml/dictionary/entry.rb +6 -6
- data/lib/chemicalml/dictionary/enum.rb +1 -1
- data/lib/chemicalml/dictionary/link.rb +3 -3
- data/lib/chemicalml/dictionary/loader.rb +19 -19
- data/lib/chemicalml/dictionary/model.rb +5 -5
- data/lib/chemicalml/dictionary/registry.rb +9 -9
- data/lib/chemicalml/dictionary.rb +13 -9
- data/lib/chemicalml/logger.rb +47 -0
- data/lib/chemicalml/schema/definition.rb +2 -2
- data/lib/chemicalml/schema.rb +7 -7
- data/lib/chemicalml/version.rb +1 -1
- data/lib/chemicalml/versioned_parser.rb +28 -10
- data/lib/chemicalml.rb +79 -17
- data/lib/tasks/reference_fetch.rake +30 -31
- data/lib/tasks/scrape_fixtures.rake +23 -24
- metadata +235 -35
- data/lib/chemicalml/cml/child_mappings.rb +0 -168
- data/lib/chemicalml/cml/translator/value_translations.rb +0 -270
- data/lib/chemicalml/cml/translator.rb +0 -484
- data/lib/chemicalml/model/atom.rb +0 -64
- data/lib/chemicalml/model/atom_parity.rb +0 -21
- data/lib/chemicalml/model/bond.rb +0 -39
- data/lib/chemicalml/model/bond_stereo.rb +0 -29
- data/lib/chemicalml/model/cml_array.rb +0 -27
- data/lib/chemicalml/model/cml_module.rb +0 -45
- data/lib/chemicalml/model/document.rb +0 -29
- data/lib/chemicalml/model/formula.rb +0 -34
- data/lib/chemicalml/model/identifier.rb +0 -21
- data/lib/chemicalml/model/label.rb +0 -21
- data/lib/chemicalml/model/matrix.rb +0 -29
- data/lib/chemicalml/model/metadata.rb +0 -23
- data/lib/chemicalml/model/metadata_list.rb +0 -25
- data/lib/chemicalml/model/molecule.rb +0 -45
- data/lib/chemicalml/model/name.rb +0 -21
- data/lib/chemicalml/model/node.rb +0 -45
- data/lib/chemicalml/model/parameter.rb +0 -27
- data/lib/chemicalml/model/parameter_list.rb +0 -25
- data/lib/chemicalml/model/product.rb +0 -21
- data/lib/chemicalml/model/product_list.rb +0 -21
- data/lib/chemicalml/model/property.rb +0 -28
- data/lib/chemicalml/model/property_list.rb +0 -25
- data/lib/chemicalml/model/reactant.rb +0 -21
- data/lib/chemicalml/model/reactant_list.rb +0 -21
- data/lib/chemicalml/model/reaction.rb +0 -41
- data/lib/chemicalml/model/reaction_list.rb +0 -23
- data/lib/chemicalml/model/scalar.rb +0 -25
- data/lib/chemicalml/model/substance.rb +0 -25
- data/lib/chemicalml/model.rb +0 -40
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Round 33 — CLI run(options) signature alignment
|
|
2
|
+
|
|
3
|
+
This round refactors every CLI command class so the run method
|
|
4
|
+
takes a single `options` hash, matching the user-requested
|
|
5
|
+
invocation pattern exactly:
|
|
6
|
+
|
|
7
|
+
MyCommandClass.new.run(options)
|
|
8
|
+
|
|
9
|
+
## Files
|
|
10
|
+
|
|
11
|
+
- [134 — CLI run(options) alignment](134-cli-run-options-alignment.md)
|
|
12
|
+
- [135 — Final verification round 33](135-final-verification-round33.md)
|
|
13
|
+
|
|
14
|
+
## Outcomes
|
|
15
|
+
|
|
16
|
+
- Every `Chemicalml::Cli::*Command` now implements
|
|
17
|
+
`def run(options)` (single hash argument). The hash carries both
|
|
18
|
+
positional args (keyed by name: `:file`, `:element`) and flags
|
|
19
|
+
(`:json`, etc.).
|
|
20
|
+
|
|
21
|
+
- `Chemicalml::Cli::Base` (Thor dispatcher) builds the options hash
|
|
22
|
+
for each command and calls `<Name>Command.new.run(hash)`. Example:
|
|
23
|
+
```ruby
|
|
24
|
+
desc "validate FILE", "..."
|
|
25
|
+
method_option :json, type: :boolean, aliases: "-j"
|
|
26
|
+
def validate(file)
|
|
27
|
+
ValidateCommand.new.run(file: file, json: options[:json])
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- Each command supports both invocation styles:
|
|
32
|
+
- Instance: `MyCommand.new.run(options)` (primary, per user spec)
|
|
33
|
+
- Class: `MyCommand.run(options)` (convenience, delegates to instance)
|
|
34
|
+
|
|
35
|
+
- Bug fix: validation guards `return warn(...), 2 unless path`
|
|
36
|
+
were returning `[warn_result, 2]` (array) instead of integer 2.
|
|
37
|
+
Rewrote as explicit `warn; return 2` two-line guards.
|
|
38
|
+
|
|
39
|
+
- CLI spec updated to test both invocation styles. 17 specs covering
|
|
40
|
+
every command via `MyCommandClass.new.run(options)` direct call.
|
|
41
|
+
|
|
42
|
+
- **593 examples, 0 failures, 3 pending**. Zero forbidden patterns.
|
|
43
|
+
|
|
44
|
+
## Architectural insight
|
|
45
|
+
|
|
46
|
+
The single-hash `run(options)` signature is more flexible than the
|
|
47
|
+
prior `(args, options)` split:
|
|
48
|
+
|
|
49
|
+
- Positional args are named (`file:`, `element:`), not positional.
|
|
50
|
+
Easier to extend (add a new arg = add a new hash key, no method
|
|
51
|
+
signature change).
|
|
52
|
+
- Same hash carries flags (`json:`, etc.). One argument, one source
|
|
53
|
+
of truth.
|
|
54
|
+
- Commands are unit-testable in isolation without Thor:
|
|
55
|
+
```ruby
|
|
56
|
+
Chemicalml::Cli::ValidateCommand.new.run(file: "x.cml", json: true)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The Thor dispatcher is now truly just routing — it parses CLI input
|
|
60
|
+
and constructs the options hash. Every command class can be reused
|
|
61
|
+
from Rake tasks, RSpec tests, or web handlers without going through
|
|
62
|
+
Thor at all.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Round 34 — Constraint descriptions, diverse fixtures, perf baseline, BIG perf fix
|
|
2
|
+
|
|
3
|
+
This round adds constraint-class descriptions, more diverse fixtures,
|
|
4
|
+
a performance baseline spec, and crucially **fixes a 680× performance
|
|
5
|
+
regression** discovered by the baseline spec.
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- [136 — Constraint descriptions](136-constraint-descriptions.md)
|
|
10
|
+
- [137 — More diverse fixtures](137-more-diverse-fixtures.md)
|
|
11
|
+
- [138 — Performance baseline spec](138-performance-baseline-spec.md)
|
|
12
|
+
- [139 — Final verification round 34](139-final-verification-round34.md)
|
|
13
|
+
|
|
14
|
+
## Outcomes
|
|
15
|
+
|
|
16
|
+
- **Constraint `description` class method** added to
|
|
17
|
+
`Convention::Constraint`. Each constraint can now carry a
|
|
18
|
+
human-readable description of the rule it enforces. Two molecular
|
|
19
|
+
constraints (`AtomMustHaveId`, `BondMustHaveOrder`) updated as
|
|
20
|
+
examples. `chemicalml constraints` command now shows descriptions
|
|
21
|
+
when present.
|
|
22
|
+
|
|
23
|
+
- **Three new diverse fixtures**:
|
|
24
|
+
- `molecular/ethylene_with_cis_trans_stereo.cml` — bondStereo with
|
|
25
|
+
`atomRefs4` (cis/trans case)
|
|
26
|
+
- `reactions/free_radical_halogenation.cml` — multi-reactant
|
|
27
|
+
reaction with substanceList catalyst
|
|
28
|
+
- `spectroscopy/ethanol_nmr.cml` — NMR spectrum with xaxis/yaxis
|
|
29
|
+
arrays, peakList with multiplicity, metadataList
|
|
30
|
+
|
|
31
|
+
- **Performance baseline spec** — establishes timing baselines for:
|
|
32
|
+
- XML/JSON serialisation of a 1000-atom molecule (< 2s)
|
|
33
|
+
- Molecular validation of a 1000-atom molecule (< 2s)
|
|
34
|
+
- `atom_count` / `find_atom` queries (< 500ms)
|
|
35
|
+
- Fixture parsing (< 20ms)
|
|
36
|
+
|
|
37
|
+
- **MAJOR performance fix**: the `ReferencesShouldResolve` constraint
|
|
38
|
+
was taking **47.8 seconds** on a 1000-atom document. Root cause:
|
|
39
|
+
`ReferenceResolver#unresolved_for` called `containing_molecule`
|
|
40
|
+
for every bond, which walked the entire document every time
|
|
41
|
+
(O(n²) for n bonds × n molecules × n atoms).
|
|
42
|
+
|
|
43
|
+
Fixed by:
|
|
44
|
+
- Adding lazily-built `atom_index` (id → Atom hash, O(1) lookup)
|
|
45
|
+
- Removing the `containing_molecule` indirection in
|
|
46
|
+
`unresolved_for` — the resolver now uses the global atom index
|
|
47
|
+
directly. CML semantics already enforce that bond refs live in
|
|
48
|
+
the parent molecule (that's `BondMustReferenceAtomsInSameMolecule`'s
|
|
49
|
+
job).
|
|
50
|
+
|
|
51
|
+
Result: **47.8s → 68ms (680× faster)**.
|
|
52
|
+
|
|
53
|
+
- **609 examples, 0 failures, 3 pending** (TOML adapter pending).
|
|
54
|
+
Zero forbidden patterns.
|
|
55
|
+
|
|
56
|
+
## Architectural insight
|
|
57
|
+
|
|
58
|
+
The performance baseline spec paid for itself immediately by catching
|
|
59
|
+
a 47-second regression that I'd introduced in round 22 when adding
|
|
60
|
+
the `ReferencesShouldResolve` constraint. Without the baseline,
|
|
61
|
+
this would have shipped to users.
|
|
62
|
+
|
|
63
|
+
The fix follows the **build indices once, query many times** pattern.
|
|
64
|
+
The resolver now builds an `atom_index` lazily on first lookup; all
|
|
65
|
+
subsequent `find_atom` calls are O(1). This is a Ruby-native
|
|
66
|
+
performance pattern that fits the existing architecture cleanly.
|
|
67
|
+
|
|
68
|
+
Lesson: baseline specs aren't just for regression detection — they
|
|
69
|
+
catch bugs that you didn't know you had. Always write the baseline
|
|
70
|
+
before optimising.
|
data/docs/constraints.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Registered Convention Constraints
|
|
2
|
+
|
|
3
|
+
Auto-generated from `Chemicalml::Convention::Registry.each_constraint`.
|
|
4
|
+
Last regenerated: 2026-07-20T09:43:53Z.
|
|
5
|
+
|
|
6
|
+
Total constraints: **91**
|
|
7
|
+
|
|
8
|
+
## convention:cascade
|
|
9
|
+
|
|
10
|
+
- **Namespace**: `http://www.xml-cml.org/convention/cascade`
|
|
11
|
+
- **Constraint count**: 4
|
|
12
|
+
|
|
13
|
+
| Constraint | Applies to | Description |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `ReactionSchemeMustHaveContent` | ReactionScheme | A `<reactionScheme>` MUST contain at least one `<reactionStepList>` or `<reaction>` child. An empty scheme carries no cascade information. |
|
|
16
|
+
| `ReactionStepListMustContainSteps` | ReactionStepList | A `<reactionStepList>` MUST contain at least one `<reactionStep>` child. An empty step list breaks the cascade chain. |
|
|
17
|
+
| `ReactionStepMustHaveReactionOrLists` | ReactionStep | A `<reactionStep>` MUST contain either a `<reaction>` child or explicit `<reactantList>` + `<productList>` children. An empty step is a dead-end in the cascade. |
|
|
18
|
+
| `ReactiveCentreAtomRefsShouldBePresent` | ReactiveCentre | A `<reactiveCentre>` SHOULD declare its `atomRefs` attribute. Without atom references the reactive centre is indistinguishable from a placeholder. Warning severity — |
|
|
19
|
+
|
|
20
|
+
## convention:compchem
|
|
21
|
+
|
|
22
|
+
- **Namespace**: `http://www.xml-cml.org/convention/compchem`
|
|
23
|
+
- **Constraint count**: 20
|
|
24
|
+
|
|
25
|
+
| Constraint | Applies to | Description |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `CompchemModuleMustContainJobList` | _(document-wide)_ | A CompChem module MUST contain at least one jobList module child per the compchem convention. |
|
|
28
|
+
| `JobMustContainInitialization` | Module | A job module MUST contain exactly one initialization module child per the compchem convention. |
|
|
29
|
+
| `JobListModuleMustHaveId` | Module | A jobList module MUST have an `id` unique within the compchem module. |
|
|
30
|
+
| `JobModuleMustHaveId` | Module | A job module MUST have an `id` unique within the compchem module. |
|
|
31
|
+
| `JobModuleAtMostOneFinalization` | Module | A job module MUST contain at most one finalization module. |
|
|
32
|
+
| `JobModuleAtMostOneEnvironment` | Module | A job module MUST contain at most one environment module. |
|
|
33
|
+
| `CalculationRequiresFinalization` | Module | Co-constraint: if a calculation module is present inside a job, a finalization MUST also be present. |
|
|
34
|
+
| `InitializationAtMostOneMolecule` | Module | The initialization module MUST NOT contain more than one molecule child. |
|
|
35
|
+
| `InitializationAtMostOneParameterList` | Module | The initialization module MUST NOT contain more than one parameterList child. |
|
|
36
|
+
| `InitializationMustNotContainProperty` | Module | The initialization module MUST NOT contain property or propertyList children directly. (Properties belong in finalization.) |
|
|
37
|
+
| `FinalizationAtMostOneMolecule` | Module | The finalization module MUST NOT contain more than one molecule child. |
|
|
38
|
+
| `FinalizationAtMostOnePropertyList` | Module | The finalization module MUST NOT contain more than one propertyList child. |
|
|
39
|
+
| `FinalizationMustNotContainParameter` | Module | The finalization module MUST NOT contain parameter or parameterList children directly. (Parameters belong in initialization.) |
|
|
40
|
+
| `EnvironmentAtMostOnePropertyList` | Module | The environment module MUST NOT contain more than one propertyList child. |
|
|
41
|
+
| `EnvironmentMustNotContainParameter` | Module | The environment module MUST NOT contain parameter or parameterList children directly. It MAY contain a propertyList (which itself can hold parameters). |
|
|
42
|
+
| `ScalarUnits` | Scalar | CompChem value-container rules: `scalar` with dataType `xsd:integer` or `xsd:double` MUST have `units`; `scalar` with dataType `xsd:string` MUST NOT have `units`. |
|
|
43
|
+
| `ArrayRules` | Array | CompChem `array` value-container rules: MUST have `size` attribute (≥ 1); `dataType` MUST be integer or double; MUST have `units`. |
|
|
44
|
+
| `MatrixRules` | Matrix | CompChem `matrix` value-container rules: MUST have `rows` and `columns` attributes (each ≥ 1); `dataType` MUST be integer or double; MUST have `units`. |
|
|
45
|
+
| `InitializationMustHaveContent` | Module | An `initialization` module MUST contain at least one of: `molecule`, `parameterList`, or a user-defined module child. Per the compchem convention spec. |
|
|
46
|
+
| `FinalizationMustHaveContent` | Module | A `finalization` module MUST contain at least one of: `molecule`, `propertyList`, or a user-defined module child. Per the compchem convention spec. |
|
|
47
|
+
|
|
48
|
+
## convention:dictionary
|
|
49
|
+
|
|
50
|
+
- **Namespace**: `http://www.xml-cml.org/convention/dictionary`
|
|
51
|
+
- **Constraint count**: 8
|
|
52
|
+
|
|
53
|
+
| Constraint | Applies to | Description |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `EntryMustHaveIdAndTerm` | DictionaryEntry | Every entry MUST have an `id` and a `term` attribute per the dictionary convention. |
|
|
56
|
+
| `EntryIdsUniqueWithinDictionary` | Dictionary | Entry ids MUST be unique within the parent dictionary per the dictionary convention. |
|
|
57
|
+
| `DictionaryMustHaveNamespace` | Dictionary | A `<dictionary>` element MUST have a `namespace` attribute whose value is a valid URI defining the scope within which the entry terms are unique. |
|
|
58
|
+
| `DictionaryNamespaceShouldEndWithSlashOrHash` | Dictionary | The `namespace` URI SHOULD end with `/` or `#` so terms can be referenced by appending them to the URI. Warning level. |
|
|
59
|
+
| `EntryMustContainDefinition` | DictionaryEntry | An `<entry>` MUST contain a single `definition` child element. The schema allows it as a string; this constraint enforces presence. |
|
|
60
|
+
| `EntryIdMustMatchPattern` | DictionaryEntry | An `<entry>` `id` MUST match `[A-Za-z][A-Za-z0-9._-]*` — start with a letter, followed by letters/digits/dot/hyphen/ underscore. Mirrors the upstream IdStartChar / IdChar BNF. |
|
|
61
|
+
| `EntryMustHaveUnitType` | DictionaryEntry | An `<entry>` MUST have a `unitType` attribute. Entries describing concepts that should not have units (e.g. name of a program) should reference `none` in the standard CML |
|
|
62
|
+
| `EntryUnitsCoConstraints` | DictionaryEntry | Co-constraint between `unitType` and `units`: - If `unitType` is `unknown`, `units` MUST NOT be present. - If `unitType` is `none`, `units` MUST be present and point |
|
|
63
|
+
|
|
64
|
+
## convention:molecular
|
|
65
|
+
|
|
66
|
+
- **Namespace**: `http://www.xml-cml.org/convention/molecular`
|
|
67
|
+
- **Constraint count**: 36
|
|
68
|
+
|
|
69
|
+
| Constraint | Applies to | Description |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `AtomArrayMustContainAtoms` | Molecule | `atomArray` MUST contain at least one atom. The atoms can be in the child form (`<atom>` elements) or the parallel-array form (`atomID` attribute with whitespace-separated ids). |
|
|
72
|
+
| `AtomIdsUniqueWithinMolecule` | _(document-wide)_ | Atom ids MUST be unique within the eldest containing molecule per the molecular convention. |
|
|
73
|
+
| `BondMustReferenceAtomsInSameMolecule` | _(document-wide)_ | Bonds MUST reference atoms within the same parent molecule per the molecular convention. |
|
|
74
|
+
| `AtomMustHaveId` | Atom | An <atom> inside an atomArray in a molecule MUST have an id attribute. |
|
|
75
|
+
| `AtomMustHaveElementType` | Atom | An <atom> inside an atomArray in a molecule MUST have an elementType attribute. |
|
|
76
|
+
| `BondMustHaveAtomRefs2` | Bond | A <bond> MUST have an atomRefs2 attribute referencing two distinct atoms in the same molecule. |
|
|
77
|
+
| `BondMustHaveOrder` | Bond | A <bond> MUST have an order attribute (S/D/T/A recommended). |
|
|
78
|
+
| `MoleculeMustHaveId` | Molecule | A <molecule> in a molecular document MUST have an id attribute unique within document scope. |
|
|
79
|
+
| `AtomCoordinatesMustBePaired` | Atom | <atom> 2D coordinates (x2, y2) must appear together; 3D coordinates (x3, y3, z3) must appear together. |
|
|
80
|
+
| `PropertyMustHaveDictRef` | Property | A <property> MUST have a dictRef attribute that identifies the property type via a dictionary entry. |
|
|
81
|
+
| `ScalarMustHaveDataType` | Scalar | A <scalar> child of a <property> MUST have a dataType attribute (e.g. xsd:float, xsd:integer). |
|
|
82
|
+
| `BondOrderShouldNotBeNumeric` | Bond | A <bond>'s order attribute SHOULD be one of S/D/T/Q/A or 'other' (numeric values are not recommended). |
|
|
83
|
+
| `AtomIdMustMatchPattern` | Atom | An <atom>'s id attribute SHOULD start with a letter and contain only letters, digits, dot, hyphen, or underscore. |
|
|
84
|
+
| `MoleculeCountMustNotAppearOnTopLevel` | _(document-wide)_ | Molecular convention: `count` MUST NOT appear on top-level molecules (direct children of `<cml>`). It is REQUIRED on molecules nested inside another `<molecule>`. |
|
|
85
|
+
| `MoleculeAtomArrayMutuallyExclusiveWithChildren` | Molecule | Molecular convention: a `<molecule>` MAY hold an `atomArray` OR child `<molecule>` elements, but not both. The two are mutually exclusive ways of describing composition. |
|
|
86
|
+
| `MoleculeBondArrayMutuallyExclusiveWithChildren` | Molecule | Molecular convention: a `<molecule>` MAY hold a `bondArray` OR child `<molecule>` elements, but not both. |
|
|
87
|
+
| `BondStereoWedgeHashMustHaveAtomRefs2` | BondStereo | Molecular convention: `<bondStereo>` value W (wedge) or H (hatch) MUST have `atomRefs2` and MUST NOT have `atomRefs4`. |
|
|
88
|
+
| `BondStereoCisTransMustHaveAtomRefs4` | BondStereo | Molecular convention: `<bondStereo>` value C (cis) or T (trans) MUST have `atomRefs4` and MUST NOT have `atomRefs2`. |
|
|
89
|
+
| `BondStereoOtherMustHaveDictRef` | BondStereo | Molecular convention: `<bondStereo>` with value `other` MUST have a `dictRef` pointing to the convention that defines the stereo semantics. |
|
|
90
|
+
| `BondIdsUniqueWithinMolecule` | _(document-wide)_ | Molecular convention: a `<bond>` `id` MUST be unique within the eldest containing molecule. Mirrors the existing `AtomIdsUniqueWithinMolecule` constraint for bonds. |
|
|
91
|
+
| `BondOrderOtherMustHaveDictRef` | Bond | Molecular convention: `<bond>` with `order="other"` MUST have a `dictRef` pointing to the dictionary that defines the order semantics. The warning-level "should not be |
|
|
92
|
+
| `AtomArrayMustBeChildOfMoleculeOrFormula` | _(document-wide)_ | Molecular convention: `<atomArray>` MUST be a child of `<molecule>` or `<formula>`. Any other parent is invalid. Checked from the parent's perspective during the walk — |
|
|
93
|
+
| `BondArrayMustBeChildOfMolecule` | _(document-wide)_ | Molecular convention: `<bondArray>` MUST be a child of `<molecule>`. Any other parent is invalid. |
|
|
94
|
+
| `BondOrderShouldBeInEnum` | Bond | A `<bond>`'s `order` attribute SHOULD be one of the XSD orderType enum values: S/1/D/2/T/3/A/unknown/other. Warning severity — CML permits extension values via |
|
|
95
|
+
| `BondStereoShouldBeInEnum` | BondStereo | A `<bondStereo>`'s `value` attribute SHOULD be one of the XSD stereoType enum values: C/T/W/H/undefined/other. Warning severity. |
|
|
96
|
+
| `MoleculeChiralityShouldBeInEnum` | Molecule | A `<molecule>`'s `chirality` attribute SHOULD be one of the XSD chiralityType enum values: enantiomer/racemate/unknown/other. Warning severity. |
|
|
97
|
+
| `BondAtomRefs2ShouldBeDistinct` | Bond | A `<bond>`'s `atomRefs2` SHOULD reference two distinct atom ids. A self-bond (`a1 a1`) is chemically meaningless. Warning severity — there are edge cases in non-classical |
|
|
98
|
+
| `ReferencesShouldResolve` | _(document-wide)_ | Walks the document via `Cml::ReferenceResolver` and reports every bond whose `atomRefs2` references atoms that don't exist in the parent molecule. Warning severity — there are |
|
|
99
|
+
| `BondStereoAtomRefs4ShouldBeDistinct` | BondStereo | A `<bondStereo>` with `atomRefs4` (used by C/T stereo) SHOULD reference four distinct atom ids. Duplicate ids make the stereo descriptor meaningless. Warning severity. |
|
|
100
|
+
| `AtomParityAtomRefs4ShouldBeDistinct` | AtomParity | An `<atomParity>` element's `atomRefs4` attribute SHOULD reference four distinct atom ids around a chiral center. Duplicate ids make the parity descriptor meaningless. |
|
|
101
|
+
| `AtomElementTypeShouldBeInPeriodicTable` | Atom | An `<atom>`'s `elementType` attribute SHOULD be one of the XSD elementTypeType enum values (the periodic table plus the special "Du" dummy and "R" group placeholder). Warns |
|
|
102
|
+
| `DictRefShouldResolve` | Atom, Bond, Molecule, Property, Scalar, Array, Matrix, Name, Label | Walks the document and warns on any element whose `dictRef` attribute cannot be resolved against the built-in dictionaries. Catches typos like `dictRef="cml:bpingpoint"`. |
|
|
103
|
+
| `MoleculeIdShouldMatchPattern` | Molecule | A `<molecule>`'s `id` attribute SHOULD match the XSD moleculeIDType pattern (letter/underscore start, alphanumeric body, optional namespace prefix). Warning severity. |
|
|
104
|
+
| `BondIdShouldMatchPattern` | Bond | A `<bond>`'s `id` attribute SHOULD match the XSD idType pattern (letter start, alphanumeric body with dots/dashes). Warning severity. |
|
|
105
|
+
| `AtomParityShouldIncludeParentAtom` | _(document-wide)_ | Walks the document and warns on `<atomParity>` elements whose parent `<atom>`'s id does not appear in atomRefs4. The CML convention requires the parent atom to be one of |
|
|
106
|
+
| `PropertyScalarDataTypeMatchesDictionary` | Property | A `<property>` with a `dictRef` whose dictionary entry declares a `dataType` SHOULD have a child `<scalar>` whose `dataType` attribute matches. Catches inconsistencies like a property |
|
|
107
|
+
|
|
108
|
+
## convention:simpleUnit
|
|
109
|
+
|
|
110
|
+
- **Namespace**: `http://www.xml-cml.org/convention/simpleUnit`
|
|
111
|
+
- **Constraint count**: 3
|
|
112
|
+
|
|
113
|
+
| Constraint | Applies to | Description |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `UnitMustHavePower` | Unit | A `<unit>` under simpleUnit MUST declare a `power` attribute (integer). Without a power the unit's exponent is undefined. |
|
|
116
|
+
| `UnitMustHaveSymbol` | Unit | A `<unit>` under simpleUnit MUST declare a non-empty `symbol` attribute. Without a symbol the unit cannot be rendered in formulae. |
|
|
117
|
+
| `RootMustBeUnitList` | _(document-wide)_ | The root of a simpleUnit document MUST be a `<unitList>` declaring `convention="convention:simpleUnit"`. Any other root shape is rejected. |
|
|
118
|
+
|
|
119
|
+
## convention:spectroscopy
|
|
120
|
+
|
|
121
|
+
- **Namespace**: `http://www.xml-cml.org/convention/spectroscopy`
|
|
122
|
+
- **Constraint count**: 5
|
|
123
|
+
|
|
124
|
+
| Constraint | Applies to | Description |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `SpectrumMustHaveConvention` | Spectrum | A `<spectrum>` MUST declare its own convention attribute so consumers know how to interpret its format and peaks. Per the molecular convention: "spectrum — any number, each MUST |
|
|
127
|
+
| `SpectrumMustHaveFormat` | Spectrum | A `<spectrum>` MUST have a `format` attribute (e.g. "mass", "ir", "nmr", "uv") so consumers know the measurement type. |
|
|
128
|
+
| `SpectrumMustHaveContent` | Spectrum | A `<spectrum>` MUST contain at least one of: `<xaxis>`, `<yaxis>`, `<peakList>`. An empty spectrum carries no data. |
|
|
129
|
+
| `PeakListMustContainPeaks` | PeakList | A `<peakList>` MUST contain at least one `<peak>` or `<peakGroup>` child. An empty peakList carries no data. |
|
|
130
|
+
| `PeakShouldHaveValues` | Peak | A `<peak>` SHOULD declare at least one of `xValue` or `yValue`. A peak with neither carries no position information. Warning severity — there are edge cases |
|
|
131
|
+
|
|
132
|
+
## convention:unit-dictionary
|
|
133
|
+
|
|
134
|
+
- **Namespace**: `http://www.xml-cml.org/convention/unit-dictionary`
|
|
135
|
+
- **Constraint count**: 10
|
|
136
|
+
|
|
137
|
+
| Constraint | Applies to | Description |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `UnitMustHaveSymbolAndUnitType` | Unit | Every unit MUST have `id`, `title`, `symbol`, `parentSI`, at least one of `multiplierToSI`/`constantToSI`, and `unitType` per the unit-dictionary convention. |
|
|
140
|
+
| `UnitMustHaveId` | Unit | A `<unit>` element MUST have an `id` attribute, unique within the unitList. |
|
|
141
|
+
| `UnitMustContainDefinition` | Unit | A `<unit>` element MUST contain a single `<definition>` child element with XHTML content. |
|
|
142
|
+
| `UnitListMustHaveNamespace` | UnitList | A `<unitList>` element MUST have a `namespace` attribute whose value is a valid URI defining the scope within which the unit ids are unique. SHOULD end with `/` or `#`. |
|
|
143
|
+
| `UnitListMustContainAtLeastOneUnit` | UnitList | A `<unitList>` element MUST contain one or more `<unit>` children, and MUST NOT contain any other CML-namespace child elements. |
|
|
144
|
+
| `UnitMustHaveTitle` | Unit | A `<unit>` element MUST have a `title` attribute (the full human-readable name of the unit). Per the unit-dictionary convention spec. |
|
|
145
|
+
| `UnitMustHaveParentSi` | Unit | A `<unit>` element MUST have a `parentSI` attribute — a QName referencing the SI unit it derives from. Per the unit-dictionary convention spec. |
|
|
146
|
+
| `UnitMustHaveMultiplierOrConstantToSi` | Unit | A `<unit>` element MUST have at least one of `multiplierToSI` or `constantToSI` — to define the conversion to the parent SI unit. Per the unit-dictionary convention spec. |
|
|
147
|
+
| `UnitUnitTypeShouldResolve` | Unit | A `<unit>`'s `unitType` attribute SHOULD reference a unitType that exists in a built-in unitType-dictionary. Catches typos like `unitType="unitType:lenght"` (misspelled). |
|
|
148
|
+
| `UnitParentSiShouldResolve` | Unit | A `<unit>`'s `parentSI` attribute SHOULD reference a unit that exists in a built-in dictionary (typically the SI dictionary). Catches typos like `parentSI="si:metr"`. |
|
|
149
|
+
|
|
150
|
+
## convention:unitType-dictionary
|
|
151
|
+
|
|
152
|
+
- **Namespace**: `http://www.xml-cml.org/convention/unitType-dictionary`
|
|
153
|
+
- **Constraint count**: 5
|
|
154
|
+
|
|
155
|
+
| Constraint | Applies to | Description |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `UnitTypeMustHaveIdAndName` | UnitType | Every unitType MUST have an `id` and a `name` attribute per the unitType-dictionary convention. |
|
|
158
|
+
| `UnitTypeIdMustMatchPattern` | UnitType | A `<unitType>` `id` MUST match `[A-Za-z][A-Za-z0-9._-]*`. |
|
|
159
|
+
| `UnitTypeMustContainDefinition` | UnitType | A `<unitType>` MUST contain a single `<definition>` child with XHTML content. |
|
|
160
|
+
| `UnitTypeListMustHaveNamespace` | UnitTypeList | A `<unitTypeList>` MUST have a `namespace` attribute (valid URI, SHOULD end with `/` or `#`). |
|
|
161
|
+
| `UnitTypeListMustContainAtLeastOneUnitType` | UnitTypeList | A `<unitTypeList>` MUST contain one or more `<unitType>` children. |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "chemicalml"
|
|
4
|
+
|
|
5
|
+
# Auto-generated documentation of every registered convention
|
|
6
|
+
# constraint. Run via `bundle exec rake docs:constraints` or
|
|
7
|
+
# `bundle exec ruby docs/generate_constraint_docs.rb`.
|
|
8
|
+
#
|
|
9
|
+
# Single source of truth: derived from `Convention::Registry.each_constraint`.
|
|
10
|
+
# Do not edit `docs/constraints.md` by hand — regenerate.
|
|
11
|
+
|
|
12
|
+
output = []
|
|
13
|
+
output << "# Registered Convention Constraints"
|
|
14
|
+
output << ""
|
|
15
|
+
output << "Auto-generated from `Chemicalml::Convention::Registry.each_constraint`."
|
|
16
|
+
output << "Last regenerated: #{Time.now.utc.iso8601}."
|
|
17
|
+
output << ""
|
|
18
|
+
output << "Total constraints: **#{Chemicalml::Convention::Registry.total_constraint_count}**"
|
|
19
|
+
output << ""
|
|
20
|
+
|
|
21
|
+
Chemicalml::Convention::Registry.each do |conv|
|
|
22
|
+
output << "## #{conv.qname}"
|
|
23
|
+
output << ""
|
|
24
|
+
output << "- **Namespace**: `#{conv.namespace_uri}`"
|
|
25
|
+
output << "- **Constraint count**: #{conv.constraint_count}"
|
|
26
|
+
output << ""
|
|
27
|
+
|
|
28
|
+
output << "| Constraint | Applies to | Description |"
|
|
29
|
+
output << "|---|---|---|"
|
|
30
|
+
conv.constraints.each do |klass|
|
|
31
|
+
name = klass.name.split("::").last
|
|
32
|
+
roles = klass.applies_to_roles
|
|
33
|
+
applies = roles.nil? ? "_(document-wide)_" : roles.map { |r| r.name.split("::").last }.join(", ")
|
|
34
|
+
desc = klass.description
|
|
35
|
+
desc = "" if desc == name
|
|
36
|
+
desc_escaped = desc.gsub("|", "\\|")
|
|
37
|
+
output << "| `#{name}` | #{applies} | #{desc_escaped} |"
|
|
38
|
+
end
|
|
39
|
+
output << ""
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
path = File.expand_path("constraints.md", __dir__)
|
|
43
|
+
File.write(path, output.join("\n"))
|
|
44
|
+
puts "Wrote #{path} (#{Chemicalml::Convention::Registry.total_constraint_count} constraints)"
|
data/exe/chemicalml
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor'
|
|
4
|
+
|
|
5
|
+
module Chemicalml
|
|
6
|
+
module Cli
|
|
7
|
+
# Thor-based dispatcher. Each command delegates to a dedicated
|
|
8
|
+
# `Chemicalml::Cli::*Command` class invoked as
|
|
9
|
+
# `MyCommand.new.run(options)`, where `options` is a single hash
|
|
10
|
+
# carrying both positional args (keyed by name) and flags.
|
|
11
|
+
#
|
|
12
|
+
# A `Chemicalml::Logger` bridged to Thor's shell is injected into
|
|
13
|
+
# every command — so info/warn/error get coloured output on the
|
|
14
|
+
# terminal while remaining loggable for library callers.
|
|
15
|
+
class Base < Thor
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Build a logger bridged to this Thor instance for coloured output.
|
|
19
|
+
def bridged_logger
|
|
20
|
+
Chemicalml::Logger.default.tap { |l| l.thor_shell = self }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
public
|
|
24
|
+
|
|
25
|
+
desc 'validate FILE', 'Validate a CML file against its declared convention'
|
|
26
|
+
method_option :json, type: :boolean, aliases: '-j',
|
|
27
|
+
desc: 'Emit machine-readable JSON output'
|
|
28
|
+
def validate(file)
|
|
29
|
+
ValidateCommand.new(logger: bridged_logger).run(file: file, json: options[:json])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc 'inspect FILE', 'Print a tree-style summary of the document'
|
|
33
|
+
def inspect(file)
|
|
34
|
+
InspectCommand.new(logger: bridged_logger).run(file: file)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
desc 'conventions', 'List registered conventions'
|
|
38
|
+
def conventions
|
|
39
|
+
ConventionsCommand.new(logger: bridged_logger).run({})
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc 'dictionaries', 'List built-in dictionaries'
|
|
43
|
+
def dictionaries
|
|
44
|
+
DictionariesCommand.new(logger: bridged_logger).run({})
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc 'elements', 'List all CML wire classes'
|
|
48
|
+
def elements
|
|
49
|
+
ElementsCommand.new(logger: bridged_logger).run({})
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc 'constraints', 'List all registered constraints'
|
|
53
|
+
def constraints
|
|
54
|
+
ConstraintsCommand.new(logger: bridged_logger).run({})
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
desc 'enums', 'List all XSD enum constants'
|
|
58
|
+
def enums
|
|
59
|
+
EnumsCommand.new(logger: bridged_logger).run({})
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
desc 'info ELEMENT', 'Show details about a CML element'
|
|
63
|
+
def info(element)
|
|
64
|
+
InfoCommand.new(logger: bridged_logger).run(element: element)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# Base class for every command. Subclasses implement `#run(options)`.
|
|
6
|
+
#
|
|
7
|
+
# Each command receives a `Chemicalml::Logger` in its constructor.
|
|
8
|
+
# When dispatched via Thor (the normal CLI path), the logger is
|
|
9
|
+
# bridged to Thor's shell for coloured output. When invoked
|
|
10
|
+
# directly (MyCommand.new.run(options)), the logger writes plain
|
|
11
|
+
# text to $stderr.
|
|
12
|
+
class Command
|
|
13
|
+
attr_reader :logger
|
|
14
|
+
|
|
15
|
+
# @param logger [Chemicalml::Logger] the logger to use. Defaults
|
|
16
|
+
# to a plain stderr logger. The Thor dispatcher passes one
|
|
17
|
+
# bridged to Thor's shell for colour.
|
|
18
|
+
def initialize(logger: Chemicalml::Logger.default)
|
|
19
|
+
@logger = logger
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def run(options = {}, logger: Chemicalml::Logger.default)
|
|
24
|
+
new(logger: logger).run(options)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def run(_options = {})
|
|
29
|
+
raise NotImplementedError, "#{self.class} must implement #run"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def puts(*args)
|
|
35
|
+
$stdout.puts(*args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def stderr(*args)
|
|
39
|
+
$stderr.puts(*args)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml constraints` — list every registered constraint
|
|
6
|
+
# across every convention with its applies_to roles.
|
|
7
|
+
class ConstraintsCommand < Command
|
|
8
|
+
def run(_options = {})
|
|
9
|
+
current = nil
|
|
10
|
+
Chemicalml::Convention::Registry.each_constraint do |conv, klass|
|
|
11
|
+
unless conv.qname == current
|
|
12
|
+
current = conv.qname
|
|
13
|
+
puts ''
|
|
14
|
+
puts "=== #{current} (#{conv.constraint_count}) ==="
|
|
15
|
+
end
|
|
16
|
+
name = klass.name.split('::').last
|
|
17
|
+
applies = klass.applies_to_roles
|
|
18
|
+
roles_str = applies.nil? ? '' : " → #{applies.map { |r| r.name.split('::').last }.join(', ')}"
|
|
19
|
+
puts " #{name}#{roles_str}"
|
|
20
|
+
desc = klass.description
|
|
21
|
+
puts " #{desc}" unless desc == name
|
|
22
|
+
end
|
|
23
|
+
0
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml conventions` — list every registered convention
|
|
6
|
+
# by QName, sorted.
|
|
7
|
+
class ConventionsCommand < Command
|
|
8
|
+
def run(_options = {})
|
|
9
|
+
Chemicalml::Convention::Registry.builtin_qnames.sort.each { |q| puts q }
|
|
10
|
+
0
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml dictionaries` — list built-in YAML dictionaries
|
|
6
|
+
# by short name.
|
|
7
|
+
class DictionariesCommand < Command
|
|
8
|
+
def run(_options = {})
|
|
9
|
+
Chemicalml::Dictionary::Registry.builtin_names.each { |n| puts n }
|
|
10
|
+
0
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml elements` — list every CML wire class registered
|
|
6
|
+
# in Schema3 with its XML element name.
|
|
7
|
+
class ElementsCommand < Command
|
|
8
|
+
def run(_options = {})
|
|
9
|
+
Chemicalml::Cml::Schema3::Configuration.ensure_registered!
|
|
10
|
+
Chemicalml::Cml::Elements::ALL.sort.each do |cls, xml_id|
|
|
11
|
+
puts "#{cls.to_s.ljust(25)} → <#{xml_id}>"
|
|
12
|
+
end
|
|
13
|
+
0
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml enums` — list every `Cml::Enums` constant with
|
|
6
|
+
# its allowed values.
|
|
7
|
+
class EnumsCommand < Command
|
|
8
|
+
def run(_options = {})
|
|
9
|
+
Chemicalml::Cml::Enums.constants(false).sort.each do |name|
|
|
10
|
+
values = Chemicalml::Cml::Enums.const_get(name)
|
|
11
|
+
puts "#{name} (#{values.size}): #{values.to_a.sort.first(20).join(', ')}"
|
|
12
|
+
end
|
|
13
|
+
0
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml info <element>` — show details about a CML element
|
|
6
|
+
# by XML name: Ruby class, role, attributes, applicable constraints.
|
|
7
|
+
class InfoCommand < Command
|
|
8
|
+
def run(options)
|
|
9
|
+
name = options[:element]
|
|
10
|
+
unless name
|
|
11
|
+
logger.error 'info requires an <element-name> argument (e.g. "atom")'
|
|
12
|
+
return 2
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
klass = Chemicalml::Cml.for_xml_name(name)
|
|
16
|
+
unless klass
|
|
17
|
+
stderr "unknown element: #{name}"
|
|
18
|
+
return 2
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Chemicalml::Cml::Schema3::Configuration.ensure_registered!
|
|
22
|
+
puts "Element: <#{name}>"
|
|
23
|
+
puts "Class: #{klass}"
|
|
24
|
+
role = role_of(klass)
|
|
25
|
+
puts "Role: #{role || '(none)'}"
|
|
26
|
+
puts ''
|
|
27
|
+
puts "Attributes (#{klass.attributes.size}):"
|
|
28
|
+
klass.attributes.each_value do |attr|
|
|
29
|
+
col = attr.collection? ? '[]' : ' '
|
|
30
|
+
puts " #{attr.name}#{col}"
|
|
31
|
+
end
|
|
32
|
+
applicable = constraints_for_role(role)
|
|
33
|
+
return 0 if applicable.empty?
|
|
34
|
+
|
|
35
|
+
puts ''
|
|
36
|
+
puts "Applicable constraints (#{applicable.size}):"
|
|
37
|
+
applicable.each do |(conv, c)|
|
|
38
|
+
puts " [#{conv.qname}] #{c.name.split('::').last}"
|
|
39
|
+
end
|
|
40
|
+
0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def role_of(klass)
|
|
46
|
+
# Find the most specific Role module included in klass
|
|
47
|
+
# (the one with the longest name that matches Cml::Role::*).
|
|
48
|
+
klass.ancestors.find do |a|
|
|
49
|
+
next false unless a.is_a?(Module)
|
|
50
|
+
next false unless a.name
|
|
51
|
+
|
|
52
|
+
a.name.start_with?('Chemicalml::Cml::Role::')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def constraints_for_role(role)
|
|
57
|
+
return [] unless role
|
|
58
|
+
|
|
59
|
+
Chemicalml::Convention::Registry.each_constraint.with_object([]) do |(conv, c), acc|
|
|
60
|
+
roles = c.applies_to_roles
|
|
61
|
+
next if roles.nil?
|
|
62
|
+
|
|
63
|
+
matched = roles.any? do |r|
|
|
64
|
+
role <= r
|
|
65
|
+
rescue StandardError
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
next unless matched
|
|
69
|
+
|
|
70
|
+
acc << [conv, c]
|
|
71
|
+
end
|
|
72
|
+
rescue StandardError
|
|
73
|
+
[]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|