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.
Files changed (450) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +7 -1
  3. data/.rubocop.yml +23 -0
  4. data/CLAUDE.md +95 -40
  5. data/README.adoc +154 -26
  6. data/TODO.align/36-molecular-convention-coverage.md +46 -0
  7. data/TODO.align/37-compchem-convention-coverage.md +55 -0
  8. data/TODO.align/38-dictionary-convention-coverage.md +34 -0
  9. data/TODO.align/39-unit-dictionary-convention-coverage.md +33 -0
  10. data/TODO.align/40-unit-type-dictionary-convention-coverage.md +28 -0
  11. data/TODO.align/41-expand-canonical-model-layer.md +43 -0
  12. data/TODO.align/42-translator-wire-new-models.md +31 -0
  13. data/TODO.align/43-dictionary-model-no-to-h.md +39 -0
  14. data/TODO.align/44-schema3-only-and-schema24-module.md +44 -0
  15. data/TODO.align/45-documentation-and-final-verification.md +23 -0
  16. data/TODO.align/46-lattice-vector-content.md +24 -0
  17. data/TODO.align/47-molecule-crystal-spectra-property-lists.md +23 -0
  18. data/TODO.align/48-model-list-and-module-lists.md +21 -0
  19. data/TODO.align/49-more-chemistry-models.md +34 -0
  20. data/TODO.align/50-validation-report.md +29 -0
  21. data/TODO.align/51-convention-auto-detection.md +30 -0
  22. data/TODO.align/52-schema24-legacy-elements.md +28 -0
  23. data/TODO.align/53-round-trip-integration-specs.md +30 -0
  24. data/TODO.align/54-document-versioned-parser-shim.md +38 -0
  25. data/TODO.align/55-molecule-missing-attributes.md +20 -0
  26. data/TODO.align/56-geometry-models.md +24 -0
  27. data/TODO.align/57-compchem-models.md +26 -0
  28. data/TODO.align/58-remaining-models.md +24 -0
  29. data/TODO.align/59-wire-new-models-translator.md +18 -0
  30. data/TODO.align/60-docs-and-final-verification.md +19 -0
  31. data/TODO.align/61-parallel-array-attrs.md +54 -0
  32. data/TODO.align/62-per-element-attribute-gaps.md +49 -0
  33. data/TODO.align/63-universal-children-mixin.md +42 -0
  34. data/TODO.align/64-per-element-child-gaps.md +81 -0
  35. data/TODO.align/65-simple-unit-convention.md +40 -0
  36. data/TODO.align/66-schema24-legacy-children.md +32 -0
  37. data/TODO.align/67-final-verification.md +32 -0
  38. data/TODO.align/68-detection-coverage.md +33 -0
  39. data/TODO.align/69-json-yaml-roundtrip.md +27 -0
  40. data/TODO.align/70-iterative-walker.md +40 -0
  41. data/TODO.align/71-violation-value.md +25 -0
  42. data/TODO.align/72-close-child-gaps.md +66 -0
  43. data/TODO.align/73-schema24-parse-limitation.md +64 -0
  44. data/TODO.align/74-final-verification-round18.md +15 -0
  45. data/TODO.align/75-key-value-mappings.md +43 -0
  46. data/TODO.align/76-schema24-workaround.md +57 -0
  47. data/TODO.align/77-convention-coverage-matrix.md +31 -0
  48. data/TODO.align/78-fixture-audit.md +23 -0
  49. data/TODO.align/79-final-verification-round19.md +15 -0
  50. data/TODO.align/80-xsd-enum-constants.md +35 -0
  51. data/TODO.align/81-enum-validation-constraints.md +29 -0
  52. data/TODO.align/82-reference-resolver.md +33 -0
  53. data/TODO.align/83-toml-roundtrip.md +20 -0
  54. data/TODO.align/84-final-verification-round21.md +16 -0
  55. data/TODO.align/85-bond-distinct-atoms.md +25 -0
  56. data/TODO.align/86-references-should-resolve.md +20 -0
  57. data/TODO.align/87-cli-utility.md +26 -0
  58. data/TODO.align/88-diverse-fixtures.md +26 -0
  59. data/TODO.align/89-final-verification-round22.md +15 -0
  60. data/TODO.align/90-bond-stereo-completeness.md +31 -0
  61. data/TODO.align/91-atomparity-distinct.md +21 -0
  62. data/TODO.align/92-unit-dictionary-completeness.md +28 -0
  63. data/TODO.align/93-yard-docs.md +23 -0
  64. data/TODO.align/94-final-verification-round23.md +15 -0
  65. data/TODO.align/README.round17.md +28 -0
  66. data/TODO.align/README.round18.md +37 -0
  67. data/TODO.align/README.round19.md +40 -0
  68. data/TODO.align/README.round20.md +49 -0
  69. data/TODO.align/README.round21.md +35 -0
  70. data/TODO.align/README.round22.md +48 -0
  71. data/TODO.align/README.round23.md +46 -0
  72. data/TODO.align/README.round24.md +53 -0
  73. data/TODO.align/README.round25.md +66 -0
  74. data/TODO.align/README.round26.md +55 -0
  75. data/TODO.align/README.round27.md +51 -0
  76. data/TODO.align/README.round28.md +61 -0
  77. data/TODO.align/README.round29.md +64 -0
  78. data/TODO.align/README.round30.md +50 -0
  79. data/TODO.align/README.round31.md +54 -0
  80. data/TODO.align/README.round32.md +67 -0
  81. data/TODO.align/README.round33.md +62 -0
  82. data/TODO.align/README.round34.md +70 -0
  83. data/docs/constraints.md +161 -0
  84. data/docs/generate_constraint_docs.rb +44 -0
  85. data/exe/chemicalml +6 -0
  86. data/lib/chemicalml/cli/base.rb +68 -0
  87. data/lib/chemicalml/cli/command.rb +43 -0
  88. data/lib/chemicalml/cli/constraints_command.rb +27 -0
  89. data/lib/chemicalml/cli/conventions_command.rb +14 -0
  90. data/lib/chemicalml/cli/dictionaries_command.rb +14 -0
  91. data/lib/chemicalml/cli/elements_command.rb +17 -0
  92. data/lib/chemicalml/cli/enums_command.rb +17 -0
  93. data/lib/chemicalml/cli/info_command.rb +77 -0
  94. data/lib/chemicalml/cli/inspect_command.rb +39 -0
  95. data/lib/chemicalml/cli/validate_command.rb +54 -0
  96. data/lib/chemicalml/cli.rb +43 -0
  97. data/lib/chemicalml/cml/base/abundance.rb +21 -5
  98. data/lib/chemicalml/cml/base/action.rb +44 -6
  99. data/lib/chemicalml/cml/base/action_list.rb +44 -8
  100. data/lib/chemicalml/cml/base/alternative.rb +37 -0
  101. data/lib/chemicalml/cml/base/amount.rb +15 -5
  102. data/lib/chemicalml/cml/base/angle.rb +34 -7
  103. data/lib/chemicalml/cml/base/annotation.rb +38 -0
  104. data/lib/chemicalml/cml/base/any_cml.rb +12 -5
  105. data/lib/chemicalml/cml/base/appinfo.rb +40 -0
  106. data/lib/chemicalml/cml/base/arg.rb +80 -0
  107. data/lib/chemicalml/cml/base/array.rb +51 -8
  108. data/lib/chemicalml/cml/base/array_list.rb +15 -5
  109. data/lib/chemicalml/cml/base/atom.rb +93 -19
  110. data/lib/chemicalml/cml/base/atom_array.rb +77 -2
  111. data/lib/chemicalml/cml/base/atom_parity.rb +18 -2
  112. data/lib/chemicalml/cml/base/atom_set.rb +15 -5
  113. data/lib/chemicalml/cml/base/atom_type.rb +27 -7
  114. data/lib/chemicalml/cml/base/atom_type_list.rb +23 -7
  115. data/lib/chemicalml/cml/base/atomic_basis_function.rb +35 -11
  116. data/lib/chemicalml/cml/base/band.rb +22 -7
  117. data/lib/chemicalml/cml/base/band_list.rb +15 -7
  118. data/lib/chemicalml/cml/base/basis_set.rb +26 -7
  119. data/lib/chemicalml/cml/base/bond.rb +39 -7
  120. data/lib/chemicalml/cml/base/bond_array.rb +41 -2
  121. data/lib/chemicalml/cml/base/bond_set.rb +15 -5
  122. data/lib/chemicalml/cml/base/bond_stereo.rb +25 -4
  123. data/lib/chemicalml/cml/base/bond_type.rb +24 -7
  124. data/lib/chemicalml/cml/base/bond_type_list.rb +23 -7
  125. data/lib/chemicalml/cml/base/cell_parameter.rb +30 -8
  126. data/lib/chemicalml/cml/base/cml_module.rb +36 -11
  127. data/lib/chemicalml/cml/base/common_children.rb +35 -0
  128. data/lib/chemicalml/cml/base/complex_object.rb +37 -0
  129. data/lib/chemicalml/cml/base/condition_list.rb +28 -8
  130. data/lib/chemicalml/cml/base/crystal.rb +27 -9
  131. data/lib/chemicalml/cml/base/definition.rb +12 -5
  132. data/lib/chemicalml/cml/base/description.rb +15 -5
  133. data/lib/chemicalml/cml/base/dictionary.rb +30 -7
  134. data/lib/chemicalml/cml/base/dictionary_entry.rb +67 -8
  135. data/lib/chemicalml/cml/base/dimension.rb +31 -7
  136. data/lib/chemicalml/cml/base/document.rb +18 -8
  137. data/lib/chemicalml/cml/base/documentation.rb +12 -5
  138. data/lib/chemicalml/cml/base/eigen.rb +33 -7
  139. data/lib/chemicalml/cml/base/electron.rb +29 -9
  140. data/lib/chemicalml/cml/base/enumeration.rb +41 -0
  141. data/lib/chemicalml/cml/base/expression.rb +47 -0
  142. data/lib/chemicalml/cml/base/float.rb +52 -0
  143. data/lib/chemicalml/cml/base/float_array.rb +55 -0
  144. data/lib/chemicalml/cml/base/formula.rb +31 -10
  145. data/lib/chemicalml/cml/base/fragment.rb +33 -9
  146. data/lib/chemicalml/cml/base/fragment_list.rb +26 -7
  147. data/lib/chemicalml/cml/base/gradient.rb +19 -6
  148. data/lib/chemicalml/cml/base/identifier.rb +22 -4
  149. data/lib/chemicalml/cml/base/integer.rb +52 -0
  150. data/lib/chemicalml/cml/base/integer_array.rb +55 -0
  151. data/lib/chemicalml/cml/base/isotope.rb +29 -8
  152. data/lib/chemicalml/cml/base/isotope_list.rb +18 -7
  153. data/lib/chemicalml/cml/base/join.rb +28 -6
  154. data/lib/chemicalml/cml/base/kpoint.rb +17 -6
  155. data/lib/chemicalml/cml/base/kpoint_list.rb +15 -7
  156. data/lib/chemicalml/cml/base/label.rb +15 -5
  157. data/lib/chemicalml/cml/base/lattice.rb +36 -9
  158. data/lib/chemicalml/cml/base/lattice_vector.rb +17 -6
  159. data/lib/chemicalml/cml/base/length.rb +31 -7
  160. data/lib/chemicalml/cml/base/line3.rb +21 -5
  161. data/lib/chemicalml/cml/base/link.rb +51 -10
  162. data/lib/chemicalml/cml/base/list.rb +23 -9
  163. data/lib/chemicalml/cml/base/map.rb +38 -5
  164. data/lib/chemicalml/cml/base/matrix.rb +38 -9
  165. data/lib/chemicalml/cml/base/mechanism.rb +20 -7
  166. data/lib/chemicalml/cml/base/mechanism_component.rb +14 -6
  167. data/lib/chemicalml/cml/base/metadata.rb +20 -6
  168. data/lib/chemicalml/cml/base/metadata_list.rb +30 -5
  169. data/lib/chemicalml/cml/base/molecule.rb +95 -21
  170. data/lib/chemicalml/cml/base/molecule_list.rb +27 -7
  171. data/lib/chemicalml/cml/base/name.rb +11 -3
  172. data/lib/chemicalml/cml/base/object.rb +20 -6
  173. data/lib/chemicalml/cml/base/observation.rb +18 -5
  174. data/lib/chemicalml/cml/base/operator.rb +40 -0
  175. data/lib/chemicalml/cml/base/parameter.rb +38 -8
  176. data/lib/chemicalml/cml/base/parameter_list.rb +30 -5
  177. data/lib/chemicalml/cml/base/particle.rb +23 -6
  178. data/lib/chemicalml/cml/base/peak.rb +86 -11
  179. data/lib/chemicalml/cml/base/peak_group.rb +81 -7
  180. data/lib/chemicalml/cml/base/peak_list.rb +25 -8
  181. data/lib/chemicalml/cml/base/peak_structure.rb +47 -6
  182. data/lib/chemicalml/cml/base/plane3.rb +15 -5
  183. data/lib/chemicalml/cml/base/point3.rb +15 -5
  184. data/lib/chemicalml/cml/base/potential.rb +17 -6
  185. data/lib/chemicalml/cml/base/potential_form.rb +31 -6
  186. data/lib/chemicalml/cml/base/potential_list.rb +15 -7
  187. data/lib/chemicalml/cml/base/product.rb +53 -2
  188. data/lib/chemicalml/cml/base/product_list.rb +36 -2
  189. data/lib/chemicalml/cml/base/property.rb +32 -8
  190. data/lib/chemicalml/cml/base/property_list.rb +26 -5
  191. data/lib/chemicalml/cml/base/reactant.rb +53 -2
  192. data/lib/chemicalml/cml/base/reactant_list.rb +36 -2
  193. data/lib/chemicalml/cml/base/reaction.rb +82 -12
  194. data/lib/chemicalml/cml/base/reaction_list.rb +29 -2
  195. data/lib/chemicalml/cml/base/reaction_scheme.rb +48 -8
  196. data/lib/chemicalml/cml/base/reaction_step.rb +33 -9
  197. data/lib/chemicalml/cml/base/reaction_step_list.rb +34 -7
  198. data/lib/chemicalml/cml/base/reactive_centre.rb +31 -6
  199. data/lib/chemicalml/cml/base/region.rb +24 -5
  200. data/lib/chemicalml/cml/base/related_entry.rb +34 -0
  201. data/lib/chemicalml/cml/base/sample.rb +32 -5
  202. data/lib/chemicalml/cml/base/scalar.rb +41 -6
  203. data/lib/chemicalml/cml/base/spectator.rb +26 -5
  204. data/lib/chemicalml/cml/base/spectator_list.rb +20 -7
  205. data/lib/chemicalml/cml/base/spectrum.rb +63 -12
  206. data/lib/chemicalml/cml/base/spectrum_data.rb +20 -8
  207. data/lib/chemicalml/cml/base/spectrum_list.rb +30 -7
  208. data/lib/chemicalml/cml/base/sphere3.rb +15 -5
  209. data/lib/chemicalml/cml/base/stmml.rb +12 -5
  210. data/lib/chemicalml/cml/base/string.rb +40 -0
  211. data/lib/chemicalml/cml/base/string_array.rb +52 -0
  212. data/lib/chemicalml/cml/base/substance.rb +42 -8
  213. data/lib/chemicalml/cml/base/substance_list.rb +32 -7
  214. data/lib/chemicalml/cml/base/symmetry.rb +33 -7
  215. data/lib/chemicalml/cml/base/system.rb +23 -8
  216. data/lib/chemicalml/cml/base/table.rb +43 -8
  217. data/lib/chemicalml/cml/base/table_cell.rb +12 -5
  218. data/lib/chemicalml/cml/base/table_content.rb +20 -8
  219. data/lib/chemicalml/cml/base/table_header.rb +15 -7
  220. data/lib/chemicalml/cml/base/table_header_cell.rb +27 -5
  221. data/lib/chemicalml/cml/base/table_row.rb +15 -7
  222. data/lib/chemicalml/cml/base/table_row_list.rb +15 -7
  223. data/lib/chemicalml/cml/base/tcell.rb +43 -0
  224. data/lib/chemicalml/cml/base/torsion.rb +34 -7
  225. data/lib/chemicalml/cml/base/transform3.rb +12 -5
  226. data/lib/chemicalml/cml/base/transition_state.rb +23 -5
  227. data/lib/chemicalml/cml/base/trow.rb +48 -0
  228. data/lib/chemicalml/cml/base/unit.rb +45 -10
  229. data/lib/chemicalml/cml/base/unit_list.rb +40 -6
  230. data/lib/chemicalml/cml/base/unit_type.rb +32 -5
  231. data/lib/chemicalml/cml/base/unit_type_list.rb +34 -6
  232. data/lib/chemicalml/cml/base/vector3.rb +15 -5
  233. data/lib/chemicalml/cml/base/xaxis.rb +33 -7
  234. data/lib/chemicalml/cml/base/yaxis.rb +33 -7
  235. data/lib/chemicalml/cml/base/z_matrix.rb +26 -5
  236. data/lib/chemicalml/cml/base.rb +139 -121
  237. data/lib/chemicalml/cml/canonical_comparison.rb +54 -0
  238. data/lib/chemicalml/cml/elements.rb +168 -124
  239. data/lib/chemicalml/cml/enums.rb +55 -0
  240. data/lib/chemicalml/cml/namespace.rb +2 -3
  241. data/lib/chemicalml/cml/patterns.rb +33 -0
  242. data/lib/chemicalml/cml/reference_resolver.rb +137 -0
  243. data/lib/chemicalml/cml/role/alternative.rb +10 -0
  244. data/lib/chemicalml/cml/role/annotation.rb +10 -0
  245. data/lib/chemicalml/cml/role/appinfo.rb +10 -0
  246. data/lib/chemicalml/cml/role/arg.rb +10 -0
  247. data/lib/chemicalml/cml/role/cml_module.rb +2 -3
  248. data/lib/chemicalml/cml/role/complex_object.rb +10 -0
  249. data/lib/chemicalml/cml/role/enumeration.rb +10 -0
  250. data/lib/chemicalml/cml/role/expression.rb +10 -0
  251. data/lib/chemicalml/cml/role/float.rb +10 -0
  252. data/lib/chemicalml/cml/role/float_array.rb +10 -0
  253. data/lib/chemicalml/cml/role/integer.rb +10 -0
  254. data/lib/chemicalml/cml/role/integer_array.rb +10 -0
  255. data/lib/chemicalml/cml/role/operator.rb +10 -0
  256. data/lib/chemicalml/cml/role/related_entry.rb +10 -0
  257. data/lib/chemicalml/cml/role/string.rb +10 -0
  258. data/lib/chemicalml/cml/role/string_array.rb +10 -0
  259. data/lib/chemicalml/cml/role/tcell.rb +10 -0
  260. data/lib/chemicalml/cml/role/trow.rb +10 -0
  261. data/lib/chemicalml/cml/role.rb +138 -121
  262. data/lib/chemicalml/cml/schema24/alternative.rb +14 -0
  263. data/lib/chemicalml/cml/schema24/annotation.rb +15 -0
  264. data/lib/chemicalml/cml/schema24/appinfo.rb +15 -0
  265. data/lib/chemicalml/cml/schema24/arg.rb +14 -0
  266. data/lib/chemicalml/cml/schema24/cml_module.rb +18 -0
  267. data/lib/chemicalml/cml/schema24/complex_object.rb +14 -0
  268. data/lib/chemicalml/cml/schema24/configuration.rb +15 -2
  269. data/lib/chemicalml/cml/schema24/enumeration.rb +16 -0
  270. data/lib/chemicalml/cml/schema24/expression.rb +14 -0
  271. data/lib/chemicalml/cml/schema24/float.rb +14 -0
  272. data/lib/chemicalml/cml/schema24/float_array.rb +14 -0
  273. data/lib/chemicalml/cml/schema24/integer.rb +14 -0
  274. data/lib/chemicalml/cml/schema24/integer_array.rb +14 -0
  275. data/lib/chemicalml/cml/schema24/operator.rb +14 -0
  276. data/lib/chemicalml/cml/schema24/related_entry.rb +14 -0
  277. data/lib/chemicalml/cml/schema24/string.rb +14 -0
  278. data/lib/chemicalml/cml/schema24/string_array.rb +14 -0
  279. data/lib/chemicalml/cml/schema24/tcell.rb +14 -0
  280. data/lib/chemicalml/cml/schema24/trow.rb +14 -0
  281. data/lib/chemicalml/cml/schema24.rb +154 -126
  282. data/lib/chemicalml/cml/schema3.rb +123 -123
  283. data/lib/chemicalml/cml/visitable.rb +77 -3
  284. data/lib/chemicalml/cml/wire_class_registry.rb +3 -3
  285. data/lib/chemicalml/cml.rb +164 -132
  286. data/lib/chemicalml/context_configuration.rb +12 -4
  287. data/lib/chemicalml/convention/base.rb +17 -3
  288. data/lib/chemicalml/convention/cascade/constraints/reaction_scheme_must_have_content.rb +33 -0
  289. data/lib/chemicalml/convention/cascade/constraints/reaction_step_list_must_contain_steps.rb +31 -0
  290. data/lib/chemicalml/convention/cascade/constraints/reaction_step_must_have_reaction_or_lists.rb +33 -0
  291. data/lib/chemicalml/convention/cascade/constraints/reactive_centre_atom_refs_should_be_present.rb +34 -0
  292. data/lib/chemicalml/convention/cascade/constraints.rb +18 -0
  293. data/lib/chemicalml/convention/cascade.rb +43 -0
  294. data/lib/chemicalml/convention/compchem/constraints/array_rules.rb +44 -0
  295. data/lib/chemicalml/convention/compchem/constraints/calculation_requires_finalization.rb +28 -0
  296. data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +5 -4
  297. data/lib/chemicalml/convention/compchem/constraints/environment_at_most_one_property_list.rb +26 -0
  298. data/lib/chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter.rb +28 -0
  299. data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule.rb +26 -0
  300. data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list.rb +26 -0
  301. data/lib/chemicalml/convention/compchem/constraints/finalization_must_have_content.rb +44 -0
  302. data/lib/chemicalml/convention/compchem/constraints/finalization_must_not_contain_parameter.rb +27 -0
  303. data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule.rb +26 -0
  304. data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list.rb +26 -0
  305. data/lib/chemicalml/convention/compchem/constraints/initialization_must_have_content.rb +54 -0
  306. data/lib/chemicalml/convention/compchem/constraints/initialization_must_not_contain_property.rb +28 -0
  307. data/lib/chemicalml/convention/compchem/constraints/job_list_module_must_have_id.rb +25 -0
  308. data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_environment.rb +25 -0
  309. data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization.rb +25 -0
  310. data/lib/chemicalml/convention/compchem/constraints/job_module_must_have_id.rb +25 -0
  311. data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +7 -9
  312. data/lib/chemicalml/convention/compchem/constraints/matrix_rules.rb +48 -0
  313. data/lib/chemicalml/convention/compchem/constraints/module_predicates.rb +50 -0
  314. data/lib/chemicalml/convention/compchem/constraints/scalar_units.rb +42 -0
  315. data/lib/chemicalml/convention/compchem/constraints.rb +40 -2
  316. data/lib/chemicalml/convention/compchem.rb +20 -2
  317. data/lib/chemicalml/convention/constraint.rb +68 -24
  318. data/lib/chemicalml/convention/coordinator.rb +90 -0
  319. data/lib/chemicalml/convention/detection.rb +39 -0
  320. data/lib/chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace.rb +29 -0
  321. data/lib/chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash.rb +32 -0
  322. data/lib/chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern.rb +33 -0
  323. data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +4 -4
  324. data/lib/chemicalml/convention/dictionary/constraints/entry_must_contain_definition.rb +29 -0
  325. data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +6 -6
  326. data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_unit_type.rb +31 -0
  327. data/lib/chemicalml/convention/dictionary/constraints/entry_units_co_constraints.rb +44 -0
  328. data/lib/chemicalml/convention/dictionary/constraints.rb +14 -2
  329. data/lib/chemicalml/convention/dictionary.rb +8 -2
  330. data/lib/chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula.rb +41 -0
  331. data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +18 -9
  332. data/lib/chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired.rb +6 -6
  333. data/lib/chemicalml/convention/molecular/constraints/atom_element_type_should_be_in_periodic_table.rb +39 -0
  334. data/lib/chemicalml/convention/molecular/constraints/atom_id_must_match_pattern.rb +7 -6
  335. data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +3 -2
  336. data/lib/chemicalml/convention/molecular/constraints/atom_must_have_element_type.rb +4 -4
  337. data/lib/chemicalml/convention/molecular/constraints/atom_must_have_id.rb +5 -4
  338. data/lib/chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct.rb +44 -0
  339. data/lib/chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom.rb +65 -0
  340. data/lib/chemicalml/convention/molecular/constraints/bond_array_must_be_child_of_molecule.rb +37 -0
  341. data/lib/chemicalml/convention/molecular/constraints/bond_atom_refs2_should_be_distinct.rb +44 -0
  342. data/lib/chemicalml/convention/molecular/constraints/bond_id_should_match_pattern.rb +38 -0
  343. data/lib/chemicalml/convention/molecular/constraints/bond_ids_unique_within_molecule.rb +44 -0
  344. data/lib/chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2.rb +4 -4
  345. data/lib/chemicalml/convention/molecular/constraints/bond_must_have_order.rb +5 -4
  346. data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +4 -3
  347. data/lib/chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref.rb +34 -0
  348. data/lib/chemicalml/convention/molecular/constraints/bond_order_should_be_in_enum.rb +39 -0
  349. data/lib/chemicalml/convention/molecular/constraints/bond_order_should_not_be_numeric.rb +3 -3
  350. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct.rb +43 -0
  351. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4.rb +45 -0
  352. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref.rb +33 -0
  353. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_should_be_in_enum.rb +38 -0
  354. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb +45 -0
  355. data/lib/chemicalml/convention/molecular/constraints/dict_ref_should_resolve.rb +59 -0
  356. data/lib/chemicalml/convention/molecular/constraints/molecule_atom_array_mutually_exclusive_with_children.rb +33 -0
  357. data/lib/chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children.rb +32 -0
  358. data/lib/chemicalml/convention/molecular/constraints/molecule_chirality_should_be_in_enum.rb +38 -0
  359. data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb +35 -0
  360. data/lib/chemicalml/convention/molecular/constraints/molecule_id_should_match_pattern.rb +38 -0
  361. data/lib/chemicalml/convention/molecular/constraints/molecule_must_have_id.rb +4 -4
  362. data/lib/chemicalml/convention/molecular/constraints/property_must_have_dict_ref.rb +4 -4
  363. data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb +58 -0
  364. data/lib/chemicalml/convention/molecular/constraints/references_should_resolve.rb +37 -0
  365. data/lib/chemicalml/convention/molecular/constraints/scalar_must_have_data_type.rb +4 -4
  366. data/lib/chemicalml/convention/molecular/constraints.rb +59 -13
  367. data/lib/chemicalml/convention/molecular.rb +25 -2
  368. data/lib/chemicalml/convention/registry.rb +95 -10
  369. data/lib/chemicalml/convention/simple_unit/constraints/root_must_be_unit_list.rb +24 -0
  370. data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_power.rb +32 -0
  371. data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_symbol.rb +31 -0
  372. data/lib/chemicalml/convention/simple_unit/constraints.rb +16 -0
  373. data/lib/chemicalml/convention/simple_unit.rb +37 -0
  374. data/lib/chemicalml/convention/spectroscopy/constraints/peak_list_must_contain_peaks.rb +31 -0
  375. data/lib/chemicalml/convention/spectroscopy/constraints/peak_should_have_values.rb +34 -0
  376. data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_content.rb +31 -0
  377. data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_convention.rb +32 -0
  378. data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_format.rb +31 -0
  379. data/lib/chemicalml/convention/spectroscopy/constraints.rb +20 -0
  380. data/lib/chemicalml/convention/spectroscopy.rb +41 -0
  381. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_contain_at_least_one_unit.rb +29 -0
  382. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_have_namespace.rb +36 -0
  383. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_contain_definition.rb +28 -0
  384. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_id.rb +28 -0
  385. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_multiplier_or_constant_to_si.rb +34 -0
  386. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_parent_si.rb +32 -0
  387. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_symbol_and_unit_type.rb +4 -4
  388. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_title.rb +32 -0
  389. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_parent_si_should_resolve.rb +45 -0
  390. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_unit_type_should_resolve.rb +46 -0
  391. data/lib/chemicalml/convention/unit_dictionary/constraints.rb +19 -1
  392. data/lib/chemicalml/convention/unit_dictionary.rb +11 -2
  393. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_id_must_match_pattern.rb +31 -0
  394. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_contain_at_least_one_unit_type.rb +28 -0
  395. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_have_namespace.rb +35 -0
  396. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_contain_definition.rb +28 -0
  397. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +6 -6
  398. data/lib/chemicalml/convention/unit_type_dictionary/constraints.rb +9 -1
  399. data/lib/chemicalml/convention/unit_type_dictionary.rb +6 -2
  400. data/lib/chemicalml/convention/validation_report.rb +90 -0
  401. data/lib/chemicalml/convention/violation.rb +9 -3
  402. data/lib/chemicalml/convention.rb +49 -11
  403. data/lib/chemicalml/dictionary/entry.rb +6 -6
  404. data/lib/chemicalml/dictionary/enum.rb +1 -1
  405. data/lib/chemicalml/dictionary/link.rb +3 -3
  406. data/lib/chemicalml/dictionary/loader.rb +19 -19
  407. data/lib/chemicalml/dictionary/model.rb +5 -5
  408. data/lib/chemicalml/dictionary/registry.rb +9 -9
  409. data/lib/chemicalml/dictionary.rb +13 -9
  410. data/lib/chemicalml/logger.rb +47 -0
  411. data/lib/chemicalml/schema/definition.rb +2 -2
  412. data/lib/chemicalml/schema.rb +7 -7
  413. data/lib/chemicalml/version.rb +1 -1
  414. data/lib/chemicalml/versioned_parser.rb +28 -10
  415. data/lib/chemicalml.rb +79 -17
  416. data/lib/tasks/reference_fetch.rake +30 -31
  417. data/lib/tasks/scrape_fixtures.rake +23 -24
  418. metadata +235 -35
  419. data/lib/chemicalml/cml/child_mappings.rb +0 -168
  420. data/lib/chemicalml/cml/translator/value_translations.rb +0 -270
  421. data/lib/chemicalml/cml/translator.rb +0 -484
  422. data/lib/chemicalml/model/atom.rb +0 -64
  423. data/lib/chemicalml/model/atom_parity.rb +0 -21
  424. data/lib/chemicalml/model/bond.rb +0 -39
  425. data/lib/chemicalml/model/bond_stereo.rb +0 -29
  426. data/lib/chemicalml/model/cml_array.rb +0 -27
  427. data/lib/chemicalml/model/cml_module.rb +0 -45
  428. data/lib/chemicalml/model/document.rb +0 -29
  429. data/lib/chemicalml/model/formula.rb +0 -34
  430. data/lib/chemicalml/model/identifier.rb +0 -21
  431. data/lib/chemicalml/model/label.rb +0 -21
  432. data/lib/chemicalml/model/matrix.rb +0 -29
  433. data/lib/chemicalml/model/metadata.rb +0 -23
  434. data/lib/chemicalml/model/metadata_list.rb +0 -25
  435. data/lib/chemicalml/model/molecule.rb +0 -45
  436. data/lib/chemicalml/model/name.rb +0 -21
  437. data/lib/chemicalml/model/node.rb +0 -45
  438. data/lib/chemicalml/model/parameter.rb +0 -27
  439. data/lib/chemicalml/model/parameter_list.rb +0 -25
  440. data/lib/chemicalml/model/product.rb +0 -21
  441. data/lib/chemicalml/model/product_list.rb +0 -21
  442. data/lib/chemicalml/model/property.rb +0 -28
  443. data/lib/chemicalml/model/property_list.rb +0 -25
  444. data/lib/chemicalml/model/reactant.rb +0 -21
  445. data/lib/chemicalml/model/reactant_list.rb +0 -21
  446. data/lib/chemicalml/model/reaction.rb +0 -41
  447. data/lib/chemicalml/model/reaction_list.rb +0 -23
  448. data/lib/chemicalml/model/scalar.rb +0 -25
  449. data/lib/chemicalml/model/substance.rb +0 -25
  450. data/lib/chemicalml/model.rb +0 -40
