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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<bondStereo>`'s `value` attribute SHOULD be one of the
|
|
8
|
+
# XSD stereoType enum values: C/T/W/H/undefined/other.
|
|
9
|
+
# Warning severity.
|
|
10
|
+
class BondStereoShouldBeInEnum < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<bondStereo>`'s `value` attribute SHOULD be one of the XSD stereoType enum values: C/T/W/H/undefined/other. Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Enums
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::BondStereo
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
value = node.content.to_s
|
|
18
|
+
return [] if value.empty?
|
|
19
|
+
return [] if STEREO_VALUES.include?(value)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "bondStereo #{node.id.inspect} value #{value.inspect} should be one of " \
|
|
23
|
+
"#{STEREO_VALUES.to_a.sort.inspect}",
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: value)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "bondStereo[#{id}]" : 'bondStereo'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb
CHANGED
|
@@ -7,11 +7,11 @@ module Chemicalml
|
|
|
7
7
|
# Molecular convention: `<bondStereo>` value W (wedge) or H
|
|
8
8
|
# (hatch) MUST have `atomRefs2` and MUST NOT have `atomRefs4`.
|
|
9
9
|
class BondStereoWedgeHashMustHaveAtomRefs2 < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Molecular convention: `<bondStereo>` value W (wedge) or H (hatch) MUST have `atomRefs2` and MUST NOT have `atomRefs4`.'
|
|
10
11
|
applies_to Chemicalml::Cml::Role::BondStereo
|
|
11
12
|
WEDGE_HASH_VALUES = %w[W H].freeze
|
|
12
13
|
|
|
13
14
|
def check_node(node, path)
|
|
14
|
-
|
|
15
15
|
value = node.content.to_s.upcase
|
|
16
16
|
return [] unless WEDGE_HASH_VALUES.include?(value)
|
|
17
17
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Walks the document and warns on any element whose `dictRef`
|
|
8
|
+
# attribute cannot be resolved against the built-in
|
|
9
|
+
# dictionaries. Catches typos like `dictRef="cml:bpingpoint"`.
|
|
10
|
+
#
|
|
11
|
+
# DocumentConstraint — needs the whole tree, but the resolver
|
|
12
|
+
# works per-node so it's just a wrapper around the per-node
|
|
13
|
+
# check.
|
|
14
|
+
class DictRefShouldResolve < Chemicalml::Convention::Constraint::NodeConstraint
|
|
15
|
+
self.description = '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"`.'
|
|
16
|
+
applies_to Chemicalml::Cml::Role::Atom,
|
|
17
|
+
Chemicalml::Cml::Role::Bond,
|
|
18
|
+
Chemicalml::Cml::Role::Molecule,
|
|
19
|
+
Chemicalml::Cml::Role::Property,
|
|
20
|
+
Chemicalml::Cml::Role::Scalar,
|
|
21
|
+
Chemicalml::Cml::Role::Array,
|
|
22
|
+
Chemicalml::Cml::Role::Matrix,
|
|
23
|
+
Chemicalml::Cml::Role::Name,
|
|
24
|
+
Chemicalml::Cml::Role::Label
|
|
25
|
+
|
|
26
|
+
def check_node(node, path)
|
|
27
|
+
dict_ref = node.dict_ref.to_s.strip
|
|
28
|
+
return [] if dict_ref.empty?
|
|
29
|
+
return [] if resolves?(dict_ref)
|
|
30
|
+
|
|
31
|
+
[violation(path: path_fingerprint(node, path),
|
|
32
|
+
message: "#{node.element_name} #{node_id_or_blank(node).inspect} " \
|
|
33
|
+
"dictRef #{dict_ref.inspect} does not resolve against any built-in dictionary",
|
|
34
|
+
severity: :warning,
|
|
35
|
+
value: dict_ref)]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def resolves?(dict_ref)
|
|
41
|
+
!Chemicalml::Dictionary::Registry.lookup(dict_ref).nil?
|
|
42
|
+
rescue StandardError
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def path_fingerprint(node, path)
|
|
47
|
+
base = path.empty? ? node.element_name : path.join('/')
|
|
48
|
+
id = node.node_id
|
|
49
|
+
id ? "#{base}[#{id}]" : base
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def node_id_or_blank(node)
|
|
53
|
+
node.node_id || ''
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -8,6 +8,7 @@ module Chemicalml
|
|
|
8
8
|
# OR child `<molecule>` elements, but not both. The two are
|
|
9
9
|
# mutually exclusive ways of describing composition.
|
|
10
10
|
class MoleculeAtomArrayMutuallyExclusiveWithChildren < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = 'Molecular convention: a `<molecule>` MAY hold an `atomArray` OR child `<molecule>` elements, but not both. The two are mutually exclusive ways of describing composition.'
|
|
11
12
|
applies_to Chemicalml::Cml::Role::Molecule
|
|
12
13
|
def check_node(node, path)
|
|
13
14
|
return [] if node.atom_array.nil?
|
|
@@ -7,6 +7,7 @@ module Chemicalml
|
|
|
7
7
|
# Molecular convention: a `<molecule>` MAY hold a `bondArray`
|
|
8
8
|
# OR child `<molecule>` elements, but not both.
|
|
9
9
|
class MoleculeBondArrayMutuallyExclusiveWithChildren < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Molecular convention: a `<molecule>` MAY hold a `bondArray` OR child `<molecule>` elements, but not both.'
|
|
10
11
|
applies_to Chemicalml::Cml::Role::Molecule
|
|
11
12
|
def check_node(node, path)
|
|
12
13
|
return [] if node.bond_array.nil?
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<molecule>`'s `chirality` attribute SHOULD be one of the
|
|
8
|
+
# XSD chiralityType enum values:
|
|
9
|
+
# enantiomer/racemate/unknown/other. Warning severity.
|
|
10
|
+
class MoleculeChiralityShouldBeInEnum < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<molecule>`'s `chirality` attribute SHOULD be one of the XSD chiralityType enum values: enantiomer/racemate/unknown/other. Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Enums
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
chirality = node.chirality.to_s
|
|
18
|
+
return [] if chirality.empty?
|
|
19
|
+
return [] if CHIRALITY_VALUES.include?(chirality)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "molecule #{node.id.inspect} chirality #{chirality.inspect} should be one of " \
|
|
23
|
+
"#{CHIRALITY_VALUES.to_a.sort.inspect}",
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: chirality)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "molecule[#{id}]" : 'molecule'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb
CHANGED
|
@@ -8,6 +8,7 @@ module Chemicalml
|
|
|
8
8
|
# molecules (direct children of `<cml>`). It is REQUIRED on
|
|
9
9
|
# molecules nested inside another `<molecule>`.
|
|
10
10
|
class MoleculeCountMustNotAppearOnTopLevel < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
11
|
+
self.description = 'Molecular convention: `count` MUST NOT appear on top-level molecules (direct children of `<cml>`). It is REQUIRED on molecules nested inside another `<molecule>`.'
|
|
11
12
|
def check(document)
|
|
12
13
|
violations = []
|
|
13
14
|
top_level_molecules(document).each do |mol, path|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<molecule>`'s `id` attribute SHOULD match the XSD
|
|
8
|
+
# moleculeIDType pattern (letter/underscore start, alphanumeric
|
|
9
|
+
# body, optional namespace prefix). Warning severity.
|
|
10
|
+
class MoleculeIdShouldMatchPattern < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = "A `<molecule>`'s `id` attribute SHOULD match the XSD moleculeIDType pattern (letter/underscore start, alphanumeric body, optional namespace prefix). Warning severity."
|
|
12
|
+
include Chemicalml::Cml::Patterns
|
|
13
|
+
|
|
14
|
+
applies_to Chemicalml::Cml::Role::Molecule
|
|
15
|
+
|
|
16
|
+
def check_node(node, _path)
|
|
17
|
+
id = node.id.to_s
|
|
18
|
+
return [] if id.empty?
|
|
19
|
+
return [] if id.match?(/\A#{MOLECULE_ID_PATTERN.source}\z/)
|
|
20
|
+
|
|
21
|
+
[violation(path: yield_path(node),
|
|
22
|
+
message: "molecule id #{id.inspect} should match the moleculeIDType pattern " \
|
|
23
|
+
'(letter start, alphanumeric body, optional prefix)',
|
|
24
|
+
severity: :warning,
|
|
25
|
+
value: id)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def yield_path(node)
|
|
31
|
+
id = node.node_id
|
|
32
|
+
id ? "molecule[#{id}]" : 'molecule'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -5,9 +5,9 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class MoleculeMustHaveId < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <molecule> in a molecular document MUST have an id attribute unique within document scope.'
|
|
8
9
|
applies_to Chemicalml::Cml::Role::Molecule
|
|
9
10
|
def check_node(node, path)
|
|
10
|
-
|
|
11
11
|
return [] unless node.id.to_s.empty?
|
|
12
12
|
|
|
13
13
|
[violation(path: path.empty? ? 'molecule' : path.join('/'),
|
|
@@ -5,9 +5,9 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class PropertyMustHaveDictRef < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <property> MUST have a dictRef attribute that identifies the property type via a dictionary entry.'
|
|
8
9
|
applies_to Chemicalml::Cml::Role::Property
|
|
9
10
|
def check_node(node, path)
|
|
10
|
-
|
|
11
11
|
return [] unless node.dict_ref.to_s.empty?
|
|
12
12
|
|
|
13
13
|
[violation(path: path.empty? ? 'property' : path.join('/'),
|
data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<property>` with a `dictRef` whose dictionary entry declares
|
|
8
|
+
# a `dataType` SHOULD have a child `<scalar>` whose `dataType`
|
|
9
|
+
# attribute matches. Catches inconsistencies like a property
|
|
10
|
+
# declaring `dictRef="cml:bp"` (boiling point, xsd:float) but
|
|
11
|
+
# carrying a `<scalar dataType="xsd:string">`.
|
|
12
|
+
#
|
|
13
|
+
# Warning severity — some dictionaries allow multiple dataTypes.
|
|
14
|
+
class PropertyScalarDataTypeMatchesDictionary < Chemicalml::Convention::Constraint::NodeConstraint
|
|
15
|
+
self.description = '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'
|
|
16
|
+
applies_to Chemicalml::Cml::Role::Property
|
|
17
|
+
|
|
18
|
+
def check_node(node, _path)
|
|
19
|
+
dict_ref = node.dict_ref.to_s
|
|
20
|
+
return [] if dict_ref.empty?
|
|
21
|
+
|
|
22
|
+
entry = lookup_entry(dict_ref)
|
|
23
|
+
return [] unless entry
|
|
24
|
+
|
|
25
|
+
expected_type = entry.data_type.to_s
|
|
26
|
+
return [] if expected_type.empty?
|
|
27
|
+
|
|
28
|
+
scalar = node.scalar
|
|
29
|
+
return [] unless scalar
|
|
30
|
+
|
|
31
|
+
actual_type = scalar.data_type.to_s
|
|
32
|
+
return [] if actual_type.empty?
|
|
33
|
+
return [] if actual_type == expected_type
|
|
34
|
+
|
|
35
|
+
[violation(path: yield_path(node),
|
|
36
|
+
message: "property #{node.id.inspect} dictRef #{dict_ref.inspect} " \
|
|
37
|
+
"expects dataType #{expected_type.inspect} but scalar has #{actual_type.inspect}",
|
|
38
|
+
severity: :warning,
|
|
39
|
+
value: { expected: expected_type, actual: actual_type }.freeze)]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def lookup_entry(dict_ref)
|
|
45
|
+
Chemicalml::Dictionary::Registry.lookup(dict_ref)
|
|
46
|
+
rescue StandardError
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def yield_path(node)
|
|
51
|
+
id = node.node_id
|
|
52
|
+
id ? "property[#{id}]" : 'property'
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Molecular
|
|
6
|
+
module Constraints
|
|
7
|
+
# Walks the document via `Cml::ReferenceResolver` and reports
|
|
8
|
+
# every bond whose `atomRefs2` references atoms that don't
|
|
9
|
+
# exist in the parent molecule. Warning severity — there are
|
|
10
|
+
# edge cases (inter-molecular bonds in transition states).
|
|
11
|
+
#
|
|
12
|
+
# DocumentConstraint because it needs the whole tree to
|
|
13
|
+
# resolve references.
|
|
14
|
+
class ReferencesShouldResolve < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
15
|
+
self.description = "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"
|
|
16
|
+
def check(document)
|
|
17
|
+
resolver = Chemicalml::Cml::ReferenceResolver.new(document)
|
|
18
|
+
resolver.unresolved_refs.map do |entry|
|
|
19
|
+
violation(path: describe(entry[:node]),
|
|
20
|
+
message: "bond #{entry[:node].id.inspect} #{entry[:attr]} references " \
|
|
21
|
+
"missing atoms: #{entry[:missing].inspect}",
|
|
22
|
+
severity: :warning,
|
|
23
|
+
value: entry[:missing])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def describe(node)
|
|
30
|
+
id = node.node_id
|
|
31
|
+
id ? "#{node.element_name}[#{id}]" : node.element_name
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -5,9 +5,9 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
class ScalarMustHaveDataType < Chemicalml::Convention::Constraint::NodeConstraint
|
|
8
|
+
self.description = 'A <scalar> child of a <property> MUST have a dataType attribute (e.g. xsd:float, xsd:integer).'
|
|
8
9
|
applies_to Chemicalml::Cml::Role::Scalar
|
|
9
10
|
def check_node(node, path)
|
|
10
|
-
|
|
11
11
|
return [] unless node.data_type.to_s.empty?
|
|
12
12
|
|
|
13
13
|
[violation(path: path.empty? ? 'scalar' : path.join('/'),
|
|
@@ -5,51 +5,77 @@ module Chemicalml
|
|
|
5
5
|
module Molecular
|
|
6
6
|
module Constraints
|
|
7
7
|
autoload :AtomArrayMustContainAtoms,
|
|
8
|
-
|
|
8
|
+
'chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms'
|
|
9
9
|
autoload :AtomIdsUniqueWithinMolecule,
|
|
10
|
-
|
|
10
|
+
'chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule'
|
|
11
11
|
autoload :BondMustReferenceAtomsInSameMolecule,
|
|
12
|
-
|
|
12
|
+
'chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule'
|
|
13
13
|
autoload :AtomMustHaveId,
|
|
14
|
-
|
|
14
|
+
'chemicalml/convention/molecular/constraints/atom_must_have_id'
|
|
15
15
|
autoload :AtomMustHaveElementType,
|
|
16
|
-
|
|
16
|
+
'chemicalml/convention/molecular/constraints/atom_must_have_element_type'
|
|
17
17
|
autoload :BondMustHaveAtomRefs2,
|
|
18
|
-
|
|
18
|
+
'chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2'
|
|
19
19
|
autoload :BondMustHaveOrder,
|
|
20
|
-
|
|
20
|
+
'chemicalml/convention/molecular/constraints/bond_must_have_order'
|
|
21
21
|
autoload :MoleculeMustHaveId,
|
|
22
|
-
|
|
22
|
+
'chemicalml/convention/molecular/constraints/molecule_must_have_id'
|
|
23
23
|
autoload :AtomCoordinatesMustBePaired,
|
|
24
|
-
|
|
24
|
+
'chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired'
|
|
25
25
|
autoload :PropertyMustHaveDictRef,
|
|
26
|
-
|
|
26
|
+
'chemicalml/convention/molecular/constraints/property_must_have_dict_ref'
|
|
27
27
|
autoload :ScalarMustHaveDataType,
|
|
28
|
-
|
|
28
|
+
'chemicalml/convention/molecular/constraints/scalar_must_have_data_type'
|
|
29
29
|
autoload :BondOrderShouldNotBeNumeric,
|
|
30
|
-
|
|
30
|
+
'chemicalml/convention/molecular/constraints/bond_order_should_not_be_numeric'
|
|
31
31
|
autoload :AtomIdMustMatchPattern,
|
|
32
|
-
|
|
32
|
+
'chemicalml/convention/molecular/constraints/atom_id_must_match_pattern'
|
|
33
33
|
autoload :MoleculeCountMustNotAppearOnTopLevel,
|
|
34
|
-
|
|
34
|
+
'chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level'
|
|
35
35
|
autoload :MoleculeAtomArrayMutuallyExclusiveWithChildren,
|
|
36
|
-
|
|
36
|
+
'chemicalml/convention/molecular/constraints/molecule_atom_array_mutually_exclusive_with_children'
|
|
37
37
|
autoload :MoleculeBondArrayMutuallyExclusiveWithChildren,
|
|
38
|
-
|
|
38
|
+
'chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children'
|
|
39
39
|
autoload :BondStereoWedgeHashMustHaveAtomRefs2,
|
|
40
|
-
|
|
40
|
+
'chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2'
|
|
41
41
|
autoload :BondStereoCisTransMustHaveAtomRefs4,
|
|
42
|
-
|
|
42
|
+
'chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4'
|
|
43
43
|
autoload :BondStereoOtherMustHaveDictRef,
|
|
44
|
-
|
|
44
|
+
'chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref'
|
|
45
45
|
autoload :BondIdsUniqueWithinMolecule,
|
|
46
|
-
|
|
46
|
+
'chemicalml/convention/molecular/constraints/bond_ids_unique_within_molecule'
|
|
47
47
|
autoload :BondOrderOtherMustHaveDictRef,
|
|
48
|
-
|
|
48
|
+
'chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref'
|
|
49
49
|
autoload :AtomArrayMustBeChildOfMoleculeOrFormula,
|
|
50
|
-
|
|
50
|
+
'chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula'
|
|
51
51
|
autoload :BondArrayMustBeChildOfMolecule,
|
|
52
|
-
|
|
52
|
+
'chemicalml/convention/molecular/constraints/bond_array_must_be_child_of_molecule'
|
|
53
|
+
autoload :BondOrderShouldBeInEnum,
|
|
54
|
+
'chemicalml/convention/molecular/constraints/bond_order_should_be_in_enum'
|
|
55
|
+
autoload :BondStereoShouldBeInEnum,
|
|
56
|
+
'chemicalml/convention/molecular/constraints/bond_stereo_should_be_in_enum'
|
|
57
|
+
autoload :MoleculeChiralityShouldBeInEnum,
|
|
58
|
+
'chemicalml/convention/molecular/constraints/molecule_chirality_should_be_in_enum'
|
|
59
|
+
autoload :BondAtomRefs2ShouldBeDistinct,
|
|
60
|
+
'chemicalml/convention/molecular/constraints/bond_atom_refs2_should_be_distinct'
|
|
61
|
+
autoload :ReferencesShouldResolve,
|
|
62
|
+
'chemicalml/convention/molecular/constraints/references_should_resolve'
|
|
63
|
+
autoload :BondStereoAtomRefs4ShouldBeDistinct,
|
|
64
|
+
'chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct'
|
|
65
|
+
autoload :AtomParityAtomRefs4ShouldBeDistinct,
|
|
66
|
+
'chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct'
|
|
67
|
+
autoload :AtomElementTypeShouldBeInPeriodicTable,
|
|
68
|
+
'chemicalml/convention/molecular/constraints/atom_element_type_should_be_in_periodic_table'
|
|
69
|
+
autoload :DictRefShouldResolve,
|
|
70
|
+
'chemicalml/convention/molecular/constraints/dict_ref_should_resolve'
|
|
71
|
+
autoload :MoleculeIdShouldMatchPattern,
|
|
72
|
+
'chemicalml/convention/molecular/constraints/molecule_id_should_match_pattern'
|
|
73
|
+
autoload :BondIdShouldMatchPattern,
|
|
74
|
+
'chemicalml/convention/molecular/constraints/bond_id_should_match_pattern'
|
|
75
|
+
autoload :AtomParityShouldIncludeParentAtom,
|
|
76
|
+
'chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom'
|
|
77
|
+
autoload :PropertyScalarDataTypeMatchesDictionary,
|
|
78
|
+
'chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary'
|
|
53
79
|
end
|
|
54
80
|
end
|
|
55
81
|
end
|
|
@@ -8,9 +8,9 @@ module Chemicalml
|
|
|
8
8
|
module Molecular
|
|
9
9
|
extend Base
|
|
10
10
|
|
|
11
|
-
autoload :Constraints,
|
|
11
|
+
autoload :Constraints, 'chemicalml/convention/molecular/constraints'
|
|
12
12
|
|
|
13
|
-
QNAME =
|
|
13
|
+
QNAME = 'convention:molecular'
|
|
14
14
|
NAMESPACE_URI = "#{Chemicalml::Convention::CONVENTION_NAMESPACE}molecular".freeze
|
|
15
15
|
|
|
16
16
|
def self.qname
|
|
@@ -44,6 +44,19 @@ module Chemicalml
|
|
|
44
44
|
register Constraints::BondOrderOtherMustHaveDictRef
|
|
45
45
|
register Constraints::AtomArrayMustBeChildOfMoleculeOrFormula
|
|
46
46
|
register Constraints::BondArrayMustBeChildOfMolecule
|
|
47
|
+
register Constraints::BondOrderShouldBeInEnum
|
|
48
|
+
register Constraints::BondStereoShouldBeInEnum
|
|
49
|
+
register Constraints::MoleculeChiralityShouldBeInEnum
|
|
50
|
+
register Constraints::BondAtomRefs2ShouldBeDistinct
|
|
51
|
+
register Constraints::ReferencesShouldResolve
|
|
52
|
+
register Constraints::BondStereoAtomRefs4ShouldBeDistinct
|
|
53
|
+
register Constraints::AtomParityAtomRefs4ShouldBeDistinct
|
|
54
|
+
register Constraints::AtomElementTypeShouldBeInPeriodicTable
|
|
55
|
+
register Constraints::DictRefShouldResolve
|
|
56
|
+
register Constraints::MoleculeIdShouldMatchPattern
|
|
57
|
+
register Constraints::BondIdShouldMatchPattern
|
|
58
|
+
register Constraints::AtomParityShouldIncludeParentAtom
|
|
59
|
+
register Constraints::PropertyScalarDataTypeMatchesDictionary
|
|
47
60
|
end
|
|
48
61
|
end
|
|
49
62
|
end
|
|
@@ -35,7 +35,7 @@ module Chemicalml
|
|
|
35
35
|
# declares no convention or an unknown one.
|
|
36
36
|
def self.detect_and_validate(document)
|
|
37
37
|
qname = Convention::Detection.convention_of(document)
|
|
38
|
-
raise ArgumentError,
|
|
38
|
+
raise ArgumentError, 'document declares no convention attribute' unless qname
|
|
39
39
|
|
|
40
40
|
validate_report(document, qname: qname)
|
|
41
41
|
end
|
|
@@ -44,21 +44,89 @@ module Chemicalml
|
|
|
44
44
|
load_cache.keys.sort
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
# Iterate every registered convention. Yields the convention
|
|
48
|
+
# module. Enumerable-style: returns an Enumerator if no block.
|
|
49
|
+
#
|
|
50
|
+
# @yield [Module] each convention module.
|
|
51
|
+
# @return [Array<Module>, Enumerator] the conventions if a
|
|
52
|
+
# block is given; otherwise an Enumerator.
|
|
53
|
+
def self.each(&)
|
|
54
|
+
return to_enum(:each) unless block_given?
|
|
55
|
+
|
|
56
|
+
load_cache.values.sort_by(&:qname).each(&)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Iterate every constraint across every convention. Yields
|
|
60
|
+
# (convention, constraint_class) pairs. Useful for documentation
|
|
61
|
+
# generation and code introspection.
|
|
62
|
+
#
|
|
63
|
+
# @yieldparam convention [Module] the convention module.
|
|
64
|
+
# @yieldparam constraint [Class] the constraint class.
|
|
65
|
+
# @return [Enumerator, Integer] count if block given; otherwise
|
|
66
|
+
# an Enumerator.
|
|
67
|
+
def self.each_constraint(&)
|
|
68
|
+
return to_enum(:each_constraint) unless block_given?
|
|
69
|
+
|
|
70
|
+
count = 0
|
|
71
|
+
each do |conv|
|
|
72
|
+
conv.constraints.each do |constraint|
|
|
73
|
+
yield(conv, constraint)
|
|
74
|
+
count += 1
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
count
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Total count of registered constraints across all conventions.
|
|
81
|
+
def self.total_constraint_count
|
|
82
|
+
each.sum(&:constraint_count)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# True if a document with the given Role could carry a
|
|
86
|
+
# convention attribute that Detection would recognise.
|
|
87
|
+
#
|
|
88
|
+
# @param role [Module] a Role::* module.
|
|
89
|
+
# @return [Boolean]
|
|
90
|
+
def self.convention_root?(role)
|
|
91
|
+
Detection::CONVENTION_ROOTS.any? { |r| role <= r }
|
|
92
|
+
rescue StandardError
|
|
93
|
+
Detection::CONVENTION_ROOTS.include?(role)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Register a custom convention at runtime. The convention module
|
|
97
|
+
# must extend `Chemicalml::Convention::Base` and implement
|
|
98
|
+
# `qname` and `namespace_uri`.
|
|
99
|
+
#
|
|
100
|
+
# @param mod [Module] the convention module (must `extend Base`).
|
|
101
|
+
# @return [Module] the registered module.
|
|
102
|
+
# @raise [ArgumentError] if `mod.qname` is nil/empty.
|
|
103
|
+
def self.register_custom(mod)
|
|
104
|
+
qname = mod.qname
|
|
105
|
+
raise ArgumentError, 'convention module must return a non-empty qname' if qname.nil? || qname.to_s.empty?
|
|
106
|
+
|
|
107
|
+
# Force load_cache to populate (acquires/releases mutex internally),
|
|
108
|
+
# then mutate directly without re-entering the mutex.
|
|
109
|
+
cache = load_cache
|
|
110
|
+
cache[qname.to_s] = mod
|
|
111
|
+
mod
|
|
112
|
+
end
|
|
113
|
+
|
|
47
114
|
def self.reset!
|
|
48
|
-
@mutex.synchronize { @
|
|
115
|
+
@mutex.synchronize { @load_cache = nil }
|
|
49
116
|
end
|
|
50
117
|
|
|
51
118
|
def self.load_cache
|
|
52
119
|
@mutex.synchronize do
|
|
53
|
-
@
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
120
|
+
@load_cache ||= {
|
|
121
|
+
Molecular.qname => Molecular,
|
|
122
|
+
Compchem.qname => Compchem,
|
|
123
|
+
Dictionary.qname => Dictionary,
|
|
124
|
+
UnitDictionary.qname => UnitDictionary,
|
|
125
|
+
UnitTypeDictionary.qname => UnitTypeDictionary,
|
|
126
|
+
Spectroscopy.qname => Spectroscopy,
|
|
127
|
+
Cascade.qname => Cascade,
|
|
128
|
+
SimpleUnit.qname => SimpleUnit
|
|
129
|
+
}
|
|
62
130
|
end
|
|
63
131
|
end
|
|
64
132
|
private_class_method :load_cache
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module SimpleUnit
|
|
6
|
+
module Constraints
|
|
7
|
+
# The root of a simpleUnit document MUST be a `<unitList>`
|
|
8
|
+
# declaring `convention="convention:simpleUnit"`. Any other
|
|
9
|
+
# root shape is rejected.
|
|
10
|
+
class RootMustBeUnitList < Chemicalml::Convention::Constraint::DocumentConstraint
|
|
11
|
+
self.description = 'The root of a simpleUnit document MUST be a `<unitList>` declaring `convention="convention:simpleUnit"`. Any other root shape is rejected.'
|
|
12
|
+
def check(document)
|
|
13
|
+
return [] if document.is_a?(Chemicalml::Cml::Role::UnitList) &&
|
|
14
|
+
document.convention == 'convention:simpleUnit'
|
|
15
|
+
|
|
16
|
+
[violation(path: '/',
|
|
17
|
+
message: 'simpleUnit root must be <unitList> declaring ' \
|
|
18
|
+
'convention="convention:simpleUnit"')]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module SimpleUnit
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<unit>` under simpleUnit MUST declare a `power` attribute
|
|
8
|
+
# (integer). Without a power the unit's exponent is undefined.
|
|
9
|
+
class UnitMustHavePower < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = "A `<unit>` under simpleUnit MUST declare a `power` attribute (integer). Without a power the unit's exponent is undefined."
|
|
11
|
+
applies_to Chemicalml::Cml::Role::Unit
|
|
12
|
+
|
|
13
|
+
def check_node(node, _path)
|
|
14
|
+
power = node.power.to_s.strip
|
|
15
|
+
return [] unless power.empty?
|
|
16
|
+
|
|
17
|
+
[violation(path: yield_path(node),
|
|
18
|
+
message: "unit #{node.id.inspect} must declare a power attribute",
|
|
19
|
+
value: node.power)]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def yield_path(node)
|
|
25
|
+
id = node.node_id
|
|
26
|
+
id ? "unit[#{id}]" : 'unit'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|