chemicalml 0.2.1 → 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/.rubocop.yml +23 -0
- data/CLAUDE.md +49 -1
- data/README.adoc +154 -26
- 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 +18 -8
- data/lib/chemicalml/cml/base/action.rb +34 -16
- data/lib/chemicalml/cml/base/action_list.rb +35 -17
- data/lib/chemicalml/cml/base/alternative.rb +13 -4
- data/lib/chemicalml/cml/base/amount.rb +14 -6
- data/lib/chemicalml/cml/base/angle.rb +28 -13
- data/lib/chemicalml/cml/base/annotation.rb +14 -6
- data/lib/chemicalml/cml/base/any_cml.rb +12 -5
- data/lib/chemicalml/cml/base/appinfo.rb +14 -6
- data/lib/chemicalml/cml/base/arg.rb +47 -13
- data/lib/chemicalml/cml/base/array.rb +40 -19
- data/lib/chemicalml/cml/base/array_list.rb +14 -6
- data/lib/chemicalml/cml/base/atom.rb +84 -28
- data/lib/chemicalml/cml/base/atom_array.rb +60 -23
- data/lib/chemicalml/cml/base/atom_parity.rb +14 -6
- data/lib/chemicalml/cml/base/atom_set.rb +14 -6
- data/lib/chemicalml/cml/base/atom_type.rb +25 -9
- data/lib/chemicalml/cml/base/atom_type_list.rb +22 -8
- data/lib/chemicalml/cml/base/atomic_basis_function.rb +33 -13
- data/lib/chemicalml/cml/base/band.rb +21 -8
- data/lib/chemicalml/cml/base/band_list.rb +15 -7
- data/lib/chemicalml/cml/base/basis_set.rb +24 -9
- data/lib/chemicalml/cml/base/bond.rb +36 -10
- data/lib/chemicalml/cml/base/bond_array.rb +34 -11
- data/lib/chemicalml/cml/base/bond_set.rb +14 -6
- data/lib/chemicalml/cml/base/bond_stereo.rb +20 -9
- data/lib/chemicalml/cml/base/bond_type.rb +23 -8
- data/lib/chemicalml/cml/base/bond_type_list.rb +22 -8
- data/lib/chemicalml/cml/base/cell_parameter.rb +28 -10
- 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 +12 -5
- data/lib/chemicalml/cml/base/condition_list.rb +26 -10
- data/lib/chemicalml/cml/base/crystal.rb +26 -10
- data/lib/chemicalml/cml/base/definition.rb +12 -5
- data/lib/chemicalml/cml/base/description.rb +14 -6
- data/lib/chemicalml/cml/base/dictionary.rb +27 -10
- data/lib/chemicalml/cml/base/dictionary_entry.rb +67 -8
- data/lib/chemicalml/cml/base/dimension.rb +26 -12
- 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 +32 -8
- data/lib/chemicalml/cml/base/electron.rb +26 -12
- data/lib/chemicalml/cml/base/enumeration.rb +16 -7
- data/lib/chemicalml/cml/base/expression.rb +21 -6
- data/lib/chemicalml/cml/base/float.rb +22 -10
- data/lib/chemicalml/cml/base/float_array.rb +24 -11
- data/lib/chemicalml/cml/base/formula.rb +31 -10
- data/lib/chemicalml/cml/base/fragment.rb +30 -12
- data/lib/chemicalml/cml/base/fragment_list.rb +24 -9
- data/lib/chemicalml/cml/base/gradient.rb +19 -6
- data/lib/chemicalml/cml/base/identifier.rb +18 -8
- data/lib/chemicalml/cml/base/integer.rb +22 -10
- data/lib/chemicalml/cml/base/integer_array.rb +24 -11
- data/lib/chemicalml/cml/base/isotope.rb +28 -9
- data/lib/chemicalml/cml/base/isotope_list.rb +17 -8
- data/lib/chemicalml/cml/base/join.rb +25 -9
- data/lib/chemicalml/cml/base/kpoint.rb +16 -7
- data/lib/chemicalml/cml/base/kpoint_list.rb +15 -7
- data/lib/chemicalml/cml/base/label.rb +14 -6
- data/lib/chemicalml/cml/base/lattice.rb +35 -10
- data/lib/chemicalml/cml/base/lattice_vector.rb +16 -7
- data/lib/chemicalml/cml/base/length.rb +26 -12
- data/lib/chemicalml/cml/base/line3.rb +18 -8
- data/lib/chemicalml/cml/base/link.rb +41 -20
- data/lib/chemicalml/cml/base/list.rb +22 -10
- data/lib/chemicalml/cml/base/map.rb +32 -11
- data/lib/chemicalml/cml/base/matrix.rb +32 -15
- 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 +18 -8
- data/lib/chemicalml/cml/base/metadata_list.rb +27 -8
- data/lib/chemicalml/cml/base/molecule.rb +90 -26
- data/lib/chemicalml/cml/base/molecule_list.rb +26 -8
- data/lib/chemicalml/cml/base/name.rb +10 -4
- data/lib/chemicalml/cml/base/object.rb +18 -8
- data/lib/chemicalml/cml/base/observation.rb +16 -7
- data/lib/chemicalml/cml/base/operator.rb +14 -6
- data/lib/chemicalml/cml/base/parameter.rb +33 -13
- data/lib/chemicalml/cml/base/parameter_list.rb +27 -8
- data/lib/chemicalml/cml/base/particle.rb +20 -9
- data/lib/chemicalml/cml/base/peak.rb +71 -26
- data/lib/chemicalml/cml/base/peak_group.rb +62 -26
- data/lib/chemicalml/cml/base/peak_list.rb +24 -9
- data/lib/chemicalml/cml/base/peak_structure.rb +40 -13
- data/lib/chemicalml/cml/base/plane3.rb +14 -6
- data/lib/chemicalml/cml/base/point3.rb +14 -6
- data/lib/chemicalml/cml/base/potential.rb +17 -6
- data/lib/chemicalml/cml/base/potential_form.rb +30 -7
- data/lib/chemicalml/cml/base/potential_list.rb +15 -7
- data/lib/chemicalml/cml/base/product.rb +45 -10
- data/lib/chemicalml/cml/base/product_list.rb +29 -9
- data/lib/chemicalml/cml/base/property.rb +29 -11
- data/lib/chemicalml/cml/base/property_list.rb +23 -8
- data/lib/chemicalml/cml/base/reactant.rb +45 -10
- data/lib/chemicalml/cml/base/reactant_list.rb +29 -9
- data/lib/chemicalml/cml/base/reaction.rb +74 -20
- data/lib/chemicalml/cml/base/reaction_list.rb +23 -8
- data/lib/chemicalml/cml/base/reaction_scheme.rb +43 -13
- data/lib/chemicalml/cml/base/reaction_step.rb +30 -12
- data/lib/chemicalml/cml/base/reaction_step_list.rb +30 -11
- data/lib/chemicalml/cml/base/reactive_centre.rb +31 -6
- data/lib/chemicalml/cml/base/region.rb +20 -9
- data/lib/chemicalml/cml/base/related_entry.rb +11 -3
- data/lib/chemicalml/cml/base/sample.rb +30 -7
- data/lib/chemicalml/cml/base/scalar.rb +32 -15
- data/lib/chemicalml/cml/base/spectator.rb +25 -6
- data/lib/chemicalml/cml/base/spectator_list.rb +20 -7
- data/lib/chemicalml/cml/base/spectrum.rb +57 -18
- data/lib/chemicalml/cml/base/spectrum_data.rb +19 -9
- data/lib/chemicalml/cml/base/spectrum_list.rb +28 -9
- data/lib/chemicalml/cml/base/sphere3.rb +14 -6
- data/lib/chemicalml/cml/base/stmml.rb +12 -5
- data/lib/chemicalml/cml/base/string.rb +14 -6
- data/lib/chemicalml/cml/base/string_array.rb +22 -10
- data/lib/chemicalml/cml/base/substance.rb +36 -14
- data/lib/chemicalml/cml/base/substance_list.rb +29 -10
- data/lib/chemicalml/cml/base/symmetry.rb +31 -9
- data/lib/chemicalml/cml/base/system.rb +21 -10
- data/lib/chemicalml/cml/base/table.rb +38 -13
- data/lib/chemicalml/cml/base/table_cell.rb +12 -5
- data/lib/chemicalml/cml/base/table_content.rb +19 -9
- data/lib/chemicalml/cml/base/table_header.rb +15 -7
- data/lib/chemicalml/cml/base/table_header_cell.rb +22 -10
- 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 +16 -7
- data/lib/chemicalml/cml/base/torsion.rb +28 -13
- 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 +22 -6
- data/lib/chemicalml/cml/base/unit.rb +39 -16
- data/lib/chemicalml/cml/base/unit_list.rb +34 -12
- data/lib/chemicalml/cml/base/unit_type.rb +27 -10
- data/lib/chemicalml/cml/base/unit_type_list.rb +29 -11
- data/lib/chemicalml/cml/base/vector3.rb +14 -6
- data/lib/chemicalml/cml/base/xaxis.rb +30 -10
- data/lib/chemicalml/cml/base/yaxis.rb +30 -10
- data/lib/chemicalml/cml/base/z_matrix.rb +26 -5
- data/lib/chemicalml/cml/base.rb +139 -138
- data/lib/chemicalml/cml/canonical_comparison.rb +54 -0
- data/lib/chemicalml/cml/elements.rb +145 -136
- 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.rb +138 -138
- data/lib/chemicalml/cml/schema24/configuration.rb +11 -1
- data/lib/chemicalml/cml/schema24.rb +139 -139
- 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 +163 -129
- data/lib/chemicalml/context_configuration.rb +4 -2
- 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 +1 -1
- data/lib/chemicalml/convention/compchem/constraints/calculation_requires_finalization.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +2 -1
- data/lib/chemicalml/convention/compchem/constraints/environment_at_most_one_property_list.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list.rb +1 -1
- 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 +1 -1
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list.rb +1 -1
- 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 +1 -1
- data/lib/chemicalml/convention/compchem/constraints/job_list_module_must_have_id.rb +1 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_environment.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/job_module_must_have_id.rb +1 -0
- data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +1 -0
- data/lib/chemicalml/convention/compchem/constraints/matrix_rules.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints/scalar_units.rb +1 -1
- data/lib/chemicalml/convention/compchem/constraints.rb +4 -0
- data/lib/chemicalml/convention/compchem.rb +4 -2
- data/lib/chemicalml/convention/constraint.rb +40 -9
- data/lib/chemicalml/convention/coordinator.rb +4 -3
- data/lib/chemicalml/convention/detection.rb +10 -4
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace.rb +1 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash.rb +1 -1
- data/lib/chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern.rb +1 -1
- data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +1 -1
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_contain_definition.rb +1 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +1 -1
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_unit_type.rb +1 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_units_co_constraints.rb +1 -1
- data/lib/chemicalml/convention/dictionary/constraints.rb +8 -8
- data/lib/chemicalml/convention/dictionary.rb +2 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula.rb +1 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +15 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired.rb +1 -1
- 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 +3 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +1 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_element_type.rb +1 -1
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_id.rb +2 -1
- 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 +1 -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 +1 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2.rb +1 -1
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_order.rb +2 -1
- data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +1 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref.rb +1 -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 +1 -1
- 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 +1 -1
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref.rb +1 -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 +1 -1
- 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 +1 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children.rb +1 -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 +1 -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 +1 -1
- data/lib/chemicalml/convention/molecular/constraints/property_must_have_dict_ref.rb +1 -1
- 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 +1 -1
- data/lib/chemicalml/convention/molecular/constraints.rb +49 -23
- data/lib/chemicalml/convention/molecular.rb +15 -2
- data/lib/chemicalml/convention/registry.rb +79 -11
- 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 +1 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_have_namespace.rb +1 -1
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_contain_definition.rb +1 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_id.rb +1 -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 +1 -1
- 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 +10 -0
- data/lib/chemicalml/convention/unit_dictionary.rb +7 -2
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_id_must_match_pattern.rb +1 -1
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_contain_at_least_one_unit_type.rb +1 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_have_namespace.rb +1 -1
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_contain_definition.rb +1 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +1 -1
- data/lib/chemicalml/convention/unit_type_dictionary.rb +2 -2
- data/lib/chemicalml/convention/validation_report.rb +30 -3
- data/lib/chemicalml/convention/violation.rb +9 -3
- data/lib/chemicalml/convention.rb +41 -14
- 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 +10 -10
- data/lib/chemicalml.rb +78 -15
- data/lib/tasks/reference_fetch.rake +30 -31
- data/lib/tasks/scrape_fixtures.rake +23 -24
- metadata +114 -3
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Round 27 — User-facing API, CLI improvements
|
|
2
|
+
|
|
3
|
+
This round adds the user-facing query API on `Cml::Visitable`, a
|
|
4
|
+
top-level `Chemicalml.validate` shortcut, and two new CLI commands
|
|
5
|
+
(`inspect`, `elements`).
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- [110 — Document query API](110-document-query-api.md)
|
|
10
|
+
- [111 — Top-level Chemicalml.validate](111-toplevel-validate.md)
|
|
11
|
+
- [112 — CLI inspect command](112-cli-inspect.md)
|
|
12
|
+
- [113 — CLI elements command](113-cli-elements.md)
|
|
13
|
+
- [114 — Final verification round 27](114-final-verification-round27.md)
|
|
14
|
+
|
|
15
|
+
## Outcomes
|
|
16
|
+
|
|
17
|
+
- **`Cml::Visitable` query methods** (inherited by every wire class):
|
|
18
|
+
- `#each_wire_node`, `#each_atom`, `#each_bond`, `#each_molecule` — recursive iterators
|
|
19
|
+
- `#find_atom(id)`, `#find_bond(id)`, `#find_molecule(id)` — id-based lookup
|
|
20
|
+
- `#atom_count`, `#bond_count`, `#molecule_count` — recursive counts
|
|
21
|
+
- All return Enumerators without a block (Enumerable-style)
|
|
22
|
+
|
|
23
|
+
- **`Chemicalml.validate(doc)`** — top-level shortcut for
|
|
24
|
+
`Convention.detect_and_validate(doc)`. Users no longer need to
|
|
25
|
+
remember the full namespace.
|
|
26
|
+
|
|
27
|
+
- **`chemicalml inspect <file>`** — new CLI command. Prints a
|
|
28
|
+
tree-style summary of the document with element names, ids, and
|
|
29
|
+
structure. Useful for debugging.
|
|
30
|
+
|
|
31
|
+
- **`chemicalml elements`** — new CLI command. Lists every Schema3
|
|
32
|
+
wire class with its XML root name. Useful for introspection.
|
|
33
|
+
|
|
34
|
+
- **CLI refactor**: `run_validate` now uses `report.summary` instead
|
|
35
|
+
of manual rendering. Cleaner code, better output.
|
|
36
|
+
|
|
37
|
+
- **559 examples, 0 failures, 3 pending** (TOML adapter pending).
|
|
38
|
+
Zero forbidden patterns.
|
|
39
|
+
|
|
40
|
+
## Architectural insight
|
|
41
|
+
|
|
42
|
+
The query methods live on `Visitable` (the marker mixin every wire
|
|
43
|
+
class includes) rather than on `Document` specifically. This means
|
|
44
|
+
ANY wire class can be the root of a query — `molecule.find_atom(id)`,
|
|
45
|
+
`reaction.find_molecule(id)`, etc. This was the right call: the
|
|
46
|
+
walker is already general (visits any subtree); exposing query
|
|
47
|
+
methods only on Document would have required callers to navigate
|
|
48
|
+
up to Document first.
|
|
49
|
+
|
|
50
|
+
The CLI's `print_tree` helper is recursive but bounded (`max_depth: 6`)
|
|
51
|
+
to avoid runaway output on pathological documents.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Round 28 — Convenience API, custom conventions, compchem completion
|
|
2
|
+
|
|
3
|
+
This round adds user-facing convenience (`parse_file`, custom
|
|
4
|
+
convention registration), more compchem constraints from the spec,
|
|
5
|
+
and a comprehensive lint cleanup.
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- [115 — parse_file convenience](115-parse-file.md)
|
|
10
|
+
- [116 — Custom convention registration](116-custom-convention.md)
|
|
11
|
+
- [117 — More compchem constraints](117-more-compchem-constraints.md)
|
|
12
|
+
- [118 — Final verification round 28](118-final-verification-round28.md)
|
|
13
|
+
|
|
14
|
+
## Outcomes
|
|
15
|
+
|
|
16
|
+
- **`Chemicalml.parse_file(path)`** — convenience wrapper around
|
|
17
|
+
`parse(File.read(path))`. Raises ArgumentError for missing files.
|
|
18
|
+
Eliminates the `File.read` boilerplate.
|
|
19
|
+
|
|
20
|
+
- **`Convention::Registry.register_custom(mod)`** — runtime
|
|
21
|
+
registration of custom conventions. The module must `extend Base`
|
|
22
|
+
and return a non-empty `qname`. Useful for domain-specific CML
|
|
23
|
+
extensions (e.g., a `convention:my-lab-extensions` for a research
|
|
24
|
+
group's custom vocabulary).
|
|
25
|
+
|
|
26
|
+
- **Two new compchem constraints** from the spec:
|
|
27
|
+
- `InitializationMustHaveContent` — initialization module must
|
|
28
|
+
contain at least one of molecule, parameterList, or user-defined
|
|
29
|
+
module
|
|
30
|
+
- `FinalizationMustHaveContent` — finalization module must contain
|
|
31
|
+
at least one of molecule, propertyList, or user-defined module
|
|
32
|
+
|
|
33
|
+
- **Lint cleanup**: ran `rubocop -A` on all recently-touched files.
|
|
34
|
+
80 offenses autocorrected (string quotes, modifier-if usage,
|
|
35
|
+
parenthesised method args, etc.). Zero remaining style issues.
|
|
36
|
+
|
|
37
|
+
- **Real bug caught during round 28**: `register_custom` initially
|
|
38
|
+
deadlocked because it called `load_cache` while holding the mutex.
|
|
39
|
+
Fixed by separating the load step (which acquires/releases its
|
|
40
|
+
own mutex) from the mutation step (direct hash access after load
|
|
41
|
+
is guaranteed to have populated `@cache`).
|
|
42
|
+
|
|
43
|
+
- Compchem convention: 20 constraints (up from 18).
|
|
44
|
+
|
|
45
|
+
- **568 examples, 0 failures, 3 pending** (TOML adapter pending).
|
|
46
|
+
Zero forbidden patterns. **88 constraints across 8 conventions.**
|
|
47
|
+
|
|
48
|
+
## Architectural insight
|
|
49
|
+
|
|
50
|
+
The `register_custom` deadlock is a classic Ruby mutex pitfall:
|
|
51
|
+
re-entering a non-reentrant `Mutex#synchronize` block from within
|
|
52
|
+
itself deadlocks. The fix — call `load_cache` first (which manages
|
|
53
|
+
its own mutex acquisition), then mutate `@cache` directly — works
|
|
54
|
+
because Ruby's `||=` assignment makes `@cache` non-nil after the
|
|
55
|
+
first load. Documented in the method comment.
|
|
56
|
+
|
|
57
|
+
This round also reinforced the value of running rubocop on each
|
|
58
|
+
round's output. 80 autocorrected offenses across 8 files means
|
|
59
|
+
style drift was creeping in — single-quote vs double-quote,
|
|
60
|
+
`unless` vs `if !`, etc. A small CI rule (`bundle exec rubocop`
|
|
61
|
+
must pass) would catch this in future.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Round 29 — Wire introspection, README, dataType consistency
|
|
2
|
+
|
|
3
|
+
This round adds wire-class introspection, updates the README to
|
|
4
|
+
reflect the current API, and adds a property-dataType consistency
|
|
5
|
+
constraint that bridges the convention and dictionary subsystems
|
|
6
|
+
in a new way.
|
|
7
|
+
|
|
8
|
+
## Files
|
|
9
|
+
|
|
10
|
+
- [119 — Wire-class introspection](119-wire-introspection.md)
|
|
11
|
+
- [120 — Update README](120-readme-update.md)
|
|
12
|
+
- [121 — Property dataType consistency](121-property-datatype.md)
|
|
13
|
+
- [122 — Final verification round 29](122-final-verification-round29.md)
|
|
14
|
+
|
|
15
|
+
## Outcomes
|
|
16
|
+
|
|
17
|
+
- **`Cml.for_xml_name(name, schema:)`** — wire-class lookup by XML
|
|
18
|
+
element name. Uses the existing `Elements::XML_TO_CLASS` reverse
|
|
19
|
+
index. Returns nil for unknown names.
|
|
20
|
+
|
|
21
|
+
- **`Cml.wire_classes(schema:)`** — enumerator over all wire classes
|
|
22
|
+
for a schema version. Useful for code generation and tooling.
|
|
23
|
+
|
|
24
|
+
- **README rewritten**:
|
|
25
|
+
- 8 conventions + 88+ constraints documented
|
|
26
|
+
- All modern API examples (`parse_file`, `validate`, `each_atom`)
|
|
27
|
+
- CLI commands documented (`validate`, `inspect`, `conventions`,
|
|
28
|
+
`dictionaries`, `elements`)
|
|
29
|
+
- Cross-format serialisation examples
|
|
30
|
+
- Custom convention registration example
|
|
31
|
+
- Dictionary lookup example
|
|
32
|
+
- Architectural overview (`Base::*`, `Role::*`, `Elements::ALL`)
|
|
33
|
+
|
|
34
|
+
- **`PropertyScalarDataTypeMatchesDictionary`** — molecular warning
|
|
35
|
+
when a `<property>`'s `<scalar>` `dataType` doesn't match the
|
|
36
|
+
`dataType` declared in the dictionary entry referenced by `dictRef`.
|
|
37
|
+
This is a **three-component integration check**: convention
|
|
38
|
+
constraint system queries the dictionary registry AND inspects the
|
|
39
|
+
document's scalar child.
|
|
40
|
+
|
|
41
|
+
- Molecular convention: 36 constraints (up from 35).
|
|
42
|
+
|
|
43
|
+
- **574 examples, 0 failures, 3 pending**. Zero forbidden patterns.
|
|
44
|
+
|
|
45
|
+
## Architectural insight
|
|
46
|
+
|
|
47
|
+
`PropertyScalarDataTypeMatchesDictionary` is the deepest
|
|
48
|
+
cross-component check yet — it validates that:
|
|
49
|
+
|
|
50
|
+
1. The property's `dictRef` resolves to a real dictionary entry
|
|
51
|
+
(uses `Dictionary::Registry.lookup`).
|
|
52
|
+
2. The entry declares a `dataType`.
|
|
53
|
+
3. The property's `<scalar>` child declares a `dataType`.
|
|
54
|
+
4. The two `dataType` values match.
|
|
55
|
+
|
|
56
|
+
If any step is missing data, the constraint silently passes (no
|
|
57
|
+
false positives). When all the data is present, it catches real
|
|
58
|
+
inconsistencies that would cause downstream type errors.
|
|
59
|
+
|
|
60
|
+
This kind of multi-step semantic validation is what mature
|
|
61
|
+
document-validation frameworks look like. Round 29 is the first
|
|
62
|
+
round where it's been possible — earlier rounds built the
|
|
63
|
+
primitives (dictionary registry, dictRef resolution, scalar
|
|
64
|
+
dataType attribute) that this constraint composes.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Round 30 — unitType resolution, JSON CLI, enumeration
|
|
2
|
+
|
|
3
|
+
This round adds the unit-unitType cross-component check (parallels
|
|
4
|
+
dictRef resolution), CLI JSON output for machine consumers, and a
|
|
5
|
+
constraint-enumeration API.
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- [123 — Unit unitType resolution](123-unit-unittype-resolution.md)
|
|
10
|
+
- [124 — CLI JSON output](124-cli-json-output.md)
|
|
11
|
+
- [125 — Constraint enumeration API](125-constraint-enumeration.md)
|
|
12
|
+
- [126 — Final verification round 30](126-final-verification-round30.md)
|
|
13
|
+
|
|
14
|
+
## Outcomes
|
|
15
|
+
|
|
16
|
+
- **`UnitUnitTypeShouldResolve`** — unit-dictionary warning when a
|
|
17
|
+
`<unit>`'s `unitType` attribute doesn't resolve against the
|
|
18
|
+
built-in unitType-dictionary. Cross-component check parallel to
|
|
19
|
+
the molecular convention's `DictRefShouldResolve`.
|
|
20
|
+
|
|
21
|
+
- **`chemicalml validate --json file.cml`** — JSON output mode for
|
|
22
|
+
the CLI. Returns `{ file:, ok:, has_warnings:, violations: [...] }`
|
|
23
|
+
where each violation has `severity`, `path`, `message`, `value`.
|
|
24
|
+
Useful for editor integration, CI pipelines, automated tooling.
|
|
25
|
+
|
|
26
|
+
- **`Convention::Registry.each_constraint`** — iterates every
|
|
27
|
+
constraint across every convention, yielding `(convention, class)`
|
|
28
|
+
pairs. Useful for documentation generation and introspection.
|
|
29
|
+
|
|
30
|
+
- **`Convention::Registry.total_constraint_count`** — sum of all
|
|
31
|
+
registered constraints across all conventions (currently 90).
|
|
32
|
+
|
|
33
|
+
- Unit-dictionary convention: 9 constraints (up from 8).
|
|
34
|
+
|
|
35
|
+
- **580 examples, 0 failures, 3 pending** (TOML adapter pending).
|
|
36
|
+
Zero forbidden patterns. **90 constraints across 8 conventions.**
|
|
37
|
+
|
|
38
|
+
## Architectural insight
|
|
39
|
+
|
|
40
|
+
`UnitUnitTypeShouldResolve` completes a symmetric pair with
|
|
41
|
+
`DictRefShouldResolve` from round 25. Both follow the same pattern:
|
|
42
|
+
walk the document, look up reference attributes against the
|
|
43
|
+
dictionary registry, warn on misses. The pattern is now established
|
|
44
|
+
enough that adding a new reference-resolution constraint is a
|
|
45
|
+
2-minute job: copy the structure, change the attribute name and the
|
|
46
|
+
target dictionary.
|
|
47
|
+
|
|
48
|
+
The `each_constraint` iterator makes the constraint table tractable
|
|
49
|
+
for documentation generation. A future round could auto-generate a
|
|
50
|
+
Markdown table of all 90 constraints from this single API call.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Round 31 — CLI tooling, parentSI resolution
|
|
2
|
+
|
|
3
|
+
This round completes the CLI tooling suite (constraints + enums
|
|
4
|
+
commands) and adds the parentSI resolution constraint, completing
|
|
5
|
+
the cross-component check symmetry.
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- [127 — CLI constraints command](127-cli-constraints.md)
|
|
10
|
+
- [128 — CLI enums command](128-cli-enums.md)
|
|
11
|
+
- [129 — ParentSI resolution](129-parentsi-resolution.md)
|
|
12
|
+
- [130 — Final verification round 31](130-final-verification-round31.md)
|
|
13
|
+
|
|
14
|
+
## Outcomes
|
|
15
|
+
|
|
16
|
+
- **`chemicalml constraints`** — new CLI command listing all 91
|
|
17
|
+
constraints grouped by convention. Each line shows the constraint
|
|
18
|
+
class name and its declared `applies_to` roles.
|
|
19
|
+
|
|
20
|
+
- **`chemicalml enums`** — new CLI command listing every
|
|
21
|
+
`Cml::Enums` constant with its allowed values. Useful for users
|
|
22
|
+
who want to know what enum values an attribute accepts.
|
|
23
|
+
|
|
24
|
+
- **`UnitParentSiShouldResolve`** — unit-dictionary warning when a
|
|
25
|
+
`<unit>`'s `parentSI` doesn't resolve against built-in
|
|
26
|
+
dictionaries. Completes the cross-component check symmetry:
|
|
27
|
+
- dictRef resolution (molecular)
|
|
28
|
+
- unitType resolution (unit-dictionary)
|
|
29
|
+
- parentSI resolution (unit-dictionary)
|
|
30
|
+
|
|
31
|
+
- **Real bug caught during round 31**: existing fixture
|
|
32
|
+
`convention_spec.rb:226` used `parent_si: "siUnits:s"` which
|
|
33
|
+
doesn't resolve (correct prefix is `si`, not `siUnits`). Fixed.
|
|
34
|
+
|
|
35
|
+
- Unit-dictionary convention: 10 constraints (up from 9).
|
|
36
|
+
|
|
37
|
+
- **583 examples, 0 failures, 3 pending**. Zero forbidden patterns.
|
|
38
|
+
**91 constraints across 8 conventions.**
|
|
39
|
+
|
|
40
|
+
## Architectural insight
|
|
41
|
+
|
|
42
|
+
The cross-component check pattern (walk document → look up reference
|
|
43
|
+
attribute against registry → warn on miss) is now fully
|
|
44
|
+
established across three constraint pairs:
|
|
45
|
+
|
|
46
|
+
| Convention | Attribute | Lookup target |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| molecular | `dictRef` | dictionary registry |
|
|
49
|
+
| unit-dictionary | `unitType` | unitType-dictionary registry |
|
|
50
|
+
| unit-dictionary | `parentSI` | unit dictionary registry |
|
|
51
|
+
|
|
52
|
+
Adding a fourth is mechanical: copy the structure, change the
|
|
53
|
+
attribute name and lookup target. The pattern's clarity is its own
|
|
54
|
+
form of documentation.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Round 32 — Thor CLI refactor, info command, auto-docs
|
|
2
|
+
|
|
3
|
+
This round refactors the CLI to use Thor with one class per command,
|
|
4
|
+
adds the `info` command for element introspection, and auto-generates
|
|
5
|
+
constraint documentation.
|
|
6
|
+
|
|
7
|
+
## Files
|
|
8
|
+
|
|
9
|
+
- [131 — CLI info command](131-cli-info-command.md)
|
|
10
|
+
- [132 — Auto-generated constraint docs](132-auto-generated-constraint-docs.md)
|
|
11
|
+
- [133 — Final verification round 32](133-final-verification-round32.md)
|
|
12
|
+
|
|
13
|
+
## Outcomes
|
|
14
|
+
|
|
15
|
+
- **CLI refactored to Thor**. Each command is now a dedicated class:
|
|
16
|
+
- `Chemicalml::Cli::Base < Thor` — dispatcher
|
|
17
|
+
- `Chemicalml::Cli::Command` — base class with `.run(args, options)`
|
|
18
|
+
and `#run(args, options)`
|
|
19
|
+
- `Chemicalml::Cli::ValidateCommand`
|
|
20
|
+
- `Chemicalml::Cli::InspectCommand`
|
|
21
|
+
- `Chemicalml::Cli::ConventionsCommand`
|
|
22
|
+
- `Chemicalml::Cli::DictionariesCommand`
|
|
23
|
+
- `Chemicalml::Cli::ElementsCommand`
|
|
24
|
+
- `Chemicalml::Cli::ConstraintsCommand`
|
|
25
|
+
- `Chemicalml::Cli::EnumsCommand`
|
|
26
|
+
- `Chemicalml::Cli::InfoCommand`
|
|
27
|
+
|
|
28
|
+
Each command supports both `MyCommand.run(args, options)` (class
|
|
29
|
+
method) and `MyCommand.new.run(args, options)` (instance method)
|
|
30
|
+
invocation patterns — matching the user's requested pattern.
|
|
31
|
+
|
|
32
|
+
- **`chemicalml info <element>`** — new CLI command. Shows element
|
|
33
|
+
XML name, Ruby class, included Role module, all attributes (with
|
|
34
|
+
collection marker), and all applicable constraints across every
|
|
35
|
+
convention. Useful for users exploring the model.
|
|
36
|
+
|
|
37
|
+
- **Auto-generated constraint docs** — `docs/generate_constraint_docs.rb`
|
|
38
|
+
script produces `docs/constraints.md` from
|
|
39
|
+
`Convention::Registry.each_constraint`. Single source of truth —
|
|
40
|
+
regenerating picks up new constraints automatically. No manual
|
|
41
|
+
maintenance.
|
|
42
|
+
|
|
43
|
+
- **Bug fix from autocorrect**: `Convention::Registry#load_cache`
|
|
44
|
+
had `@cache` renamed to `@load_cache` by rubocop's
|
|
45
|
+
`MemoizedInstanceVariableName` rule. `register_custom` and `reset!`
|
|
46
|
+
needed alignment — fixed in this round.
|
|
47
|
+
|
|
48
|
+
- **586 examples, 0 failures, 3 pending**. Zero forbidden patterns.
|
|
49
|
+
|
|
50
|
+
## Architectural insight
|
|
51
|
+
|
|
52
|
+
The Thor refactor separates concerns cleanly:
|
|
53
|
+
|
|
54
|
+
1. **Thor dispatcher** owns argument parsing, help text, option
|
|
55
|
+
declarations. Each `desc + def` block is 2-3 lines.
|
|
56
|
+
2. **Command class** owns the actual work. Easy to test in isolation
|
|
57
|
+
(`MyCommand.new.run(args, options)` returns an exit code).
|
|
58
|
+
3. **No business logic in the dispatcher** — it's pure routing.
|
|
59
|
+
|
|
60
|
+
This pattern scales: a future `rake` task, Rake task, or web handler
|
|
61
|
+
can re-use any `*Command` class without going through Thor. The
|
|
62
|
+
Thor dispatcher is just one possible entry point.
|
|
63
|
+
|
|
64
|
+
The auto-generated constraint docs demonstrate the value of the
|
|
65
|
+
`each_constraint` API from round 30: a single iteration produces
|
|
66
|
+
comprehensive documentation with zero manual upkeep. Adding a new
|
|
67
|
+
constraint and re-running the generator is all it takes.
|
|
@@ -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. |
|