@@ -5,18 +5,23 @@ module Chemicalml
5
5
  # Value object describing one constraint violation. Severity is
6
6
  # either `:error` (document is invalid under the convention) or
7
7
  # `:warning` (document is valid but problematic).
8
+ #
9
+ # `value` carries the offending value where natural (e.g. the
10
+ # duplicated atom id, the malformed unit symbol). Optional —
11
+ # constraints that flag a missing attribute leave `value` nil.
8
12
  class Violation
9
13
  SEVERITIES = %i[error warning].freeze
10
14
 
11
- attr_reader :path, :message, :severity, :constraint
15
+ attr_reader :path, :message, :severity, :constraint, :value
12
16
 
13
- def initialize(path:, message:, severity: :error, constraint: nil)
17
+ def initialize(path:, message:, severity: :error, constraint: nil, value: nil)
14
18
  raise ArgumentError, "unknown severity: #{severity.inspect}" unless SEVERITIES.include?(severity.to_sym)
15
19
 
16
20
  @path = path
17
21
  @message = message
18
22
  @severity = severity.to_sym
19
23
  @constraint = constraint
24
+ @value = value
20
25
  freeze
21
26
  end
22
27
 
@@ -29,7 +34,8 @@ module Chemicalml
29
34
  end
30
35
 
