openphar 0.1.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 (108) hide show
  1. checksums.yaml +7 -0
  2. data/README.adoc +221 -0
  3. data/lib/openphar/cli/main.rb +137 -0
  4. data/lib/openphar/cli.rb +11 -0
  5. data/lib/openphar/core/slug_generator.rb +107 -0
  6. data/lib/openphar/core.rb +11 -0
  7. data/lib/openphar/errors/configuration_error.rb +8 -0
  8. data/lib/openphar/errors/monograph_not_found_error.rb +15 -0
  9. data/lib/openphar/errors/parse_error.rb +18 -0
  10. data/lib/openphar/errors/unknown_format_error.rb +8 -0
  11. data/lib/openphar/errors/unknown_publisher_error.rb +8 -0
  12. data/lib/openphar/errors/unknown_type_error.rb +8 -0
  13. data/lib/openphar/errors/validation_error.rb +15 -0
  14. data/lib/openphar/errors.rb +17 -0
  15. data/lib/openphar/exporters/coverage_validator.rb +265 -0
  16. data/lib/openphar/exporters/neo4j/model_registry.rb +130 -0
  17. data/lib/openphar/exporters/neo4j/node_builder.rb +84 -0
  18. data/lib/openphar/exporters/neo4j/property_mapper.rb +154 -0
  19. data/lib/openphar/exporters/neo4j/relationship_builder.rb +87 -0
  20. data/lib/openphar/exporters/neo4j.rb +16 -0
  21. data/lib/openphar/exporters/neo4j_exporter.rb +199 -0
  22. data/lib/openphar/exporters.rb +15 -0
  23. data/lib/openphar/linkers/chp/cross_edition_linker.rb +101 -0
  24. data/lib/openphar/linkers/chp.rb +11 -0
  25. data/lib/openphar/linkers/cross_publisher_linker.rb +295 -0
  26. data/lib/openphar/linkers/herbapedia_linker.rb +125 -0
  27. data/lib/openphar/linkers.rb +13 -0
  28. data/lib/openphar/migrators/chp/classifier.rb +86 -0
  29. data/lib/openphar/migrators/chp.rb +15 -0
  30. data/lib/openphar/migrators/chp_migrator.rb +130 -0
  31. data/lib/openphar/migrators/jp_migrator.rb +345 -0
  32. data/lib/openphar/migrators/phint_migrator.rb +426 -0
  33. data/lib/openphar/migrators.rb +15 -0
  34. data/lib/openphar/models/ahp.rb +25 -0
  35. data/lib/openphar/models/amino_acid_monograph.rb +28 -0
  36. data/lib/openphar/models/api.rb +29 -0
  37. data/lib/openphar/models/assay_specification.rb +19 -0
  38. data/lib/openphar/models/base_entity.rb +221 -0
  39. data/lib/openphar/models/biological_substance_monograph.rb +31 -0
  40. data/lib/openphar/models/chemical_drug_monograph.rb +39 -0
  41. data/lib/openphar/models/chp/biologic.rb +28 -0
  42. data/lib/openphar/models/chp/chemical_preparation.rb +28 -0
  43. data/lib/openphar/models/chp/chemical_substance.rb +28 -0
  44. data/lib/openphar/models/chp/general_chapter.rb +30 -0
  45. data/lib/openphar/models/chp/monograph.rb +116 -0
  46. data/lib/openphar/models/chp/section.rb +37 -0
  47. data/lib/openphar/models/chp/tcm_crude_drug.rb +28 -0
  48. data/lib/openphar/models/chp/tcm_extract.rb +29 -0
  49. data/lib/openphar/models/chp/tcm_formulation.rb +28 -0
  50. data/lib/openphar/models/chp.rb +33 -0
  51. data/lib/openphar/models/crude_drug_monograph.rb +31 -0
  52. data/lib/openphar/models/edition.rb +41 -0
  53. data/lib/openphar/models/formulation_monograph.rb +31 -0
  54. data/lib/openphar/models/hkcmms.rb +26 -0
  55. data/lib/openphar/models/identification_specification.rb +19 -0
  56. data/lib/openphar/models/jp/kampo_formula.rb +94 -0
  57. data/lib/openphar/models/jp.rb +21 -0
  58. data/lib/openphar/models/limit.rb +54 -0
  59. data/lib/openphar/models/mineral_substance_monograph.rb +28 -0
  60. data/lib/openphar/models/monograph.rb +58 -0
  61. data/lib/openphar/models/ph_int/buffer_solution.rb +38 -0
  62. data/lib/openphar/models/ph_int/dosage_form_monograph.rb +43 -0
  63. data/lib/openphar/models/ph_int/radiopharmaceutical_monograph.rb +52 -0
  64. data/lib/openphar/models/ph_int/reagent.rb +50 -0
  65. data/lib/openphar/models/ph_int/reference_substance.rb +50 -0
  66. data/lib/openphar/models/ph_int/test_method.rb +50 -0
  67. data/lib/openphar/models/ph_int/test_solution.rb +39 -0
  68. data/lib/openphar/models/ph_int/volumetric_solution.rb +38 -0
  69. data/lib/openphar/models/ph_int.rb +37 -0
  70. data/lib/openphar/models/physical_specification.rb +17 -0
  71. data/lib/openphar/models/publisher.rb +98 -0
  72. data/lib/openphar/models/purity_specification.rb +16 -0
  73. data/lib/openphar/models/supplement.rb +31 -0
  74. data/lib/openphar/models/test_specification.rb +29 -0
  75. data/lib/openphar/models/thp.rb +24 -0
  76. data/lib/openphar/models/vitamin_monograph.rb +28 -0
  77. data/lib/openphar/models.rb +58 -0
  78. data/lib/openphar/monograph_merger.rb +374 -0
  79. data/lib/openphar/parsers/base_monograph_parser.rb +108 -0
  80. data/lib/openphar/parsers/jp_html_parser.rb +92 -0
  81. data/lib/openphar/parsers/jp_html_parser_base.rb +113 -0
  82. data/lib/openphar/parsers/jp_ja_html_parser.rb +220 -0
  83. data/lib/openphar/parsers/phint_json_parser.rb +332 -0
  84. data/lib/openphar/parsers.rb +21 -0
  85. data/lib/openphar/registry/publisher_registry.rb +46 -0
  86. data/lib/openphar/registry/type_registry.rb +147 -0
  87. data/lib/openphar/registry.rb +24 -0
  88. data/lib/openphar/repositories/monograph_repository.rb +350 -0
  89. data/lib/openphar/repositories.rb +11 -0
  90. data/lib/openphar/transformers/jsonld_transformer.rb +106 -0
  91. data/lib/openphar/transformers.rb +11 -0
  92. data/lib/openphar/version.rb +5 -0
  93. data/lib/openphar.rb +119 -0
  94. data/ontology/bibliographic/edition.ttl +267 -0
  95. data/ontology/context/chp.jsonld +69 -0
  96. data/ontology/context/crude-drugs.jsonld +56 -0
  97. data/ontology/context/pharmacopoeia.jsonld +631 -0
  98. data/ontology/core/identification.ttl +456 -0
  99. data/ontology/core/pharmacopoeia.ttl +3427 -0
  100. data/ontology/core/substance-form.ttl +302 -0
  101. data/ontology/core/unit.ttl +493 -0
  102. data/ontology/publisher/chp/extensions.ttl +186 -0
  103. data/ontology/publisher/phint/extensions.ttl +327 -0
  104. data/ontology/quality/test-method.ttl +610 -0
  105. data/shapes/chp/monograph.ttl +153 -0
  106. data/shapes/edition-shapes.ttl +230 -0
  107. data/shapes/monograph-shapes.ttl +1324 -0
  108. metadata +319 -0
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ module PhInt
6
+ # Test Method
7
+ #
8
+ # Represents analytical test methods from Ph.Int. Section 7.
9
+ #
10
+ # Test methods define procedures for quality control testing
11
+ # of pharmaceutical substances and products.
12
+ #
13
+ # @example
14
+ # method = PhInt::TestMethod.new(
15
+ # id: 'phint-method-hplc',
16
+ # method_id: '2.2.29',
17
+ # method_type: 'Chromatography',
18
+ # description: { 'en' => 'Liquid chromatography...' }
19
+ # )
20
+ class TestMethod < BaseEntity
21
+ attribute :method_id, :string
22
+ attribute :pref_label, :hash, default: {}
23
+ attribute :method_type, :string
24
+ attribute :description, :hash, default: {}
25
+ attribute :publisher, :string
26
+ attribute :belongs_to_edition, :string
27
+
28
+ json do
29
+ map '@id', to: :id
30
+ map 'methodId', to: :method_id
31
+ map 'prefLabel', to: :pref_label
32
+ map 'methodType', to: :method_type
33
+ map 'description', to: :description
34
+ map 'publisher', to: :publisher
35
+ map 'belongsToEdition', to: :belongs_to_edition
36
+ end
37
+
38
+ class << self
39
+ def neo4j_labels
40
+ ['TestMethod']
41
+ end
42
+
43
+ def jsonld_type
44
+ 'TestMethod'
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ module PhInt
6
+ # Test Solution
7
+ #
8
+ # A solution used in pharmacopoeial tests.
9
+ # Test solutions have a specific concentration and may have
10
+ # specific storage requirements.
11
+ #
12
+ # @example
13
+ # solution = PhInt::TestSolution.new(
14
+ # id: 'phint-ts-ferric-chloride',
15
+ # concentration: '5% w/v',
16
+ # storage_conditions: { 'temperature' => '2-8°C' }
17
+ # )
18
+ class TestSolution < Reagent
19
+ attribute :concentration, :string
20
+ attribute :storage_conditions, :hash, default: {}
21
+
22
+ json do
23
+ map 'concentration', to: :concentration
24
+ map 'storageConditions', to: :storage_conditions
25
+ end
26
+
27
+ class << self
28
+ def neo4j_labels
29
+ %w[Reagent TestSolution]
30
+ end
31
+
32
+ def jsonld_type
33
+ 'TestSolution'
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ module PhInt
6
+ # Volumetric Solution
7
+ #
8
+ # A solution of known concentration used for titrations.
9
+ # Volumetric solutions must be standardized against a primary standard.
10
+ #
11
+ # @example
12
+ # solution = PhInt::VolumetricSolution.new(
13
+ # id: 'phint-vs-hcl-01m',
14
+ # molarity: '0.1 mol/L',
15
+ # standardization: { 'primaryStandard' => 'Sodium carbonate' }
16
+ # )
17
+ class VolumetricSolution < Reagent
18
+ attribute :molarity, :string
19
+ attribute :standardization, :hash, default: {}
20
+
21
+ json do
22
+ map 'molarity', to: :molarity
23
+ map 'standardization', to: :standardization
24
+ end
25
+
26
+ class << self
27
+ def neo4j_labels
28
+ %w[Reagent VolumetricSolution]
29
+ end
30
+
31
+ def jsonld_type
32
+ 'VolumetricSolution'
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # International Pharmacopoeia (Ph.Int.) specific models.
6
+ #
7
+ # Contains models unique to the WHO International Pharmacopoeia:
8
+ # - Radiopharmaceuticals (radioactive drugs)
9
+ # - Dosage form monographs
10
+ # - Test methods and reagents
11
+ # - Reference substances
12
+ #
13
+ # @example
14
+ # # Access Ph.Int. models
15
+ # Openphar::Models::PhInt::RadiopharmaceuticalMonograph
16
+ # Openphar::Models::PhInt::TestMethod
17
+ #
18
+ # @see https://www.who.int/teams/health-product-and-policy-standards/inn-and-pharmacopoeia
19
+ module PhInt
20
+ # Monograph types
21
+ autoload :RadiopharmaceuticalMonograph,
22
+ 'openphar/models/ph_int/radiopharmaceutical_monograph'
23
+ autoload :DosageFormMonograph,
24
+ 'openphar/models/ph_int/dosage_form_monograph'
25
+
26
+ # Test methods and reagents
27
+ autoload :TestMethod, 'openphar/models/ph_int/test_method'
28
+ autoload :Reagent, 'openphar/models/ph_int/reagent'
29
+ autoload :TestSolution, 'openphar/models/ph_int/test_solution'
30
+ autoload :VolumetricSolution, 'openphar/models/ph_int/volumetric_solution'
31
+ autoload :BufferSolution, 'openphar/models/ph_int/buffer_solution'
32
+
33
+ # Reference substances
34
+ autoload :ReferenceSubstance, 'openphar/models/ph_int/reference_substance'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Represents a physical specification
6
+ #
7
+ # Physical specifications define limits for physical properties
8
+ # such as melting point, optical rotation, density, etc.
9
+ class PhysicalSpecification < TestSpecification
10
+ attribute :physical_property, :hash, default: {}
11
+
12
+ json do
13
+ map 'physicalProperty', to: :physical_property
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Represents a pharmacopoeia publisher
6
+ class Publisher < Lutaml::Model::Serializable
7
+ attribute :id, :string
8
+ attribute :code, :string
9
+ attribute :name, :hash, default: {}
10
+ attribute :country, :string
11
+ attribute :url, :string
12
+
13
+ # Publisher registry
14
+ PUBLISHERS = {
15
+ 'JP' => {
16
+ code: 'JP',
17
+ name: { 'en' => 'Japanese Pharmacopoeia', 'ja' => '日本薬局方' },
18
+ country: 'JP',
19
+ url: 'https://www.mhlw.go.jp/topics/bukyoku/iyaku/yakkyoku/'
20
+ },
21
+ 'PhInt' => {
22
+ code: 'PhInt',
23
+ name: { 'en' => 'International Pharmacopoeia', 'fr' => 'Pharmacopée Internationale' },
24
+ country: 'INT',
25
+ url: 'https://www.who.int/teams/health-product-and-policy-standards/inn-and-pharmacopoeia'
26
+ },
27
+ 'API' => {
28
+ code: 'API',
29
+ name: { 'en' => 'Ayurvedic Pharmacopoeia of India' },
30
+ country: 'IN',
31
+ url: 'https://main.ayush.gov.in/'
32
+ },
33
+ 'HKCMMS' => {
34
+ code: 'HKCMMS',
35
+ name: { 'en' => 'Hong Kong Chinese Materia Medica Standards', 'zh-Hant' => '香港中藥材標準' },
36
+ country: 'HK',
37
+ url: 'https://www.cmms.org.hk/'
38
+ },
39
+ 'THP' => {
40
+ code: 'THP',
41
+ name: { 'en' => 'Thai Herbal Pharmacopoeia', 'th' => 'ตำรายาจารีกสมุนไพร' },
42
+ country: 'TH',
43
+ url: 'https://www.fda.moph.go.th/'
44
+ },
45
+ 'AHP' => {
46
+ code: 'AHP',
47
+ name: { 'en' => 'American Herbal Pharmacopoeia' },
48
+ country: 'US',
49
+ url: 'https://www.herbal-ahp.org/'
50
+ },
51
+ 'WHO' => {
52
+ code: 'WHO',
53
+ name: { 'en' => 'WHO Monographs on Selected Medicinal Plants' },
54
+ country: 'INT',
55
+ url: 'https://www.who.int/'
56
+ }
57
+ }.freeze
58
+
59
+ json do
60
+ map '@id', to: :id
61
+ map 'code', to: :code
62
+ map 'name', to: :name
63
+ map 'country', to: :country
64
+ map 'url', to: :url
65
+ end
66
+
67
+ class << self
68
+ # Find a publisher by code
69
+ def find(code)
70
+ return nil unless PUBLISHERS.key?(code)
71
+
72
+ data = PUBLISHERS[code]
73
+ new(
74
+ id: code,
75
+ code: data[:code],
76
+ name: data[:name],
77
+ country: data[:country],
78
+ url: data[:url]
79
+ )
80
+ end
81
+
82
+ # Returns all publishers
83
+ def all
84
+ PUBLISHERS.keys.map { |code| find(code) }
85
+ end
86
+
87
+ # Returns the IRI for a publisher
88
+ def iri(code)
89
+ "#{Openphar.base_iri}/ontology/core/#{code}"
90
+ end
91
+ end
92
+
93
+ def iri
94
+ self.class.iri(code)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Represents a purity specification
6
+ #
7
+ # Purity specifications define limits for impurities in a substance.
8
+ class PuritySpecification < TestSpecification
9
+ attribute :impurity_type, :hash, default: {}
10
+
11
+ json do
12
+ map 'impurityType', to: :impurity_type
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Represents a supplement to a pharmacopoeia edition
6
+ #
7
+ # Supplements are updates issued between main editions,
8
+ # containing additions, deletions, and revisions.
9
+ class Supplement < Lutaml::Model::Serializable
10
+ attribute :id, :string
11
+ attribute :supplement_number, :string
12
+ attribute :supplement_to, :string
13
+ attribute :publication_date, :date
14
+ attribute :effective_date, :date
15
+ attribute :pref_label, :hash, default: {}
16
+
17
+ json do
18
+ map 'id', to: :id
19
+ map 'supplementNumber', to: :supplement_number
20
+ map 'supplementTo', to: :supplement_to
21
+ map 'supplementPublicationDate', to: :publication_date
22
+ map 'supplementEffectiveDate', to: :effective_date
23
+ map 'prefLabel', to: :pref_label
24
+ end
25
+
26
+ def iri
27
+ "#{Openphar.base_iri}/data/edition/#{id}"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Represents a test specification within a monograph
6
+ #
7
+ # Base class for all test specification types. Each test specification
8
+ # defines acceptance criteria for a specific quality test.
9
+ class TestSpecification < Lutaml::Model::Serializable
10
+ attribute :id, :string
11
+ attribute :test_name, :hash, default: {}
12
+ attribute :test_type, :string
13
+ attribute :harmonized_method, :string
14
+ attribute :publisher_method, :string
15
+ attribute :test_conditions, :hash, default: {}
16
+ attribute :limit, Limit
17
+
18
+ json do
19
+ map '@id', to: :id
20
+ map 'testName', to: :test_name
21
+ map 'testType', to: :test_type
22
+ map 'harmonizedMethod', to: :harmonized_method
23
+ map 'publisherMethod', to: :publisher_method
24
+ map 'testConditions', to: :test_conditions
25
+ map 'limit', to: :limit
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Thai Herbal Pharmacopoeia (THP) specific models.
6
+ #
7
+ # Contains models unique to the Thai Herbal Pharmacopoeia:
8
+ # - Thai traditional medicine monographs
9
+ # - Bilingual (Thai/English) content
10
+ # - Cannabis monographs (legal in Thailand)
11
+ #
12
+ # @example
13
+ # # Access THP models
14
+ # Openphar::Models::THP::ThaiHerbalMonograph
15
+ #
16
+ # @see http://www.fda.moph.go.th/
17
+ module THP
18
+ # Placeholder for THP-specific models
19
+ # Will include:
20
+ # - ThaiHerbalMonograph
21
+ # - CannabisMonograph (THP-specific)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Represents a vitamin monograph
6
+ #
7
+ # Vitamins are essential organic compounds required in small amounts.
8
+ class VitaminMonograph < ChemicalDrugMonograph
9
+ attribute :vitamin_type, :string
10
+ attribute :biological_activity, :string
11
+
12
+ json do
13
+ map 'vitaminType', to: :vitamin_type
14
+ map 'biologicalActivity', to: :biological_activity
15
+ end
16
+
17
+ class << self
18
+ def neo4j_labels
19
+ %w[Monograph ChemicalDrug Vitamin]
20
+ end
21
+
22
+ def jsonld_type
23
+ 'VitaminMonograph'
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Openphar
4
+ module Models
5
+ # Data models for pharmacopoeia entities.
6
+ #
7
+ # All models inherit from BaseEntity and define their attributes,
8
+ # JSON mappings, and serialization methods.
9
+ #
10
+ # == Namespace Structure
11
+ #
12
+ # Core models are defined directly in Openphar::Models:
13
+ # - Monograph and its subclasses (CrudeDrugMonograph, ChemicalDrugMonograph, etc.)
14
+ # - Limit, TestSpecification and subclasses
15
+ # - Edition, Supplement, Publisher
16
+ #
17
+ # Publisher-specific models are in sub-modules:
18
+ # - Openphar::Models::PhInt (International Pharmacopoeia)
19
+ # - Openphar::Models::JP (Japan Pharmacopoeia)
20
+
21
+ # Base class with common serialization
22
+ autoload :BaseEntity, 'openphar/models/base_entity'
23
+
24
+ # Quantitative limits
25
+ autoload :Limit, 'openphar/models/limit'
26
+
27
+ # Test specifications (one class per file)
28
+ autoload :TestSpecification, 'openphar/models/test_specification'
29
+ autoload :AssaySpecification, 'openphar/models/assay_specification'
30
+ autoload :PuritySpecification, 'openphar/models/purity_specification'
31
+ autoload :PhysicalSpecification, 'openphar/models/physical_specification'
32
+ autoload :IdentificationSpecification, 'openphar/models/identification_specification'
33
+
34
+ # Bibliographic entities (one class per file)
35
+ autoload :Edition, 'openphar/models/edition'
36
+ autoload :Supplement, 'openphar/models/supplement'
37
+ autoload :Publisher, 'openphar/models/publisher'
38
+
39
+ # Monograph types (one class per file)
40
+ autoload :Monograph, 'openphar/models/monograph'
41
+ autoload :CrudeDrugMonograph, 'openphar/models/crude_drug_monograph'
42
+ autoload :ChemicalDrugMonograph, 'openphar/models/chemical_drug_monograph'
43
+ autoload :FormulationMonograph, 'openphar/models/formulation_monograph'
44
+ autoload :VitaminMonograph, 'openphar/models/vitamin_monograph'
45
+ autoload :AminoAcidMonograph, 'openphar/models/amino_acid_monograph'
46
+ autoload :MineralSubstanceMonograph, 'openphar/models/mineral_substance_monograph'
47
+ autoload :BiologicalSubstanceMonograph, 'openphar/models/biological_substance_monograph'
48
+
49
+ # Publisher-specific model modules
50
+ autoload :PhInt, 'openphar/models/ph_int'
51
+ autoload :JP, 'openphar/models/jp'
52
+ autoload :Chp, 'openphar/models/chp'
53
+ autoload :AHP, 'openphar/models/ahp'
54
+ autoload :API, 'openphar/models/api'
55
+ autoload :HKCMMS, 'openphar/models/hkcmms'
56
+ autoload :THP, 'openphar/models/thp'
57
+ end
58
+ end