chemicalml 0.2.1 → 0.4.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 +21 -14
- data/.rubocop.yml +23 -0
- data/CHANGELOG.md +32 -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/chemicalml.gemspec +1 -1
- 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 +42 -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 +14 -5
- data/lib/chemicalml/cml/base/description.rb +16 -6
- data/lib/chemicalml/cml/base/dictionary.rb +28 -11
- data/lib/chemicalml/cml/base/dictionary_entry.rb +69 -10
- data/lib/chemicalml/cml/base/dimension.rb +26 -12
- data/lib/chemicalml/cml/base/document.rb +24 -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 +92 -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 +73 -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 +30 -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 +32 -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/xhtml/p.rb +21 -0
- data/lib/chemicalml/cml/xhtml.rb +20 -0
- data/lib/chemicalml/cml.rb +164 -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 +15 -1
- 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 +118 -5
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
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml inspect <file>` — print a tree-style summary of
|
|
6
|
+
# the document: element names, ids, nested children.
|
|
7
|
+
class InspectCommand < Command
|
|
8
|
+
def run(options)
|
|
9
|
+
path = options[:file]
|
|
10
|
+
unless path
|
|
11
|
+
logger.error 'inspect requires a <file> argument'
|
|
12
|
+
return 2
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
doc = Chemicalml.parse(File.read(path), schema: :schema3)
|
|
16
|
+
print_tree(doc, 0)
|
|
17
|
+
0
|
|
18
|
+
rescue ArgumentError, Lutaml::Model::InvalidFormatError => e
|
|
19
|
+
logger.error "FAIL: #{e.message}"
|
|
20
|
+
2
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def print_tree(node, depth, max_depth: 6)
|
|
26
|
+
return if depth > max_depth
|
|
27
|
+
return unless node.is_a?(Lutaml::Model::Serializable)
|
|
28
|
+
|
|
29
|
+
indent = ' ' * depth
|
|
30
|
+
line = "#{indent}#{node.class.name.split('::').last}"
|
|
31
|
+
line += " [#{node.node_id}]" if node.is_a?(Chemicalml::Cml::Visitable) && node.node_id
|
|
32
|
+
puts line
|
|
33
|
+
return unless node.is_a?(Chemicalml::Cml::Visitable)
|
|
34
|
+
|
|
35
|
+
node.wire_children.each { |c| print_tree(c, depth + 1, max_depth: max_depth) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Cli
|
|
5
|
+
# `chemicalml validate <file>` — auto-detect convention and
|
|
6
|
+
# print violations. With `--json` / `-j`, emits machine-readable
|
|
7
|
+
# JSON.
|
|
8
|
+
class ValidateCommand < Command
|
|
9
|
+
def run(options)
|
|
10
|
+
path = options[:file]
|
|
11
|
+
unless path
|
|
12
|
+
logger.error 'validate requires a <file> argument'
|
|
13
|
+
return 2
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
logger.info "Validating #{path}" unless options[:json]
|
|
17
|
+
doc = Chemicalml.parse(File.read(path), schema: :schema3)
|
|
18
|
+
report = Chemicalml.validate(doc)
|
|
19
|
+
|
|
20
|
+
if options[:json]
|
|
21
|
+
puts json_report(report, path)
|
|
22
|
+
elsif report.ok? && !report.has_warnings?
|
|
23
|
+
logger.info "OK: #{path}"
|
|
24
|
+
else
|
|
25
|
+
logger.error report.summary
|
|
26
|
+
end
|
|
27
|
+
report.ok? ? 0 : 1
|
|
28
|
+
rescue ArgumentError, Lutaml::Model::InvalidFormatError => e
|
|
29
|
+
logger.error "FAIL: #{e.message}"
|
|
30
|
+
2
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def json_report(report, path)
|
|
36
|
+
require 'json'
|
|
37
|
+
payload = {
|
|
38
|
+
file: path,
|
|
39
|
+
ok: report.ok?,
|
|
40
|
+
has_warnings: report.has_warnings?,
|
|
41
|
+
violations: report.violations.map do |v|
|
|
42
|
+
{
|
|
43
|
+
severity: v.severity,
|
|
44
|
+
path: v.path,
|
|
45
|
+
message: v.message,
|
|
46
|
+
value: v.value
|
|
47
|
+
}.compact
|
|
48
|
+
end
|
|
49
|
+
}
|
|
50
|
+
JSON.pretty_generate(payload)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
# Command-line interface. Built on Thor for dispatch; each command is
|
|
5
|
+
# a dedicated class under `Chemicalml::Cli::*Command` exposing
|
|
6
|
+
# `.run(args, options)` (and `#run` on an instance).
|
|
7
|
+
#
|
|
8
|
+
# Dispatch flow:
|
|
9
|
+
#
|
|
10
|
+
# exe/chemicalml ARGV
|
|
11
|
+
# -> Chemicalml::Cli::Base.start(ARGV) (Thor)
|
|
12
|
+
# -> Chemicalml::Cli::<Name>Command.new.run(args, options)
|
|
13
|
+
#
|
|
14
|
+
# Adding a new command:
|
|
15
|
+
# 1. Create `lib/chemicalml/cli/<name>_command.rb` with a class
|
|
16
|
+
# extending `Chemicalml::Cli::Command` and implementing `#run`.
|
|
17
|
+
# 2. Add one `desc + def` block in `Chemicalml::Cli::Base` that
|
|
18
|
+
# invokes `<Name>Command.new.run(args, options)`.
|
|
19
|
+
# 3. Add the autoload entry below.
|
|
20
|
+
module Cli
|
|
21
|
+
autoload :Base, 'chemicalml/cli/base'
|
|
22
|
+
autoload :Command, 'chemicalml/cli/command'
|
|
23
|
+
autoload :ValidateCommand, 'chemicalml/cli/validate_command'
|
|
24
|
+
autoload :InspectCommand, 'chemicalml/cli/inspect_command'
|
|
25
|
+
autoload :ConventionsCommand, 'chemicalml/cli/conventions_command'
|
|
26
|
+
autoload :DictionariesCommand, 'chemicalml/cli/dictionaries_command'
|
|
27
|
+
autoload :ElementsCommand, 'chemicalml/cli/elements_command'
|
|
28
|
+
autoload :ConstraintsCommand, 'chemicalml/cli/constraints_command'
|
|
29
|
+
autoload :EnumsCommand, 'chemicalml/cli/enums_command'
|
|
30
|
+
autoload :InfoCommand, 'chemicalml/cli/info_command'
|
|
31
|
+
|
|
32
|
+
# Backward-compatible entry point used by `exe/chemicalml` and tests.
|
|
33
|
+
# @param argv [Array<String>] the command line.
|
|
34
|
+
# @return [Integer] process exit code.
|
|
35
|
+
def self.run(argv)
|
|
36
|
+
Base.start(argv)
|
|
37
|
+
0
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
warn "FAIL: #{e.message}"
|
|
40
|
+
2
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|