chemicalml 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +7 -1
- data/.rubocop.yml +23 -0
- data/CLAUDE.md +95 -40
- data/README.adoc +154 -26
- data/TODO.align/36-molecular-convention-coverage.md +46 -0
- data/TODO.align/37-compchem-convention-coverage.md +55 -0
- data/TODO.align/38-dictionary-convention-coverage.md +34 -0
- data/TODO.align/39-unit-dictionary-convention-coverage.md +33 -0
- data/TODO.align/40-unit-type-dictionary-convention-coverage.md +28 -0
- data/TODO.align/41-expand-canonical-model-layer.md +43 -0
- data/TODO.align/42-translator-wire-new-models.md +31 -0
- data/TODO.align/43-dictionary-model-no-to-h.md +39 -0
- data/TODO.align/44-schema3-only-and-schema24-module.md +44 -0
- data/TODO.align/45-documentation-and-final-verification.md +23 -0
- data/TODO.align/46-lattice-vector-content.md +24 -0
- data/TODO.align/47-molecule-crystal-spectra-property-lists.md +23 -0
- data/TODO.align/48-model-list-and-module-lists.md +21 -0
- data/TODO.align/49-more-chemistry-models.md +34 -0
- data/TODO.align/50-validation-report.md +29 -0
- data/TODO.align/51-convention-auto-detection.md +30 -0
- data/TODO.align/52-schema24-legacy-elements.md +28 -0
- data/TODO.align/53-round-trip-integration-specs.md +30 -0
- data/TODO.align/54-document-versioned-parser-shim.md +38 -0
- data/TODO.align/55-molecule-missing-attributes.md +20 -0
- data/TODO.align/56-geometry-models.md +24 -0
- data/TODO.align/57-compchem-models.md +26 -0
- data/TODO.align/58-remaining-models.md +24 -0
- data/TODO.align/59-wire-new-models-translator.md +18 -0
- data/TODO.align/60-docs-and-final-verification.md +19 -0
- data/TODO.align/61-parallel-array-attrs.md +54 -0
- data/TODO.align/62-per-element-attribute-gaps.md +49 -0
- data/TODO.align/63-universal-children-mixin.md +42 -0
- data/TODO.align/64-per-element-child-gaps.md +81 -0
- data/TODO.align/65-simple-unit-convention.md +40 -0
- data/TODO.align/66-schema24-legacy-children.md +32 -0
- data/TODO.align/67-final-verification.md +32 -0
- data/TODO.align/68-detection-coverage.md +33 -0
- data/TODO.align/69-json-yaml-roundtrip.md +27 -0
- data/TODO.align/70-iterative-walker.md +40 -0
- data/TODO.align/71-violation-value.md +25 -0
- data/TODO.align/72-close-child-gaps.md +66 -0
- data/TODO.align/73-schema24-parse-limitation.md +64 -0
- data/TODO.align/74-final-verification-round18.md +15 -0
- data/TODO.align/75-key-value-mappings.md +43 -0
- data/TODO.align/76-schema24-workaround.md +57 -0
- data/TODO.align/77-convention-coverage-matrix.md +31 -0
- data/TODO.align/78-fixture-audit.md +23 -0
- data/TODO.align/79-final-verification-round19.md +15 -0
- data/TODO.align/80-xsd-enum-constants.md +35 -0
- data/TODO.align/81-enum-validation-constraints.md +29 -0
- data/TODO.align/82-reference-resolver.md +33 -0
- data/TODO.align/83-toml-roundtrip.md +20 -0
- data/TODO.align/84-final-verification-round21.md +16 -0
- data/TODO.align/85-bond-distinct-atoms.md +25 -0
- data/TODO.align/86-references-should-resolve.md +20 -0
- data/TODO.align/87-cli-utility.md +26 -0
- data/TODO.align/88-diverse-fixtures.md +26 -0
- data/TODO.align/89-final-verification-round22.md +15 -0
- data/TODO.align/90-bond-stereo-completeness.md +31 -0
- data/TODO.align/91-atomparity-distinct.md +21 -0
- data/TODO.align/92-unit-dictionary-completeness.md +28 -0
- data/TODO.align/93-yard-docs.md +23 -0
- data/TODO.align/94-final-verification-round23.md +15 -0
- data/TODO.align/README.round17.md +28 -0
- data/TODO.align/README.round18.md +37 -0
- data/TODO.align/README.round19.md +40 -0
- data/TODO.align/README.round20.md +49 -0
- data/TODO.align/README.round21.md +35 -0
- data/TODO.align/README.round22.md +48 -0
- data/TODO.align/README.round23.md +46 -0
- data/TODO.align/README.round24.md +53 -0
- data/TODO.align/README.round25.md +66 -0
- data/TODO.align/README.round26.md +55 -0
- data/TODO.align/README.round27.md +51 -0
- data/TODO.align/README.round28.md +61 -0
- data/TODO.align/README.round29.md +64 -0
- data/TODO.align/README.round30.md +50 -0
- data/TODO.align/README.round31.md +54 -0
- data/TODO.align/README.round32.md +67 -0
- data/TODO.align/README.round33.md +62 -0
- data/TODO.align/README.round34.md +70 -0
- data/docs/constraints.md +161 -0
- data/docs/generate_constraint_docs.rb +44 -0
- data/exe/chemicalml +6 -0
- data/lib/chemicalml/cli/base.rb +68 -0
- data/lib/chemicalml/cli/command.rb +43 -0
- data/lib/chemicalml/cli/constraints_command.rb +27 -0
- data/lib/chemicalml/cli/conventions_command.rb +14 -0
- data/lib/chemicalml/cli/dictionaries_command.rb +14 -0
- data/lib/chemicalml/cli/elements_command.rb +17 -0
- data/lib/chemicalml/cli/enums_command.rb +17 -0
- data/lib/chemicalml/cli/info_command.rb +77 -0
- data/lib/chemicalml/cli/inspect_command.rb +39 -0
- data/lib/chemicalml/cli/validate_command.rb +54 -0
- data/lib/chemicalml/cli.rb +43 -0
- data/lib/chemicalml/cml/base/abundance.rb +21 -5
- data/lib/chemicalml/cml/base/action.rb +44 -6
- data/lib/chemicalml/cml/base/action_list.rb +44 -8
- data/lib/chemicalml/cml/base/alternative.rb +37 -0
- data/lib/chemicalml/cml/base/amount.rb +15 -5
- data/lib/chemicalml/cml/base/angle.rb +34 -7
- data/lib/chemicalml/cml/base/annotation.rb +38 -0
- data/lib/chemicalml/cml/base/any_cml.rb +12 -5
- data/lib/chemicalml/cml/base/appinfo.rb +40 -0
- data/lib/chemicalml/cml/base/arg.rb +80 -0
- data/lib/chemicalml/cml/base/array.rb +51 -8
- data/lib/chemicalml/cml/base/array_list.rb +15 -5
- data/lib/chemicalml/cml/base/atom.rb +93 -19
- data/lib/chemicalml/cml/base/atom_array.rb +77 -2
- data/lib/chemicalml/cml/base/atom_parity.rb +18 -2
- data/lib/chemicalml/cml/base/atom_set.rb +15 -5
- data/lib/chemicalml/cml/base/atom_type.rb +27 -7
- data/lib/chemicalml/cml/base/atom_type_list.rb +23 -7
- data/lib/chemicalml/cml/base/atomic_basis_function.rb +35 -11
- data/lib/chemicalml/cml/base/band.rb +22 -7
- data/lib/chemicalml/cml/base/band_list.rb +15 -7
- data/lib/chemicalml/cml/base/basis_set.rb +26 -7
- data/lib/chemicalml/cml/base/bond.rb +39 -7
- data/lib/chemicalml/cml/base/bond_array.rb +41 -2
- data/lib/chemicalml/cml/base/bond_set.rb +15 -5
- data/lib/chemicalml/cml/base/bond_stereo.rb +25 -4
- data/lib/chemicalml/cml/base/bond_type.rb +24 -7
- data/lib/chemicalml/cml/base/bond_type_list.rb +23 -7
- data/lib/chemicalml/cml/base/cell_parameter.rb +30 -8
- data/lib/chemicalml/cml/base/cml_module.rb +36 -11
- data/lib/chemicalml/cml/base/common_children.rb +35 -0
- data/lib/chemicalml/cml/base/complex_object.rb +37 -0
- data/lib/chemicalml/cml/base/condition_list.rb +28 -8
- data/lib/chemicalml/cml/base/crystal.rb +27 -9
- data/lib/chemicalml/cml/base/definition.rb +12 -5
- data/lib/chemicalml/cml/base/description.rb +15 -5
- data/lib/chemicalml/cml/base/dictionary.rb +30 -7
- data/lib/chemicalml/cml/base/dictionary_entry.rb +67 -8
- data/lib/chemicalml/cml/base/dimension.rb +31 -7
- data/lib/chemicalml/cml/base/document.rb +18 -8
- data/lib/chemicalml/cml/base/documentation.rb +12 -5
- data/lib/chemicalml/cml/base/eigen.rb +33 -7
- data/lib/chemicalml/cml/base/electron.rb +29 -9
- data/lib/chemicalml/cml/base/enumeration.rb +41 -0
- data/lib/chemicalml/cml/base/expression.rb +47 -0
- data/lib/chemicalml/cml/base/float.rb +52 -0
- data/lib/chemicalml/cml/base/float_array.rb +55 -0
- data/lib/chemicalml/cml/base/formula.rb +31 -10
- data/lib/chemicalml/cml/base/fragment.rb +33 -9
- data/lib/chemicalml/cml/base/fragment_list.rb +26 -7
- data/lib/chemicalml/cml/base/gradient.rb +19 -6
- data/lib/chemicalml/cml/base/identifier.rb +22 -4
- data/lib/chemicalml/cml/base/integer.rb +52 -0
- data/lib/chemicalml/cml/base/integer_array.rb +55 -0
- data/lib/chemicalml/cml/base/isotope.rb +29 -8
- data/lib/chemicalml/cml/base/isotope_list.rb +18 -7
- data/lib/chemicalml/cml/base/join.rb +28 -6
- data/lib/chemicalml/cml/base/kpoint.rb +17 -6
- data/lib/chemicalml/cml/base/kpoint_list.rb +15 -7
- data/lib/chemicalml/cml/base/label.rb +15 -5
- data/lib/chemicalml/cml/base/lattice.rb +36 -9
- data/lib/chemicalml/cml/base/lattice_vector.rb +17 -6
- data/lib/chemicalml/cml/base/length.rb +31 -7
- data/lib/chemicalml/cml/base/line3.rb +21 -5
- data/lib/chemicalml/cml/base/link.rb +51 -10
- data/lib/chemicalml/cml/base/list.rb +23 -9
- data/lib/chemicalml/cml/base/map.rb +38 -5
- data/lib/chemicalml/cml/base/matrix.rb +38 -9
- data/lib/chemicalml/cml/base/mechanism.rb +20 -7
- data/lib/chemicalml/cml/base/mechanism_component.rb +14 -6
- data/lib/chemicalml/cml/base/metadata.rb +20 -6
- data/lib/chemicalml/cml/base/metadata_list.rb +30 -5
- data/lib/chemicalml/cml/base/molecule.rb +95 -21
- data/lib/chemicalml/cml/base/molecule_list.rb +27 -7
- data/lib/chemicalml/cml/base/name.rb +11 -3
- data/lib/chemicalml/cml/base/object.rb +20 -6
- data/lib/chemicalml/cml/base/observation.rb +18 -5
- data/lib/chemicalml/cml/base/operator.rb +40 -0
- data/lib/chemicalml/cml/base/parameter.rb +38 -8
- data/lib/chemicalml/cml/base/parameter_list.rb +30 -5
- data/lib/chemicalml/cml/base/particle.rb +23 -6
- data/lib/chemicalml/cml/base/peak.rb +86 -11
- data/lib/chemicalml/cml/base/peak_group.rb +81 -7
- data/lib/chemicalml/cml/base/peak_list.rb +25 -8
- data/lib/chemicalml/cml/base/peak_structure.rb +47 -6
- data/lib/chemicalml/cml/base/plane3.rb +15 -5
- data/lib/chemicalml/cml/base/point3.rb +15 -5
- data/lib/chemicalml/cml/base/potential.rb +17 -6
- data/lib/chemicalml/cml/base/potential_form.rb +31 -6
- data/lib/chemicalml/cml/base/potential_list.rb +15 -7
- data/lib/chemicalml/cml/base/product.rb +53 -2
- data/lib/chemicalml/cml/base/product_list.rb +36 -2
- data/lib/chemicalml/cml/base/property.rb +32 -8
- data/lib/chemicalml/cml/base/property_list.rb +26 -5
- data/lib/chemicalml/cml/base/reactant.rb +53 -2
- data/lib/chemicalml/cml/base/reactant_list.rb +36 -2
- data/lib/chemicalml/cml/base/reaction.rb +82 -12
- data/lib/chemicalml/cml/base/reaction_list.rb +29 -2
- data/lib/chemicalml/cml/base/reaction_scheme.rb +48 -8
- data/lib/chemicalml/cml/base/reaction_step.rb +33 -9
- data/lib/chemicalml/cml/base/reaction_step_list.rb +34 -7
- data/lib/chemicalml/cml/base/reactive_centre.rb +31 -6
- data/lib/chemicalml/cml/base/region.rb +24 -5
- data/lib/chemicalml/cml/base/related_entry.rb +34 -0
- data/lib/chemicalml/cml/base/sample.rb +32 -5
- data/lib/chemicalml/cml/base/scalar.rb +41 -6
- data/lib/chemicalml/cml/base/spectator.rb +26 -5
- data/lib/chemicalml/cml/base/spectator_list.rb +20 -7
- data/lib/chemicalml/cml/base/spectrum.rb +63 -12
- data/lib/chemicalml/cml/base/spectrum_data.rb +20 -8
- data/lib/chemicalml/cml/base/spectrum_list.rb +30 -7
- data/lib/chemicalml/cml/base/sphere3.rb +15 -5
- data/lib/chemicalml/cml/base/stmml.rb +12 -5
- data/lib/chemicalml/cml/base/string.rb +40 -0
- data/lib/chemicalml/cml/base/string_array.rb +52 -0
- data/lib/chemicalml/cml/base/substance.rb +42 -8
- data/lib/chemicalml/cml/base/substance_list.rb +32 -7
- data/lib/chemicalml/cml/base/symmetry.rb +33 -7
- data/lib/chemicalml/cml/base/system.rb +23 -8
- data/lib/chemicalml/cml/base/table.rb +43 -8
- data/lib/chemicalml/cml/base/table_cell.rb +12 -5
- data/lib/chemicalml/cml/base/table_content.rb +20 -8
- data/lib/chemicalml/cml/base/table_header.rb +15 -7
- data/lib/chemicalml/cml/base/table_header_cell.rb +27 -5
- data/lib/chemicalml/cml/base/table_row.rb +15 -7
- data/lib/chemicalml/cml/base/table_row_list.rb +15 -7
- data/lib/chemicalml/cml/base/tcell.rb +43 -0
- data/lib/chemicalml/cml/base/torsion.rb +34 -7
- data/lib/chemicalml/cml/base/transform3.rb +12 -5
- data/lib/chemicalml/cml/base/transition_state.rb +23 -5
- data/lib/chemicalml/cml/base/trow.rb +48 -0
- data/lib/chemicalml/cml/base/unit.rb +45 -10
- data/lib/chemicalml/cml/base/unit_list.rb +40 -6
- data/lib/chemicalml/cml/base/unit_type.rb +32 -5
- data/lib/chemicalml/cml/base/unit_type_list.rb +34 -6
- data/lib/chemicalml/cml/base/vector3.rb +15 -5
- data/lib/chemicalml/cml/base/xaxis.rb +33 -7
- data/lib/chemicalml/cml/base/yaxis.rb +33 -7
- data/lib/chemicalml/cml/base/z_matrix.rb +26 -5
- data/lib/chemicalml/cml/base.rb +139 -121
- data/lib/chemicalml/cml/canonical_comparison.rb +54 -0
- data/lib/chemicalml/cml/elements.rb +168 -124
- data/lib/chemicalml/cml/enums.rb +55 -0
- data/lib/chemicalml/cml/namespace.rb +2 -3
- data/lib/chemicalml/cml/patterns.rb +33 -0
- data/lib/chemicalml/cml/reference_resolver.rb +137 -0
- data/lib/chemicalml/cml/role/alternative.rb +10 -0
- data/lib/chemicalml/cml/role/annotation.rb +10 -0
- data/lib/chemicalml/cml/role/appinfo.rb +10 -0
- data/lib/chemicalml/cml/role/arg.rb +10 -0
- data/lib/chemicalml/cml/role/cml_module.rb +2 -3
- data/lib/chemicalml/cml/role/complex_object.rb +10 -0
- data/lib/chemicalml/cml/role/enumeration.rb +10 -0
- data/lib/chemicalml/cml/role/expression.rb +10 -0
- data/lib/chemicalml/cml/role/float.rb +10 -0
- data/lib/chemicalml/cml/role/float_array.rb +10 -0
- data/lib/chemicalml/cml/role/integer.rb +10 -0
- data/lib/chemicalml/cml/role/integer_array.rb +10 -0
- data/lib/chemicalml/cml/role/operator.rb +10 -0
- data/lib/chemicalml/cml/role/related_entry.rb +10 -0
- data/lib/chemicalml/cml/role/string.rb +10 -0
- data/lib/chemicalml/cml/role/string_array.rb +10 -0
- data/lib/chemicalml/cml/role/tcell.rb +10 -0
- data/lib/chemicalml/cml/role/trow.rb +10 -0
- data/lib/chemicalml/cml/role.rb +138 -121
- data/lib/chemicalml/cml/schema24/alternative.rb +14 -0
- data/lib/chemicalml/cml/schema24/annotation.rb +15 -0
- data/lib/chemicalml/cml/schema24/appinfo.rb +15 -0
- data/lib/chemicalml/cml/schema24/arg.rb +14 -0
- data/lib/chemicalml/cml/schema24/cml_module.rb +18 -0
- data/lib/chemicalml/cml/schema24/complex_object.rb +14 -0
- data/lib/chemicalml/cml/schema24/configuration.rb +15 -2
- data/lib/chemicalml/cml/schema24/enumeration.rb +16 -0
- data/lib/chemicalml/cml/schema24/expression.rb +14 -0
- data/lib/chemicalml/cml/schema24/float.rb +14 -0
- data/lib/chemicalml/cml/schema24/float_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/integer.rb +14 -0
- data/lib/chemicalml/cml/schema24/integer_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/operator.rb +14 -0
- data/lib/chemicalml/cml/schema24/related_entry.rb +14 -0
- data/lib/chemicalml/cml/schema24/string.rb +14 -0
- data/lib/chemicalml/cml/schema24/string_array.rb +14 -0
- data/lib/chemicalml/cml/schema24/tcell.rb +14 -0
- data/lib/chemicalml/cml/schema24/trow.rb +14 -0
- data/lib/chemicalml/cml/schema24.rb +154 -126
- data/lib/chemicalml/cml/schema3.rb +123 -123
- data/lib/chemicalml/cml/visitable.rb +77 -3
- data/lib/chemicalml/cml/wire_class_registry.rb +3 -3
- data/lib/chemicalml/cml.rb +164 -132
- data/lib/chemicalml/context_configuration.rb +12 -4
- data/lib/chemicalml/convention/base.rb +17 -3
- data/lib/chemicalml/convention/cascade/constraints/reaction_scheme_must_have_content.rb +33 -0
- data/lib/chemicalml/convention/cascade/constraints/reaction_step_list_must_contain_steps.rb +31 -0
- data/lib/chemicalml/convention/cascade/constraints/reaction_step_must_have_reaction_or_lists.rb +33 -0
- data/lib/chemicalml/convention/cascade/constraints/reactive_centre_atom_refs_should_be_present.rb +34 -0
- data/lib/chemicalml/convention/cascade/constraints.rb +18 -0
- data/lib/chemicalml/convention/cascade.rb +43 -0
- data/lib/chemicalml/convention/compchem/constraints/array_rules.rb +44 -0
- data/lib/chemicalml/convention/compchem/constraints/calculation_requires_finalization.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +5 -4
- data/lib/chemicalml/convention/compchem/constraints/environment_at_most_one_property_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_must_have_content.rb +44 -0
- data/lib/chemicalml/convention/compchem/constraints/finalization_must_not_contain_parameter.rb +27 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list.rb +26 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_must_have_content.rb +54 -0
- data/lib/chemicalml/convention/compchem/constraints/initialization_must_not_contain_property.rb +28 -0
- data/lib/chemicalml/convention/compchem/constraints/job_list_module_must_have_id.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_environment.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_module_must_have_id.rb +25 -0
- data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +7 -9
- data/lib/chemicalml/convention/compchem/constraints/matrix_rules.rb +48 -0
- data/lib/chemicalml/convention/compchem/constraints/module_predicates.rb +50 -0
- data/lib/chemicalml/convention/compchem/constraints/scalar_units.rb +42 -0
- data/lib/chemicalml/convention/compchem/constraints.rb +40 -2
- data/lib/chemicalml/convention/compchem.rb +20 -2
- data/lib/chemicalml/convention/constraint.rb +68 -24
- data/lib/chemicalml/convention/coordinator.rb +90 -0
- data/lib/chemicalml/convention/detection.rb +39 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace.rb +29 -0
- data/lib/chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash.rb +32 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern.rb +33 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +4 -4
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_contain_definition.rb +29 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +6 -6
- data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_unit_type.rb +31 -0
- data/lib/chemicalml/convention/dictionary/constraints/entry_units_co_constraints.rb +44 -0
- data/lib/chemicalml/convention/dictionary/constraints.rb +14 -2
- data/lib/chemicalml/convention/dictionary.rb +8 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula.rb +41 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +18 -9
- data/lib/chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired.rb +6 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_element_type_should_be_in_periodic_table.rb +39 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_id_must_match_pattern.rb +7 -6
- data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +3 -2
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_element_type.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/atom_must_have_id.rb +5 -4
- data/lib/chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom.rb +65 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_array_must_be_child_of_molecule.rb +37 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_atom_refs2_should_be_distinct.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_id_should_match_pattern.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_ids_unique_within_molecule.rb +44 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/bond_must_have_order.rb +5 -4
- data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +4 -3
- data/lib/chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref.rb +34 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_should_be_in_enum.rb +39 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_order_should_not_be_numeric.rb +3 -3
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct.rb +43 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4.rb +45 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref.rb +33 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_should_be_in_enum.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb +45 -0
- data/lib/chemicalml/convention/molecular/constraints/dict_ref_should_resolve.rb +59 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_atom_array_mutually_exclusive_with_children.rb +33 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children.rb +32 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_chirality_should_be_in_enum.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb +35 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_id_should_match_pattern.rb +38 -0
- data/lib/chemicalml/convention/molecular/constraints/molecule_must_have_id.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/property_must_have_dict_ref.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb +58 -0
- data/lib/chemicalml/convention/molecular/constraints/references_should_resolve.rb +37 -0
- data/lib/chemicalml/convention/molecular/constraints/scalar_must_have_data_type.rb +4 -4
- data/lib/chemicalml/convention/molecular/constraints.rb +59 -13
- data/lib/chemicalml/convention/molecular.rb +25 -2
- data/lib/chemicalml/convention/registry.rb +95 -10
- data/lib/chemicalml/convention/simple_unit/constraints/root_must_be_unit_list.rb +24 -0
- data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_power.rb +32 -0
- data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_symbol.rb +31 -0
- data/lib/chemicalml/convention/simple_unit/constraints.rb +16 -0
- data/lib/chemicalml/convention/simple_unit.rb +37 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/peak_list_must_contain_peaks.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/peak_should_have_values.rb +34 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_content.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_convention.rb +32 -0
- data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_format.rb +31 -0
- data/lib/chemicalml/convention/spectroscopy/constraints.rb +20 -0
- data/lib/chemicalml/convention/spectroscopy.rb +41 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_contain_at_least_one_unit.rb +29 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_have_namespace.rb +36 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_contain_definition.rb +28 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_id.rb +28 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_multiplier_or_constant_to_si.rb +34 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_parent_si.rb +32 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_symbol_and_unit_type.rb +4 -4
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_title.rb +32 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_parent_si_should_resolve.rb +45 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints/unit_unit_type_should_resolve.rb +46 -0
- data/lib/chemicalml/convention/unit_dictionary/constraints.rb +19 -1
- data/lib/chemicalml/convention/unit_dictionary.rb +11 -2
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_id_must_match_pattern.rb +31 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_contain_at_least_one_unit_type.rb +28 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_have_namespace.rb +35 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_contain_definition.rb +28 -0
- data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +6 -6
- data/lib/chemicalml/convention/unit_type_dictionary/constraints.rb +9 -1
- data/lib/chemicalml/convention/unit_type_dictionary.rb +6 -2
- data/lib/chemicalml/convention/validation_report.rb +90 -0
- data/lib/chemicalml/convention/violation.rb +9 -3
- data/lib/chemicalml/convention.rb +49 -11
- data/lib/chemicalml/dictionary/entry.rb +6 -6
- data/lib/chemicalml/dictionary/enum.rb +1 -1
- data/lib/chemicalml/dictionary/link.rb +3 -3
- data/lib/chemicalml/dictionary/loader.rb +19 -19
- data/lib/chemicalml/dictionary/model.rb +5 -5
- data/lib/chemicalml/dictionary/registry.rb +9 -9
- data/lib/chemicalml/dictionary.rb +13 -9
- data/lib/chemicalml/logger.rb +47 -0
- data/lib/chemicalml/schema/definition.rb +2 -2
- data/lib/chemicalml/schema.rb +7 -7
- data/lib/chemicalml/version.rb +1 -1
- data/lib/chemicalml/versioned_parser.rb +28 -10
- data/lib/chemicalml.rb +79 -17
- data/lib/tasks/reference_fetch.rake +30 -31
- data/lib/tasks/scrape_fixtures.rake +23 -24
- metadata +235 -35
- data/lib/chemicalml/cml/child_mappings.rb +0 -168
- data/lib/chemicalml/cml/translator/value_translations.rb +0 -270
- data/lib/chemicalml/cml/translator.rb +0 -484
- data/lib/chemicalml/model/atom.rb +0 -64
- data/lib/chemicalml/model/atom_parity.rb +0 -21
- data/lib/chemicalml/model/bond.rb +0 -39
- data/lib/chemicalml/model/bond_stereo.rb +0 -29
- data/lib/chemicalml/model/cml_array.rb +0 -27
- data/lib/chemicalml/model/cml_module.rb +0 -45
- data/lib/chemicalml/model/document.rb +0 -29
- data/lib/chemicalml/model/formula.rb +0 -34
- data/lib/chemicalml/model/identifier.rb +0 -21
- data/lib/chemicalml/model/label.rb +0 -21
- data/lib/chemicalml/model/matrix.rb +0 -29
- data/lib/chemicalml/model/metadata.rb +0 -23
- data/lib/chemicalml/model/metadata_list.rb +0 -25
- data/lib/chemicalml/model/molecule.rb +0 -45
- data/lib/chemicalml/model/name.rb +0 -21
- data/lib/chemicalml/model/node.rb +0 -45
- data/lib/chemicalml/model/parameter.rb +0 -27
- data/lib/chemicalml/model/parameter_list.rb +0 -25
- data/lib/chemicalml/model/product.rb +0 -21
- data/lib/chemicalml/model/product_list.rb +0 -21
- data/lib/chemicalml/model/property.rb +0 -28
- data/lib/chemicalml/model/property_list.rb +0 -25
- data/lib/chemicalml/model/reactant.rb +0 -21
- data/lib/chemicalml/model/reactant_list.rb +0 -21
- data/lib/chemicalml/model/reaction.rb +0 -41
- data/lib/chemicalml/model/reaction_list.rb +0 -23
- data/lib/chemicalml/model/scalar.rb +0 -25
- data/lib/chemicalml/model/substance.rb +0 -25
- data/lib/chemicalml/model.rb +0 -40
|
@@ -4,10 +4,48 @@ module Chemicalml
|
|
|
4
4
|
module Convention
|
|
5
5
|
module Compchem
|
|
6
6
|
module Constraints
|
|
7
|
+
autoload :ModulePredicates,
|
|
8
|
+
'chemicalml/convention/compchem/constraints/module_predicates'
|
|
7
9
|
autoload :CompchemModuleMustContainJobList,
|
|
8
|
-
|
|
10
|
+
'chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list'
|
|
9
11
|
autoload :JobMustContainInitialization,
|
|
10
|
-
|
|
12
|
+
'chemicalml/convention/compchem/constraints/job_must_contain_initialization'
|
|
13
|
+
autoload :JobListModuleMustHaveId,
|
|
14
|
+
'chemicalml/convention/compchem/constraints/job_list_module_must_have_id'
|
|
15
|
+
autoload :JobModuleMustHaveId,
|
|
16
|
+
'chemicalml/convention/compchem/constraints/job_module_must_have_id'
|
|
17
|
+
autoload :JobModuleAtMostOneFinalization,
|
|
18
|
+
'chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization'
|
|
19
|
+
autoload :JobModuleAtMostOneEnvironment,
|
|
20
|
+
'chemicalml/convention/compchem/constraints/job_module_at_most_one_environment'
|
|
21
|
+
autoload :CalculationRequiresFinalization,
|
|
22
|
+
'chemicalml/convention/compchem/constraints/calculation_requires_finalization'
|
|
23
|
+
autoload :InitializationAtMostOneMolecule,
|
|
24
|
+
'chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule'
|
|
25
|
+
autoload :InitializationAtMostOneParameterList,
|
|
26
|
+
'chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list'
|
|
27
|
+
autoload :InitializationMustNotContainProperty,
|
|
28
|
+
'chemicalml/convention/compchem/constraints/initialization_must_not_contain_property'
|
|
29
|
+
autoload :FinalizationAtMostOneMolecule,
|
|
30
|
+
'chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule'
|
|
31
|
+
autoload :FinalizationAtMostOnePropertyList,
|
|
32
|
+
'chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list'
|
|
33
|
+
autoload :FinalizationMustNotContainParameter,
|
|
34
|
+
'chemicalml/convention/compchem/constraints/finalization_must_not_contain_parameter'
|
|
35
|
+
autoload :EnvironmentAtMostOnePropertyList,
|
|
36
|
+
'chemicalml/convention/compchem/constraints/environment_at_most_one_property_list'
|
|
37
|
+
autoload :EnvironmentMustNotContainParameter,
|
|
38
|
+
'chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter'
|
|
39
|
+
autoload :ScalarUnits,
|
|
40
|
+
'chemicalml/convention/compchem/constraints/scalar_units'
|
|
41
|
+
autoload :ArrayRules,
|
|
42
|
+
'chemicalml/convention/compchem/constraints/array_rules'
|
|
43
|
+
autoload :MatrixRules,
|
|
44
|
+
'chemicalml/convention/compchem/constraints/matrix_rules'
|
|
45
|
+
autoload :InitializationMustHaveContent,
|
|
46
|
+
'chemicalml/convention/compchem/constraints/initialization_must_have_content'
|
|
47
|
+
autoload :FinalizationMustHaveContent,
|
|
48
|
+
'chemicalml/convention/compchem/constraints/finalization_must_have_content'
|
|
11
49
|
end
|
|
12
50
|
end
|
|
13
51
|
end
|
|
@@ -8,9 +8,9 @@ module Chemicalml
|
|
|
8
8
|
module Compchem
|
|
9
9
|
extend Base
|
|
10
10
|
|
|
11
|
-
autoload :Constraints,
|
|
11
|
+
autoload :Constraints, 'chemicalml/convention/compchem/constraints'
|
|
12
12
|
|
|
13
|
-
QNAME =
|
|
13
|
+
QNAME = 'convention:compchem'
|
|
14
14
|
NAMESPACE_URI = "#{Chemicalml::Convention::CONVENTION_NAMESPACE}compchem".freeze
|
|
15
15
|
|
|
16
16
|
def self.qname
|
|
@@ -23,6 +23,24 @@ module Chemicalml
|
|
|
23
23
|
|
|
24
24
|
register Constraints::CompchemModuleMustContainJobList
|
|
25
25
|
register Constraints::JobMustContainInitialization
|
|
26
|
+
register Constraints::JobListModuleMustHaveId
|
|
27
|
+
register Constraints::JobModuleMustHaveId
|
|
28
|
+
register Constraints::JobModuleAtMostOneFinalization
|
|
29
|
+
register Constraints::JobModuleAtMostOneEnvironment
|
|
30
|
+
register Constraints::CalculationRequiresFinalization
|
|
31
|
+
register Constraints::InitializationAtMostOneMolecule
|
|
32
|
+
register Constraints::InitializationAtMostOneParameterList
|
|
33
|
+
register Constraints::InitializationMustNotContainProperty
|
|
34
|
+
register Constraints::FinalizationAtMostOneMolecule
|
|
35
|
+
register Constraints::FinalizationAtMostOnePropertyList
|
|
36
|
+
register Constraints::FinalizationMustNotContainParameter
|
|
37
|
+
register Constraints::EnvironmentAtMostOnePropertyList
|
|
38
|
+
register Constraints::EnvironmentMustNotContainParameter
|
|
39
|
+
register Constraints::ScalarUnits
|
|
40
|
+
register Constraints::ArrayRules
|
|
41
|
+
register Constraints::MatrixRules
|
|
42
|
+
register Constraints::InitializationMustHaveContent
|
|
43
|
+
register Constraints::FinalizationMustHaveContent
|
|
26
44
|
end
|
|
27
45
|
end
|
|
28
46
|
end
|
|
@@ -3,45 +3,87 @@
|
|
|
3
3
|
module Chemicalml
|
|
4
4
|
module Convention
|
|
5
5
|
# Abstract base class for a single constraint. Subclasses implement
|
|
6
|
-
# `check_node` (one node at a time) or `
|
|
7
|
-
# document at once). The base class provides traversal and
|
|
8
|
-
# collection plumbing.
|
|
6
|
+
# `check_node` (one node at a time) or `check` (whole document).
|
|
9
7
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# No framework code changes.
|
|
8
|
+
# A constraint subclass MAY declare `applies_to` — one or more
|
|
9
|
+
# `Cml::Role::*` modules. When it does, the Coordinator only
|
|
10
|
+
# invokes `check_node` for nodes matching that role. Without
|
|
11
|
+
# `applies_to`, the constraint receives every node (legacy
|
|
12
|
+
# behaviour). Declaring `applies_to` is the fast path: the
|
|
13
|
+
# dispatch is O(node.ancestors) per node, not O(constraint_count).
|
|
18
14
|
class Constraint
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
class << self
|
|
16
|
+
# Returns the Role module(s) this constraint applies to, or
|
|
17
|
+
# nil if it must run for every node.
|
|
18
|
+
attr_reader :applies_to_roles
|
|
19
|
+
|
|
20
|
+
# Declare one or more Role modules this constraint handles.
|
|
21
|
+
# applies_to Chemicalml::Cml::Role::Atom
|
|
22
|
+
# applies_to Chemicalml::Cml::Role::Bond, Chemicalml::Cml::Role::AtomParity
|
|
23
|
+
def applies_to(*roles)
|
|
24
|
+
@applies_to_roles = roles.flatten.freeze
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Human-readable description of the rule this constraint
|
|
28
|
+
# enforces. Subclasses MAY override. Falls back to the class
|
|
29
|
+
# name. Used by `chemicalml constraints` and the auto-generated
|
|
30
|
+
# constraint docs.
|
|
31
|
+
#
|
|
32
|
+
# @return [String]
|
|
33
|
+
def description
|
|
34
|
+
@description || name.split('::').last
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Set the description (DSL for subclasses).
|
|
38
|
+
# description "A <bond> must have an order attribute"
|
|
39
|
+
attr_writer :description
|
|
40
|
+
|
|
41
|
+
# Severity this constraint emits. Subclasses MAY override.
|
|
42
|
+
# Default `:error` — warning subclasses override to `:warning`.
|
|
43
|
+
#
|
|
44
|
+
# @return [Symbol] `:error` or `:warning`.
|
|
45
|
+
def default_severity
|
|
46
|
+
:error
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def initialize
|
|
51
|
+
freeze
|
|
21
52
|
end
|
|
22
53
|
|
|
23
54
|
def check(_document)
|
|
24
55
|
raise NotImplementedError,
|
|
25
|
-
"#{self.class
|
|
56
|
+
"#{self.class} must implement #check(document)"
|
|
26
57
|
end
|
|
27
58
|
|
|
28
59
|
protected
|
|
29
60
|
|
|
30
|
-
def violation(path:, message:, severity: :error)
|
|
61
|
+
def violation(path:, message:, severity: :error, value: nil)
|
|
31
62
|
Violation.new(path: path, message: message,
|
|
32
|
-
severity: severity, constraint: self.class
|
|
63
|
+
severity: severity, constraint: self.class,
|
|
64
|
+
value: value)
|
|
33
65
|
end
|
|
34
66
|
|
|
35
67
|
# Walk every wire node reachable from `node`. Yields (node, path)
|
|
36
68
|
# pairs. Path is a slash-joined breadcrumb. Nodes that don't
|
|
37
69
|
# include `Chemicalml::Cml::Visitable` are skipped.
|
|
38
|
-
|
|
70
|
+
#
|
|
71
|
+
# Iterative (worklist) implementation — does not recurse, so
|
|
72
|
+
# deeply-nested documents cannot overflow the stack. Traversal
|
|
73
|
+
# order is DFS pre-order, matching the prior recursive walker.
|
|
74
|
+
def walk_nodes(node, path = [])
|
|
39
75
|
return unless node
|
|
40
76
|
return unless visitable?(node)
|
|
41
77
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
78
|
+
worklist = [[node, path]]
|
|
79
|
+
until worklist.empty?
|
|
80
|
+
current, current_path = worklist.shift
|
|
81
|
+
yield(current, current_path)
|
|
82
|
+
current.wire_children.reverse_each do |child|
|
|
83
|
+
next unless visitable?(child)
|
|
84
|
+
|
|
85
|
+
worklist.unshift([child, current_path + [describe(child)]])
|
|
86
|
+
end
|
|
45
87
|
end
|
|
46
88
|
end
|
|
47
89
|
|
|
@@ -54,8 +96,9 @@ module Chemicalml
|
|
|
54
96
|
id_value ? "#{node.element_name}[#{id_value}]" : node.element_name
|
|
55
97
|
end
|
|
56
98
|
|
|
57
|
-
#
|
|
58
|
-
# `check_node(node, path)`. Subclasses get traversal for
|
|
99
|
+
# NodeConstraint: walks the document tree once per node and
|
|
100
|
+
# calls `check_node(node, path)`. Subclasses get traversal for
|
|
101
|
+
# free plus declarative role dispatch via `applies_to`.
|
|
59
102
|
class NodeConstraint < Constraint
|
|
60
103
|
def check(document)
|
|
61
104
|
violations = []
|
|
@@ -70,8 +113,9 @@ module Chemicalml
|
|
|
70
113
|
end
|
|
71
114
|
end
|
|
72
115
|
|
|
73
|
-
#
|
|
74
|
-
# for cross-cutting rules like "atom ids unique within
|
|
116
|
+
# DocumentConstraint: operates on the whole document at once —
|
|
117
|
+
# used for cross-cutting rules like "atom ids unique within
|
|
118
|
+
# molecule". Walks the tree itself; not subject to dispatch.
|
|
75
119
|
class DocumentConstraint < Constraint
|
|
76
120
|
end
|
|
77
121
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
# Single-pass constraint dispatcher. Replaces the previous
|
|
6
|
+
# O(N*C) walk (every constraint walked the whole tree) with
|
|
7
|
+
# O(N + total_applicable) — one tree walk per validation, with
|
|
8
|
+
# each node dispatched only to constraints that declared
|
|
9
|
+
# `applies_to` matching one of the node's ancestors.
|
|
10
|
+
#
|
|
11
|
+
# Constraints that don't declare `applies_to` fall into a
|
|
12
|
+
# default "all nodes" bucket and run for every visited node,
|
|
13
|
+
# preserving backward compatibility.
|
|
14
|
+
class Coordinator
|
|
15
|
+
attr_reader :document_constraints, :node_constraints
|
|
16
|
+
|
|
17
|
+
def initialize(constraint_classes)
|
|
18
|
+
@document_constraints = constraint_classes
|
|
19
|
+
.select { |c| c < Constraint::DocumentConstraint }
|
|
20
|
+
.map(&:new)
|
|
21
|
+
@node_constraints = constraint_constraints(constraint_classes)
|
|
22
|
+
.map(&:new)
|
|
23
|
+
@always_applicable = []
|
|
24
|
+
@by_role = Hash.new { |h, k| h[k] = [] }
|
|
25
|
+
@node_constraints.each { |c| register(c) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def validate(document)
|
|
29
|
+
violations = @document_constraints.flat_map do |constraint|
|
|
30
|
+
Array(constraint.check(document))
|
|
31
|
+
end
|
|
32
|
+
return violations unless visitable?(document)
|
|
33
|
+
|
|
34
|
+
walk(document) do |node, path|
|
|
35
|
+
applicable_for(node).each do |constraint|
|
|
36
|
+
violations.concat(Array(constraint.check_node(node, path)))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
violations
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def constraint_constraints(classes)
|
|
45
|
+
classes.select { |c| c < Constraint::NodeConstraint }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def register(constraint)
|
|
49
|
+
roles = constraint.class.applies_to_roles
|
|
50
|
+
if roles.nil? || roles.empty?
|
|
51
|
+
@always_applicable << constraint
|
|
52
|
+
else
|
|
53
|
+
roles.each { |role| @by_role[role] << constraint }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def visitable?(node)
|
|
58
|
+
node.is_a?(Chemicalml::Cml::Visitable)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def applicable_for(node)
|
|
62
|
+
applicable = @always_applicable
|
|
63
|
+
node.class.ancestors.each do |ancestor|
|
|
64
|
+
next unless ancestor.is_a?(::Module)
|
|
65
|
+
|
|
66
|
+
bucket = @by_role[ancestor]
|
|
67
|
+
next unless bucket
|
|
68
|
+
|
|
69
|
+
applicable += bucket
|
|
70
|
+
end
|
|
71
|
+
applicable
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def walk(node, path = [], &block)
|
|
75
|
+
return unless node
|
|
76
|
+
return unless visitable?(node)
|
|
77
|
+
|
|
78
|
+
yield(node, path)
|
|
79
|
+
node.wire_children.each do |child|
|
|
80
|
+
walk(child, path + [describe(child)], &block)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def describe(node)
|
|
85
|
+
id_value = node.node_id
|
|
86
|
+
id_value ? "#{node.element_name}[#{id_value}]" : node.element_name
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
# Convention detection from a wire document. Reads the
|
|
6
|
+
# `convention` attribute from the root element and returns the
|
|
7
|
+
# QName string (e.g. "convention:molecular").
|
|
8
|
+
#
|
|
9
|
+
# Used by `Registry.detect_and_validate` and reusable by callers
|
|
10
|
+
# that want to know which convention a document declares without
|
|
11
|
+
# running validation.
|
|
12
|
+
module Detection
|
|
13
|
+
# Wire roles that may carry a top-level convention attribute.
|
|
14
|
+
# Adding a new convention whose root is a new element type =
|
|
15
|
+
# adding one role here. OCP — no existing code changes.
|
|
16
|
+
CONVENTION_ROOTS = [
|
|
17
|
+
Chemicalml::Cml::Role::Document,
|
|
18
|
+
Chemicalml::Cml::Role::Module,
|
|
19
|
+
Chemicalml::Cml::Role::Molecule,
|
|
20
|
+
Chemicalml::Cml::Role::Dictionary,
|
|
21
|
+
Chemicalml::Cml::Role::UnitList,
|
|
22
|
+
Chemicalml::Cml::Role::UnitTypeList,
|
|
23
|
+
Chemicalml::Cml::Role::Spectrum,
|
|
24
|
+
Chemicalml::Cml::Role::SpectrumList,
|
|
25
|
+
Chemicalml::Cml::Role::ReactionScheme,
|
|
26
|
+
Chemicalml::Cml::Role::ReactionList
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
def self.convention_of(document)
|
|
30
|
+
CONVENTION_ROOTS.each do |role|
|
|
31
|
+
next unless document.is_a?(role)
|
|
32
|
+
|
|
33
|
+
return document.convention if document.convention
|
|
34
|
+
end
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Dictionary
|
|
6
|
+
module Constraints
|
|
7
|
+
# A `<dictionary>` element MUST have a `namespace` attribute
|
|
8
|
+
# whose value is a valid URI defining the scope within which
|
|
9
|
+
# the entry terms are unique.
|
|
10
|
+
class DictionaryMustHaveNamespace < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = 'A `<dictionary>` element MUST have a `namespace` attribute whose value is a valid URI defining the scope within which the entry terms are unique.'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::Dictionary
|
|
13
|
+
def check_node(node, path)
|
|
14
|
+
return [] unless node.namespace.to_s.empty?
|
|
15
|
+
|
|
16
|
+
[violation(path: path.join('/'),
|
|
17
|
+
message: 'dictionary must have a namespace attribute')]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def dictionary?(node)
|
|
23
|
+
node.is_a?(Chemicalml::Cml::Role::Dictionary)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Dictionary
|
|
6
|
+
module Constraints
|
|
7
|
+
# The `namespace` URI SHOULD end with `/` or `#` so terms can
|
|
8
|
+
# be referenced by appending them to the URI. Warning level.
|
|
9
|
+
class DictionaryNamespaceShouldEndWithSlashOrHash < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'The `namespace` URI SHOULD end with `/` or `#` so terms can be referenced by appending them to the URI. Warning level.'
|
|
11
|
+
applies_to Chemicalml::Cml::Role::Dictionary
|
|
12
|
+
def check_node(node, path)
|
|
13
|
+
ns = node.namespace.to_s
|
|
14
|
+
return [] if ns.empty?
|
|
15
|
+
return [] if ns.end_with?('/', '#')
|
|
16
|
+
|
|
17
|
+
[violation(path: path.join('/'),
|
|
18
|
+
message: "dictionary namespace #{ns.inspect} should end with / or # " \
|
|
19
|
+
'so terms can be referenced by appending',
|
|
20
|
+
severity: :warning)]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def dictionary?(node)
|
|
26
|
+
node.is_a?(Chemicalml::Cml::Role::Dictionary)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Dictionary
|
|
6
|
+
module Constraints
|
|
7
|
+
# An `<entry>` `id` MUST match `[A-Za-z][A-Za-z0-9._-]*` —
|
|
8
|
+
# start with a letter, followed by letters/digits/dot/hyphen/
|
|
9
|
+
# underscore. Mirrors the upstream IdStartChar / IdChar BNF.
|
|
10
|
+
class EntryIdMustMatchPattern < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = '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.'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::DictionaryEntry
|
|
13
|
+
PATTERN = /\A[A-Za-z][A-Za-z0-9._-]*\z/
|
|
14
|
+
|
|
15
|
+
def check_node(node, path)
|
|
16
|
+
id = node.id.to_s
|
|
17
|
+
return [] if id.empty?
|
|
18
|
+
return [] if id.match?(PATTERN)
|
|
19
|
+
|
|
20
|
+
[violation(path: path.join('/'),
|
|
21
|
+
message: "entry id #{id.inspect} must match [A-Za-z][A-Za-z0-9._-]*")]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def entry?(node)
|
|
27
|
+
node.is_a?(Chemicalml::Cml::Role::DictionaryEntry)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -7,16 +7,16 @@ module Chemicalml
|
|
|
7
7
|
# Entry ids MUST be unique within the parent dictionary per
|
|
8
8
|
# the dictionary convention.
|
|
9
9
|
class EntryIdsUniqueWithinDictionary < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Entry ids MUST be unique within the parent dictionary per the dictionary convention.'
|
|
11
|
+
applies_to Chemicalml::Cml::Role::Dictionary
|
|
10
12
|
def check_node(node, path)
|
|
11
|
-
return [] unless dictionary?(node)
|
|
12
|
-
|
|
13
13
|
entries = node.entries || []
|
|
14
|
-
ids = entries.map
|
|
14
|
+
ids = entries.map(&:id).compact
|
|
15
15
|
duplicates = ids.group_by { |x| x }.select { |_, v| v.length > 1 }.keys
|
|
16
16
|
return [] if duplicates.empty?
|
|
17
17
|
|
|
18
18
|
duplicates.map do |dup|
|
|
19
|
-
violation(path: path.join(
|
|
19
|
+
violation(path: path.join('/'),
|
|
20
20
|
message: "duplicate entry id #{dup.inspect} within dictionary")
|
|
21
21
|
end
|
|
22
22
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Dictionary
|
|
6
|
+
module Constraints
|
|
7
|
+
# An `<entry>` MUST contain a single `definition` child
|
|
8
|
+
# element. The schema allows it as a string; this constraint
|
|
9
|
+
# enforces presence.
|
|
10
|
+
class EntryMustContainDefinition < Chemicalml::Convention::Constraint::NodeConstraint
|
|
11
|
+
self.description = 'An `<entry>` MUST contain a single `definition` child element. The schema allows it as a string; this constraint enforces presence.'
|
|
12
|
+
applies_to Chemicalml::Cml::Role::DictionaryEntry
|
|
13
|
+
def check_node(node, path)
|
|
14
|
+
return [] unless node.definition.to_s.strip.empty?
|
|
15
|
+
|
|
16
|
+
[violation(path: path.join('/'),
|
|
17
|
+
message: "entry #{node.id.inspect} must contain a single definition child")]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def entry?(node)
|
|
23
|
+
node.is_a?(Chemicalml::Cml::Role::DictionaryEntry)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -7,17 +7,17 @@ module Chemicalml
|
|
|
7
7
|
# Every entry MUST have an `id` and a `term` attribute per the
|
|
8
8
|
# dictionary convention.
|
|
9
9
|
class EntryMustHaveIdAndTerm < Chemicalml::Convention::Constraint::NodeConstraint
|
|
10
|
+
self.description = 'Every entry MUST have an `id` and a `term` attribute per the dictionary convention.'
|
|
11
|
+
applies_to Chemicalml::Cml::Role::DictionaryEntry
|
|
10
12
|
def check_node(node, path)
|
|
11
|
-
return [] unless entry?(node)
|
|
12
|
-
|
|
13
13
|
violations = []
|
|
14
14
|
if node.id.to_s.empty?
|
|
15
|
-
violations << violation(path: path.join(
|
|
16
|
-
message:
|
|
15
|
+
violations << violation(path: path.join('/'),
|
|
16
|
+
message: 'entry must have an id attribute')
|
|
17
17
|
end
|
|
18
18
|
if node.term.to_s.empty?
|
|
19
|
-
violations << violation(path: path.join(
|
|
20
|
-
message:
|
|
19
|
+
violations << violation(path: path.join('/'),
|
|
20
|
+
message: 'entry must have a term attribute')
|
|
21
21
|
end
|
|
22
22
|
violations
|
|
23
23
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Dictionary
|
|
6
|
+
module Constraints
|
|
7
|
+
# An `<entry>` MUST have a `unitType` attribute. Entries
|
|
8
|
+
# describing concepts that should not have units (e.g. name
|
|
9
|
+
# of a program) should reference `none` in the standard CML
|
|
10
|
+
# unitType dictionary.
|
|
11
|
+
class EntryMustHaveUnitType < Chemicalml::Convention::Constraint::NodeConstraint
|
|
12
|
+
self.description = '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'
|
|
13
|
+
applies_to Chemicalml::Cml::Role::DictionaryEntry
|
|
14
|
+
def check_node(node, path)
|
|
15
|
+
return [] unless node.unit_type.to_s.empty?
|
|
16
|
+
|
|
17
|
+
[violation(path: path.join('/'),
|
|
18
|
+
message: "entry #{node.id.inspect} must have a unitType attribute " \
|
|
19
|
+
"(use 'none' for concepts without units)")]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def entry?(node)
|
|
25
|
+
node.is_a?(Chemicalml::Cml::Role::DictionaryEntry)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chemicalml
|
|
4
|
+
module Convention
|
|
5
|
+
module Dictionary
|
|
6
|
+
module Constraints
|
|
7
|
+
# Co-constraint between `unitType` and `units`:
|
|
8
|
+
#
|
|
9
|
+
# - If `unitType` is `unknown`, `units` MUST NOT be present.
|
|
10
|
+
# - If `unitType` is `none`, `units` MUST be present and point
|
|
11
|
+
# to `http://www.xml-cml.org/unit/si#none`.
|
|
12
|
+
class EntryUnitsCoConstraints < Chemicalml::Convention::Constraint::NodeConstraint
|
|
13
|
+
self.description = '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'
|
|
14
|
+
applies_to Chemicalml::Cml::Role::DictionaryEntry
|
|
15
|
+
NONE_UNITS = 'http://www.xml-cml.org/unit/si#none'
|
|
16
|
+
|
|
17
|
+
def check_node(node, path)
|
|
18
|
+
unit_type = node.unit_type.to_s
|
|
19
|
+
units = node.units.to_s
|
|
20
|
+
violations = []
|
|
21
|
+
|
|
22
|
+
if unit_type == 'unknown' && !units.empty?
|
|
23
|
+
violations << violation(path: path.join('/'),
|
|
24
|
+
message: "entry #{node.id.inspect} has unitType 'unknown' " \
|
|
25
|
+
'and therefore must not have units')
|
|
26
|
+
end
|
|
27
|
+
if unit_type == 'none' && units != NONE_UNITS
|
|
28
|
+
violations << violation(path: path.join('/'),
|
|
29
|
+
message: "entry #{node.id.inspect} has unitType 'none' — " \
|
|
30
|
+
"units must be #{NONE_UNITS.inspect}")
|
|
31
|
+
end
|
|
32
|
+
violations
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def entry?(node)
|
|
38
|
+
node.is_a?(Chemicalml::Cml::Role::DictionaryEntry)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -5,9 +5,21 @@ module Chemicalml
|
|
|
5
5
|
module Dictionary
|
|
6
6
|
module Constraints
|
|
7
7
|
autoload :EntryMustHaveIdAndTerm,
|
|
8
|
-
|
|
8
|
+
'chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term'
|
|
9
9
|
autoload :EntryIdsUniqueWithinDictionary,
|
|
10
|
-
|
|
10
|
+
'chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary'
|
|
11
|
+
autoload :DictionaryMustHaveNamespace,
|
|
12
|
+
'chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace'
|
|
13
|
+
autoload :DictionaryNamespaceShouldEndWithSlashOrHash,
|
|
14
|
+
'chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash'
|
|
15
|
+
autoload :EntryMustContainDefinition,
|
|
16
|
+
'chemicalml/convention/dictionary/constraints/entry_must_contain_definition'
|
|
17
|
+
autoload :EntryIdMustMatchPattern,
|
|
18
|
+
'chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern'
|
|
19
|
+
autoload :EntryMustHaveUnitType,
|
|
20
|
+
'chemicalml/convention/dictionary/constraints/entry_must_have_unit_type'
|
|
21
|
+
autoload :EntryUnitsCoConstraints,
|
|
22
|
+
'chemicalml/convention/dictionary/constraints/entry_units_co_constraints'
|
|
11
23
|
end
|
|
12
24
|
end
|
|
13
25
|
end
|
|
@@ -8,9 +8,9 @@ module Chemicalml
|
|
|
8
8
|
module Dictionary
|
|
9
9
|
extend Base
|
|
10
10
|
|
|
11
|
-
autoload :Constraints,
|
|
11
|
+
autoload :Constraints, 'chemicalml/convention/dictionary/constraints'
|
|
12
12
|
|
|
13
|
-
QNAME =
|
|
13
|
+
QNAME = 'convention:dictionary'
|
|
14
14
|
NAMESPACE_URI = "#{Chemicalml::Convention::CONVENTION_NAMESPACE}dictionary".freeze
|
|
15
15
|
|
|
16
16
|
def self.qname
|
|
@@ -23,6 +23,12 @@ module Chemicalml
|
|
|
23
23
|
|
|
24
24
|
register Constraints::EntryMustHaveIdAndTerm
|
|
25
25
|
register Constraints::EntryIdsUniqueWithinDictionary
|
|
26
|
+
register Constraints::DictionaryMustHaveNamespace
|
|
27
|
+
register Constraints::DictionaryNamespaceShouldEndWithSlashOrHash
|
|
28
|
+
register Constraints::EntryMustContainDefinition
|
|
29
|
+
register Constraints::EntryIdMustMatchPattern
|
|
30
|
+
register Constraints::EntryMustHaveUnitType
|
|
31
|
+
register Constraints::EntryUnitsCoConstraints
|
|
26
32
|
end
|
|
27
33
|
end
|
|
28
34
|
end
|