31
36
  def to_s
32
- "#{severity.upcase} #{path}: #{message}"
37
+ suffix = value.nil? ? '' : " (value=#{value.inspect})"
38
+ "#{severity.upcase} #{path}: #{message}#{suffix}"
33
39
  end
34
40
  end
35
41
  end
@@ -8,32 +8,70 @@ module Chemicalml
8
8
  # convention owns its constraint classes; the framework walks
9
9
  # whatever was registered.
10
10
  #
11
- # The five built-in conventions:
11
+ # The built-in conventions:
12
12
  #
13
13
  # molecular http://www.xml-cml.org/convention/molecular
14
14
  # compchem http://www.xml-cml.org/convention/compchem
15
15
  # dictionary http://www.xml-cml.org/convention/dictionary
16
16
  # unit-dictionary http://www.xml-cml.org/convention/unit-dictionary
17
17
  # unitType-dictionary http://www.xml-cml.org/convention/unitType-dictionary
18
+ # spectroscopy http://www.xml-cml.org/convention/spectroscopy
19
+ # cascade http://www.xml-cml.org/convention/cascade
20
+ # simpleUnit http://www.xml-cml.org/convention/simpleUnit
18
21
  module Convention
19
- autoload :Base, "chemicalml/convention/base"
20
- autoload :Compchem, "chemicalml/convention/compchem"
21
- autoload :Constraint, "chemicalml/convention/constraint"
22
- autoload :Dictionary, "chemicalml/convention/dictionary"
23
- autoload :Molecular, "chemicalml/convention/molecular"
24
- autoload :Registry, "chemicalml/convention/registry"
25
- autoload :UnitDictionary, "chemicalml/convention/unit_dictionary"
26
- autoload :UnitTypeDictionary, "chemicalml/convention/unit_type_dictionary"
27
- autoload :Violation, "chemicalml/convention/violation"
22
+ autoload :Base, 'chemicalml/convention/base'
23
+ autoload :Cascade, 'chemicalml/convention/cascade'
24
+ autoload :Compchem, 'chemicalml/convention/compchem'
25
+ autoload :Constraint, 'chemicalml/convention/constraint'
26
+ autoload :Coordinator, 'chemicalml/convention/coordinator'
27
+ autoload :Detection, 'chemicalml/convention/detection'
28
+ autoload :Dictionary, 'chemicalml/convention/dictionary'
29
+ autoload :Molecular, 'chemicalml/convention/molecular'
30
+ autoload :Registry, 'chemicalml/convention/registry'
31
+ autoload :SimpleUnit, 'chemicalml/convention/simple_unit'
32
+ autoload :Spectroscopy, 'chemicalml/convention/spectroscopy'
33
+ autoload :UnitDictionary, 'chemicalml/convention/unit_dictionary'
34
+ autoload :UnitTypeDictionary, 'chemicalml/convention/unit_type_dictionary'
35
+ autoload :ValidationReport, 'chemicalml/convention/validation_report'
36
+ autoload :Violation, 'chemicalml/convention/violation'
28
37
 
29
- CONVENTION_NAMESPACE = "http://www.xml-cml.org/convention/".freeze
38
+ CONVENTION_NAMESPACE = 'http://www.xml-cml.org/convention/'
30
39
 
40
+ # Look up a convention by QName (e.g. "convention:molecular").
41
+ # @param qname [String] the convention QName.
42
+ # @return [Module, nil] the convention module, or nil if unknown.
31
43
  def self.lookup(qname)
32
44
  Registry.lookup(qname)
33
45
  end
34
46
 
47
+ # Validate a document against a named convention. Returns the
48
+ # raw violation list.
49
+ #
50
+ # @param document [Lutaml::Model::Serializable] the CML document.
51
+ # @param qname [String] the convention QName (e.g. "convention:molecular").
52
+ # @return [Array<Chemicalml::Convention::Violation>] the violations.
53
+ # @raise [ArgumentError] if the qname is not registered.
35
54
  def self.validate(document, qname:)
36
55
  Registry.validate(document, qname: qname)
37
56
  end
57
+
58
+ # Validate and return a structured report (errors + warnings).
59
+ #
60
+ # @param document [Lutaml::Model::Serializable] the CML document.
61
+ # @param qname [String] the convention QName.
62
+ # @return [Chemicalml::Convention::ValidationReport] the report.
63
+ def self.validate_report(document, qname:)
64
+ Registry.validate_report(document, qname: qname)
65
+ end
66
+
67
+ # Auto-detect the convention from the document root's `convention`
68
+ # attribute and validate.
69
+ #
70
+ # @param document [Lutaml::Model::Serializable] the CML document.
71
+ # @return [Chemicalml::Convention::ValidationReport] the report.
72
+ # @raise [ArgumentError] if no convention is declared.
73
+ def self.detect_and_validate(document)
74
+ Registry.detect_and_validate(document)
75
+ end
38
76
  end
39
77
  end
@@ -6,7 +6,7 @@ module Chemicalml
6
6
  # The YAML shape mirrors the structure documented in
7
7
  # `TODO.cml-full/05-dictionary-layer.md`.
8
8
  class Entry
9
- ID_PATTERN = /\A[A-Za-z][A-Za-z0-9._-]*\z/.freeze
9
+ ID_PATTERN = /\A[A-Za-z][A-Za-z0-9._-]*\z/
10
10
 
11
11
  attr_reader :id, :term, :definition, :description,
12
12
  :data_type, :unit_type, :units,
@@ -30,7 +30,7 @@ module Chemicalml
30
30
  freeze
31
31
  end
32
32
 
33
- def to_h
33
+ def value_attributes
34
34
  h = {
35
35
  id: id,
36
36
  term: term,
@@ -40,19 +40,19 @@ module Chemicalml
40
40
  h[:data_type] = data_type if data_type
41
41
  h[:unit_type] = unit_type if unit_type
42
42
  h[:units] = units if units
43
- h[:enum] = enum.to_h if enum
44
- h[:links] = links.map(&:to_h) unless links.empty?
43
+ h[:enum] = enum.value_attributes if enum
44
+ h[:links] = links.map(&:value_attributes) unless links.empty?
45
45
  h[:source_code] = source_code if source_code
46
46
  h
47
47
  end
48
48
 
49
49
  def eql?(other)
50
- other.is_a?(Entry) && id == other.id && to_h == other.to_h
50
+ other.is_a?(Entry) && id == other.id && value_attributes == other.value_attributes
51
51
  end
52
52
  alias == eql?
53
53
 
54
54
  def hash
55
- [id, to_h].hash
55
+ [id, value_attributes].hash
56
56
  end
57
57
  end
58
58
  end
@@ -34,7 +34,7 @@ module Chemicalml
34
34
  values.include?(value)
35
35
  end
36
36
 
37
- def to_h
37
+ def value_attributes
38
38
  { kind: kind, values: values }
39
39
  end
40
40
 
@@ -15,17 +15,17 @@ module Chemicalml
15
15
  freeze
16
16
  end
17
17
 
18
- def to_h
18
+ def value_attributes
19
19
  { rel: rel, href: href, title: title }.compact
20
20
  end
21
21
 
22
22
  def eql?(other)
23
- other.is_a?(Link) && to_h == other.to_h
23
+ other.is_a?(Link) && value_attributes == other.value_attributes
24
24
  end
25
25
  alias == eql?
26
26
 
27
27
  def hash
28
- to_h.hash
28
+ value_attributes.hash
29
29
  end
30
30
  end
31
31
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "yaml"
3
+ require 'yaml'
4
4
 
5
5
  module Chemicalml
6
6
  module Dictionary
@@ -17,26 +17,26 @@ module Chemicalml
17
17
 
18
18
  def self.from_hash(hash)
19
19
  Model.new(
20
- namespace: hash.fetch("namespace"),
21
- prefix: hash.fetch("prefix"),
22
- title: hash.fetch("title"),
23
- description: hash["description"],
24
- entries: (hash["entries"] || []).map { |e| build_entry(e) }
20
+ namespace: hash.fetch('namespace'),
21
+ prefix: hash.fetch('prefix'),
22
+ title: hash.fetch('title'),
23
+ description: hash['description'],
24
+ entries: (hash['entries'] || []).map { |e| build_entry(e) }
25
25
  )
26
26
  end
27
27
 
28
28
  def self.build_entry(h)
29
29
  Entry.new(
30
- id: h.fetch("id"),
31
- term: h.fetch("term"),
32
- definition: h.fetch("definition"),
33
- description: h["description"],
34
- data_type: h["data_type"],
35
- unit_type: h["unit_type"],
36
- units: h["units"],
37
- enum: build_enum(h["enum"]),
38
- links: (h["links"] || []).map { |l| build_link(l) },
39
- source_code: h["source_code"]
30
+ id: h.fetch('id'),
31
+ term: h.fetch('term'),
32
+ definition: h.fetch('definition'),
33
+ description: h['description'],
34
+ data_type: h['data_type'],
35
+ unit_type: h['unit_type'],
36
+ units: h['units'],
37
+ enum: build_enum(h['enum']),
38
+ links: (h['links'] || []).map { |l| build_link(l) },
39
+ source_code: h['source_code']
40
40
  )
41
41
  end
42
42
  private_class_method :build_entry
@@ -45,14 +45,14 @@ module Chemicalml
45
45
  return nil unless h
46
46
 
47
47
  Enum.new(
48
- kind: h["kind"] || :open,
49
- values: h["values"] || []
48
+ kind: h['kind'] || :open,
49
+ values: h['values'] || []
50
50
  )
51
51
  end
52
52
  private_class_method :build_enum
53
53
 
54
54
  def self.build_link(h)
55
- Link.new(rel: h.fetch("rel"), href: h.fetch("href"), title: h["title"])
55
+ Link.new(rel: h.fetch('rel'), href: h.fetch('href'), title: h['title'])
56
56
  end
57
57
  private_class_method :build_link
58
58
  end
@@ -35,29 +35,29 @@ module Chemicalml
35
35
  entries.map(&:id)
36
36
  end
37
37
 
38
- def to_h
38
+ def value_attributes
39
39
  {
40
40
  namespace: namespace,
41
41
  prefix: prefix,
42
42
  title: title,
43
43
  description: description,
44
- entries: entries.map(&:to_h)
44
+ entries: entries.map(&:value_attributes)
45
45
  }
46
46
  end
47
47
 
48
48
  def eql?(other)
49
- other.is_a?(Model) && namespace == other.namespace && to_h == other.to_h
49
+ other.is_a?(Model) && namespace == other.namespace && value_attributes == other.value_attributes
50
50
  end
51
51
  alias == eql?
52
52
 
53
53
  def hash
54
- [namespace, to_h].hash
54
+ [namespace, value_attributes].hash
55
55
  end
56
56
 
57
57
  private
58
58
 
59
59
  def split_qname(qname)
60
- qname.to_s.split(":", 2)
60
+ qname.to_s.split(':', 2)
61
61
  end
62
62
  end
63
63
  end
@@ -13,7 +13,7 @@ module Chemicalml
13
13
  @mutex = Mutex.new
14
14
 
15
15
  def self.lookup(qname)
16
- prefix, id = qname.to_s.split(":", 2)
16
+ prefix, id = qname.to_s.split(':', 2)
17
17
  return nil unless id
18
18
 
19
19
  dict = load_by_prefix(prefix)
@@ -39,7 +39,7 @@ module Chemicalml
39
39
 
40
40
  def self.load_by_prefix(prefix)
41
41
  manifest.each do |name, info|
42
- return load_builtin(name) if info["prefix"] == prefix
42
+ return load_builtin(name) if info['prefix'] == prefix
43
43
  end
44
44
  nil
45
45
  end
@@ -49,27 +49,27 @@ module Chemicalml
49
49
  end
50
50
 
51
51
  def self.builtin_names
52
- Dir.glob(File.join(BUILTIN_DIR, "*.yaml"))
53
- .reject { |p| File.basename(p).start_with?("_") }
54
- .map { |p| File.basename(p, ".yaml").to_sym }
52
+ Dir.glob(File.join(BUILTIN_DIR, '*.yaml'))
53
+ .reject { |p| File.basename(p).start_with?('_') }
54
+ .map { |p| File.basename(p, '.yaml').to_sym }
55
55
  .sort
56
56
  end
57
57
 
58
58
  def self.manifest
59
59
  @manifest ||= begin
60
- path = File.join(BUILTIN_DIR, "_index.yaml")
60
+ path = File.join(BUILTIN_DIR, '_index.yaml')
61
61
  if File.exist?(path)
62
62
  YAML.load_file(path) || {}
63
63
  else
64
- builtin_names.each_with_object({}) do |name, h|
65
- h[name.to_s] = { "prefix" => name.to_s }
64
+ builtin_names.to_h do |name|
65
+ [name.to_s, { 'prefix' => name.to_s }]
66
66
  end
67
67
  end
68
68
  end
69
69
  end
70
70
  private_class_method :manifest
71
71
 
72
- require "yaml"
72
+ require 'yaml'
73
73
  end
74
74
  end
75
75
  end
@@ -8,17 +8,21 @@ module Chemicalml
8
8
  # Built-in dictionaries ship as YAML under `data/dictionaries/` and
9
9
  # are loaded into `Chemicalml::Dictionary::Registry` lazily.
10
10
  module Dictionary
11
- autoload :Entry, "chemicalml/dictionary/entry"
12
- autoload :Enum, "chemicalml/dictionary/enum"
13
- autoload :Link, "chemicalml/dictionary/link"
14
- autoload :Loader, "chemicalml/dictionary/loader"
15
- autoload :Model, "chemicalml/dictionary/model"
16
- autoload :Registry, "chemicalml/dictionary/registry"
11
+ autoload :Entry, 'chemicalml/dictionary/entry'
12
+ autoload :Enum, 'chemicalml/dictionary/enum'
13
+ autoload :Link, 'chemicalml/dictionary/link'
14
+ autoload :Loader, 'chemicalml/dictionary/loader'
15
+ autoload :Model, 'chemicalml/dictionary/model'
16
+ autoload :Registry, 'chemicalml/dictionary/registry'
17
17
 
18
- BUILTIN_DIR = File.expand_path("../../data/dictionaries", __dir__).freeze
18
+ BUILTIN_DIR = File.expand_path('../../data/dictionaries', __dir__).freeze
19
19
 
20
- # Convenience: load a built-in dictionary by short name
21
- # (e.g. `:compchem`). Returns a `Chemicalml::Dictionary::Model`.
20
+ # Convenience: load a built-in dictionary by short name.
21
+ #
22
+ # @param name [Symbol, String] the dictionary short name (YAML
23
+ # filename stem, e.g. `:compchem`, `:cml`).
24
+ # @return [Chemicalml::Dictionary::Model] the loaded dictionary.
25
+ # @raise [KeyError] if `name` is not a built-in dictionary.
22
26
  def self.load(name)
23
27
  Registry.load_builtin(name)
24
28
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Chemicalml
6
+ # Logger used across the CLI and API. Wraps Ruby's ::Logger and can
7
+ # bridge to Thor's `say` / `say_error` when running under a Thor
8
+ # dispatcher — that gives coloured output on the terminal while
9
+ # plain `Logger.new($stderr)` works for library callers.
10
+ #
11
+ # Severity routing under Thor:
12
+ # debug → suppressed (set level manually if needed)
13
+ # info → say (green-ish, $stdout)
14
+ # warn → say_error with :yellow ($stderr)
15
+ # error → say_error with :red ($stderr)
16
+ # fatal → say_error with :red ($stderr)
17
+ class Logger < ::Logger
18
+ attr_reader :thor_shell
19
+
20
+ # Bridge to a Thor shell instance (self inside a Thor command).
21
+ # When set, info/warn/error route through Thor for coloured output.
22
+ def thor_shell=(shell)
23
+ @thor_shell = shell
24
+ end
25
+
26
+ def add(severity, message = nil, progname = nil)
27
+ return super unless thor_shell
28
+ return true if severity < level
29
+
30
+ msg = message || progname
31
+ case severity
32
+ when ERROR, FATAL
33
+ thor_shell.say_error(msg.to_s, :red)
34
+ when WARN
35
+ thor_shell.say_error(msg.to_s, :yellow)
36
+ else
37
+ thor_shell.say(msg.to_s)
38
+ end
39
+ end
40
+
41
+ # Convenience: create a default logger that writes to $stderr at
42
+ # INFO level. Used when no logger is explicitly provided.
43
+ def self.default
44
+ new($stderr).tap { |l| l.level = INFO }
45
+ end
46
+ end
47
+ end
@@ -19,7 +19,7 @@ module Chemicalml
19
19
  end
20
20
 
21
21
  def wire_namespace_constant
22
- ruby_namespace.split("::").reduce(Object) { |ns, name| ns.const_get(name) }
22
+ ruby_namespace.split('::').reduce(Object) { |ns, name| ns.const_get(name) }
23
23
  end
24
24
 
25
25
  def eql?(other)
@@ -34,7 +34,7 @@ module Chemicalml
34
34
  private
35
35
 
36
36
  def project_root
37
- File.expand_path("../../..", __dir__)
37
+ File.expand_path('../../..', __dir__)
38
38
  end
39
39
  end
40
40
  end
@@ -9,10 +9,10 @@ module Chemicalml
9
9
  # `reference-docs/schemas/`. They are never modified or regenerated
10
10
  # from code.
11
11
  module Schema
12
- autoload :Definition, "chemicalml/schema/definition"
13
- autoload :Registry, "chemicalml/schema/registry"
12
+ autoload :Definition, 'chemicalml/schema/definition'
13
+ autoload :Registry, 'chemicalml/schema/registry'
14
14
 
15
- CML_XML_NAMESPACE = "http://www.xml-cml.org/schema"
15
+ CML_XML_NAMESPACE = 'http://www.xml-cml.org/schema'
16
16
 
17
17
  # Built-in versions registered at load time. Adding a new CML schema
18
18
  # version = appending an entry here and creating the matching
@@ -20,15 +20,15 @@ module Chemicalml
20
20
  BUILTIN = {
21
21
  schema24: Definition.new(
22
22
  version: :schema24,
23
- xsd_path: "reference-docs/schemas/schema24/schema.xsd",
23
+ xsd_path: 'reference-docs/schemas/schema24/schema.xsd',
24
24
  xml_namespace: CML_XML_NAMESPACE,
25
- ruby_namespace: "Chemicalml::Cml::Schema24"
25
+ ruby_namespace: 'Chemicalml::Cml::Schema24'
26
26
  ),
27
27
  schema3: Definition.new(
28
28
  version: :schema3,
29
- xsd_path: "reference-docs/schemas/schema3/schema.xsd",
29
+ xsd_path: 'reference-docs/schemas/schema3/schema.xsd',
30
30
  xml_namespace: CML_XML_NAMESPACE,
31
- ruby_namespace: "Chemicalml::Cml::Schema3"
31
+ ruby_namespace: 'Chemicalml::Cml::Schema3'
32
32
  )
33
33
  }.freeze
34
34
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chemicalml
4
- VERSION = "0.2.0"
4
+ VERSION = '0.3.0'
5
5
  end
@@ -9,19 +9,37 @@ module Chemicalml
9
9
  # (Document), `<module>` (compchem Module), `<dictionary>`,
10
10
  # `<unitList>`, `<unitTypeList>`, and the legacy standalone roots
11
11
  # `<molecule>`, `<reaction>`, `<reactionList>`.
12
+ #
13
+ # ---
14
+ #
15
+ # XML processing boundary (read me):
16
+ #
17
+ # The gem uses `lutaml-model` for ALL XML parsing and serialization
18
+ # — 242 wire classes extend `Lutaml::Model::Serializable`, and no
19
+ # `lib/` file defines `to_xml`/`from_xml`/`to_h`/`from_h` on a
20
+ # model class. Zero Nokogiri/REXML references in `lib/`.
21
+ #
22
+ # This file has TWO pre-processing helpers — `root_element_of` and
23
+ # `inject_namespace` — that operate on the XML *string* before
24
+ # `Lutaml::Model::Serializable.from_xml` is called. They are NOT
25
+ # serialization: they don't construct XML nodes, don't traverse
26
+ # trees, don't map attributes to model fields. They are input
27
+ # normalization so callers can pass namespace-less XML or rely on
28
+ # the parser to dispatch by root element name. The actual parse
29
+ # happens on the `const_get(class_name).from_xml(...)` call below.
12
30
  module VersionedParser
13
31
  # Maps root element name → constant name on the schema module.
14
32
  # Adding a new root type = adding one entry here. OCP — no
15
33
  # existing code changes.
16
34
  KNOWN_ROOTS = {
17
- "cml" => :Document,
18
- "molecule" => :Molecule,
19
- "reaction" => :Reaction,
20
- "reactionList" => :ReactionList,
21
- "module" => :Module,
22
- "dictionary" => :Dictionary,
23
- "unitList" => :UnitList,
24
- "unitTypeList" => :UnitTypeList,
35
+ 'cml' => :Document,
36
+ 'molecule' => :Molecule,
37
+ 'reaction' => :Reaction,
38
+ 'reactionList' => :ReactionList,
39
+ 'module' => :Module,
40
+ 'dictionary' => :Dictionary,
41
+ 'unitList' => :UnitList,
42
+ 'unitTypeList' => :UnitTypeList
25
43
  }.freeze
26
44
 
27
45
  def parse(xml, namespace_exist: true)
@@ -39,7 +57,7 @@ module Chemicalml
39
57
  unless const_defined?(class_name, false)
40
58
  raise ArgumentError,
41
59
  "#{name} does not define #{class_name} " \
42
- "(not all root elements exist in every schema version)"
60
+ '(not all root elements exist in every schema version)'
43
61
  end
44
62
 
45
63
  const_get(class_name).from_xml(
@@ -65,7 +83,7 @@ module Chemicalml
65
83
  match = xml.match(/<([a-zA-Z][\w.-]*)(?::[a-zA-Z][\w.-]*)?/)
66
84
  return match[1] if match
67
85
 
68
- raise ArgumentError, "could not detect root element in XML"
86
+ raise ArgumentError, 'could not detect root element in XML'
69
87
  end
70
88
 
71
89
  def xml_input(xml, namespace_exist, root)