glossarist 2.6.6 → 2.6.7

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +90 -29
  3. data/glossarist.gemspec +2 -0
  4. data/lib/glossarist/citation.rb +26 -123
  5. data/lib/glossarist/cli/compare_command.rb +106 -0
  6. data/lib/glossarist/cli/export_command.rb +11 -14
  7. data/lib/glossarist/cli/validate_command.rb +111 -20
  8. data/lib/glossarist/cli.rb +18 -0
  9. data/lib/glossarist/collections/bibliography_collection.rb +4 -2
  10. data/lib/glossarist/collections/localization_collection.rb +2 -0
  11. data/lib/glossarist/comparison_result.rb +35 -0
  12. data/lib/glossarist/concept_collector.rb +44 -0
  13. data/lib/glossarist/concept_comparator.rb +72 -0
  14. data/lib/glossarist/concept_data.rb +16 -0
  15. data/lib/glossarist/concept_diff.rb +15 -0
  16. data/lib/glossarist/concept_document.rb +11 -0
  17. data/lib/glossarist/concept_manager.rb +19 -5
  18. data/lib/glossarist/concept_ref.rb +13 -0
  19. data/lib/glossarist/concept_validator.rb +6 -1
  20. data/lib/glossarist/context_configuration.rb +90 -0
  21. data/lib/glossarist/dataset_validator.rb +8 -4
  22. data/lib/glossarist/designation/prefix.rb +17 -0
  23. data/lib/glossarist/designation/suffix.rb +17 -0
  24. data/lib/glossarist/gcr_metadata.rb +7 -14
  25. data/lib/glossarist/gcr_package.rb +35 -23
  26. data/lib/glossarist/gcr_validator.rb +38 -17
  27. data/lib/glossarist/localized_concept.rb +8 -0
  28. data/lib/glossarist/managed_concept.rb +39 -6
  29. data/lib/glossarist/managed_concept_data.rb +2 -1
  30. data/lib/glossarist/rdf/ext/jsonld_transform_ext.rb +208 -0
  31. data/lib/glossarist/rdf/ext/mapping_ext.rb +37 -0
  32. data/lib/glossarist/rdf/ext/mapping_rule_ext.rb +27 -0
  33. data/lib/glossarist/rdf/ext/member_rule_ext.rb +34 -0
  34. data/lib/glossarist/rdf/ext/turtle_transform_ext.rb +222 -0
  35. data/lib/glossarist/rdf/ext.rb +39 -0
  36. data/lib/glossarist/rdf/gloss_citation.rb +36 -0
  37. data/lib/glossarist/rdf/gloss_concept.rb +58 -0
  38. data/lib/glossarist/rdf/gloss_concept_date.rb +24 -0
  39. data/lib/glossarist/rdf/gloss_concept_reference.rb +29 -0
  40. data/lib/glossarist/rdf/gloss_concept_source.rb +37 -0
  41. data/lib/glossarist/rdf/gloss_designation.rb +146 -0
  42. data/lib/glossarist/rdf/gloss_detailed_definition.rb +24 -0
  43. data/lib/glossarist/rdf/gloss_grammar_info.rb +57 -0
  44. data/lib/glossarist/rdf/gloss_locality.rb +25 -0
  45. data/lib/glossarist/rdf/gloss_localized_concept.rb +67 -0
  46. data/lib/glossarist/rdf/gloss_non_verbal_rep.rb +31 -0
  47. data/lib/glossarist/rdf/gloss_pronunciation.rb +32 -0
  48. data/lib/glossarist/rdf/gloss_reference.rb +55 -0
  49. data/lib/glossarist/rdf/namespaces/glossarist_namespace.rb +12 -0
  50. data/lib/glossarist/rdf/namespaces/iso_thes_namespace.rb +12 -0
  51. data/lib/glossarist/rdf/namespaces/owl_namespace.rb +12 -0
  52. data/lib/glossarist/rdf/namespaces/prov_namespace.rb +12 -0
  53. data/lib/glossarist/rdf/namespaces/rdf_namespace.rb +12 -0
  54. data/lib/glossarist/rdf/namespaces/skosxl_namespace.rb +12 -0
  55. data/lib/glossarist/rdf/namespaces.rb +8 -2
  56. data/lib/glossarist/rdf/relationships.rb +19 -0
  57. data/lib/glossarist/rdf/v3/configuration.rb +15 -0
  58. data/lib/glossarist/rdf/v3.rb +79 -0
  59. data/lib/glossarist/rdf.rb +22 -2
  60. data/lib/glossarist/reference_extractor.rb +12 -19
  61. data/lib/glossarist/reference_resolver.rb +3 -3
  62. data/lib/glossarist/related_concept.rb +2 -10
  63. data/lib/glossarist/schema_migration.rb +39 -0
  64. data/lib/glossarist/sts/term_mapper.rb +2 -2
  65. data/lib/glossarist/transforms/concept_to_gloss_transform.rb +355 -0
  66. data/lib/glossarist/transforms.rb +2 -2
  67. data/lib/glossarist/v1/concept.rb +17 -17
  68. data/lib/glossarist/v2/citation.rb +36 -0
  69. data/lib/glossarist/v2/concept_data.rb +46 -0
  70. data/lib/glossarist/v2/concept_document.rb +18 -0
  71. data/lib/glossarist/v2/concept_ref.rb +8 -0
  72. data/lib/glossarist/v2/concept_source.rb +16 -0
  73. data/lib/glossarist/v2/configuration.rb +13 -0
  74. data/lib/glossarist/v2/detailed_definition.rb +14 -0
  75. data/lib/glossarist/v2/localized_concept.rb +9 -0
  76. data/lib/glossarist/v2/managed_concept.rb +25 -0
  77. data/lib/glossarist/v2/managed_concept_data.rb +49 -0
  78. data/lib/glossarist/v2/related_concept.rb +15 -0
  79. data/lib/glossarist/v2.rb +28 -0
  80. data/lib/glossarist/v3/bibliography_entry.rb +19 -0
  81. data/lib/glossarist/v3/bibliography_file.rb +27 -0
  82. data/lib/glossarist/v3/citation.rb +30 -0
  83. data/lib/glossarist/v3/concept_data.rb +46 -0
  84. data/lib/glossarist/v3/concept_document.rb +18 -0
  85. data/lib/glossarist/v3/concept_ref.rb +8 -0
  86. data/lib/glossarist/v3/concept_source.rb +16 -0
  87. data/lib/glossarist/v3/configuration.rb +13 -0
  88. data/lib/glossarist/v3/detailed_definition.rb +14 -0
  89. data/lib/glossarist/v3/image_entry.rb +21 -0
  90. data/lib/glossarist/v3/image_file.rb +31 -0
  91. data/lib/glossarist/v3/localized_concept.rb +9 -0
  92. data/lib/glossarist/v3/managed_concept.rb +26 -0
  93. data/lib/glossarist/v3/managed_concept_data.rb +34 -0
  94. data/lib/glossarist/v3/related_concept.rb +15 -0
  95. data/lib/glossarist/v3.rb +36 -0
  96. data/lib/glossarist/validation/bibliography_index.rb +61 -30
  97. data/lib/glossarist/validation/rules/asciidoc_xref_rule.rb +2 -15
  98. data/lib/glossarist/validation/rules/authoritative_source_rule.rb +2 -15
  99. data/lib/glossarist/validation/rules/base.rb +5 -0
  100. data/lib/glossarist/validation/rules/bibliography_yaml_rule.rb +2 -3
  101. data/lib/glossarist/validation/rules/citation_completeness_rule.rb +5 -27
  102. data/lib/glossarist/validation/rules/dataset_context.rb +8 -3
  103. data/lib/glossarist/validation/rules/date_validity_rule.rb +1 -1
  104. data/lib/glossarist/validation/rules/designation_status_rule.rb +0 -1
  105. data/lib/glossarist/validation/rules/designation_type_rule.rb +1 -5
  106. data/lib/glossarist/validation/rules/domain_ref_rule.rb +37 -0
  107. data/lib/glossarist/validation/rules/domain_target_rule.rb +56 -0
  108. data/lib/glossarist/validation/rules/gcr_context.rb +12 -13
  109. data/lib/glossarist/validation/rules/image_reference_rule.rb +2 -17
  110. data/lib/glossarist/validation/rules/locality_completeness_rule.rb +58 -0
  111. data/lib/glossarist/validation/rules/localization_consistency_rule.rb +72 -0
  112. data/lib/glossarist/validation/rules/localization_presence_rule.rb +1 -1
  113. data/lib/glossarist/validation/rules/model_validity_rule.rb +71 -0
  114. data/lib/glossarist/validation/rules/orphaned_bibliography_rule.rb +1 -13
  115. data/lib/glossarist/validation/rules/orphaned_images_rule.rb +16 -11
  116. data/lib/glossarist/validation/rules/ref_shape_rule.rb +68 -0
  117. data/lib/glossarist/validation/rules/related_concept_cycle_rule.rb +1 -3
  118. data/lib/glossarist/validation/rules/related_concept_symmetry_rule.rb +1 -3
  119. data/lib/glossarist/validation/rules/related_concept_target_rule.rb +64 -0
  120. data/lib/glossarist/validation/rules/schema_version_rule.rb +41 -0
  121. data/lib/glossarist/validation/rules/source_type_rule.rb +1 -15
  122. data/lib/glossarist/validation/rules/source_urn_format_rule.rb +65 -0
  123. data/lib/glossarist/validation/rules/uuid_format_rule.rb +33 -0
  124. data/lib/glossarist/validation/rules.rb +10 -43
  125. data/lib/glossarist/validation/validation_issue.rb +14 -11
  126. data/lib/glossarist/validation_result.rb +12 -22
  127. data/lib/glossarist/version.rb +1 -1
  128. data/lib/glossarist.rb +9 -0
  129. data/memory/project-status.md +43 -0
  130. data/scripts/migrate_dataset.rb +180 -0
  131. data/scripts/migrate_isotc204_to_v3.rb +134 -0
  132. data/scripts/migrate_isotc211_to_v3.rb +153 -0
  133. data/scripts/migrate_osgeo_to_v3.rb +155 -0
  134. data/scripts/upgrade_dataset_to_v3.rb +47 -0
  135. metadata +111 -6
  136. data/TODO.integration/01-gcr-package-cli.md +0 -180
  137. data/lib/glossarist/rdf/skos_concept.rb +0 -43
  138. data/lib/glossarist/rdf/skos_vocabulary.rb +0 -25
  139. data/lib/glossarist/transforms/concept_to_skos_transform.rb +0 -131
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0e6019628f010211b1f05fbc2297a9c20b53b85ac23e57ac71d8d09ac933dcc
4
- data.tar.gz: 65bc93a2714354d47261e21d6ee34c0b46f6d967688188c2af04dcf04ed3aaca
3
+ metadata.gz: 5e27bfae8df00d59f8ef6ed55ec4ad8562171cee6740a4bc7baf1f5a9f9561eb
4
+ data.tar.gz: 78fc3b6f141bba0a3e3d7881321b25e1365f04fbbd5f7fb67c10ba364d7dfb65
5
5
  SHA512:
6
- metadata.gz: 86d9478fdc0bdecdfdce06dd607bd6254c04a9be4e261f41131571c60c043af5b84a2dbef7904c721e0c2646c9436fc734038c4ccd5da3a7a8c31b3fb6fc5429
7
- data.tar.gz: 0d9c205d5733dcc767f2f1922eb43fcfdc8e2b445f7c144667bdb508cc285a24e2b50fef9326d085642f1269177f0044401d92fb2128d22466afb91ef25faa34
6
+ metadata.gz: 1beb0e161bbc7d4a44ab7239ec6d3880633dcfdab0e6021dedccf4e4a9cc29bcea764c74cf13390c99232a324abfe3578de9df2613b0a51036ed77b0a3bdb682
7
+ data.tar.gz: ec719ad1adce3ac72aa67d766c9c7c437ad55c40d17ac5d8c514c7d26c9a934517fb544062e14a23e95c715e8f5e46d51709548b34b05f562c2fd9bd5e64cd9c
data/README.adoc CHANGED
@@ -392,7 +392,7 @@ A concept related to the current concept with a typed relationship.
392
392
 
393
393
  type:: Enum — the relationship type (see <<relationship-types,Relationship Types>> below).
394
394
  content:: String — free-text content describing the related concept.
395
- ref:: A <<citation,Citation>> reference to the related concept.
395
+ ref:: A <<concept-ref,ConceptRef>> reference to the related concept (`source + id`, no version or locality).
396
396
 
397
397
  There are two ways to initialize and populate a related concept
398
398
 
@@ -403,7 +403,7 @@ There are two ways to initialize and populate a related concept
403
403
  related_concept = Glossarist::RelatedConcept.new({
404
404
  content: "Test content",
405
405
  type: :supersedes,
406
- ref: <concept citation>
406
+ ref: Glossarist::ConceptRef.new(source: "IEC", id: "102-03-02"),
407
407
  })
408
408
  ----
409
409
 
@@ -414,7 +414,7 @@ related_concept = Glossarist::RelatedConcept.new({
414
414
  related_concept = Glossarist::RelatedConcept.new
415
415
  related_concept.type = "supersedes"
416
416
  related_concept.content = "designation of the related concept"
417
- related_concept.ref = <Citation object>
417
+ related_concept.ref = Glossarist::ConceptRef.new(source: "IEC", id: "102-03-02")
418
418
  ----
419
419
 
420
420
  [[relationship-types]]
@@ -658,7 +658,7 @@ A definition of the managed term.
658
658
  It has the following attributes:
659
659
 
660
660
  content:: The text of the definition of the managed term.
661
- sources:: List of Bibliographic references(<<citation,Citation>>) for this particular definition of the managed term.
661
+ sources:: List of <<concept-source,bibliographic sources>> for this particular definition of the managed term.
662
662
 
663
663
  There are two ways to initialize and populate a detailed definition
664
664
 
@@ -684,42 +684,94 @@ detailed_definition.sources = [<list of citations>]
684
684
  [[id,citation]]
685
685
  === Citation
686
686
 
687
- Citation can be either structured or unstructured. A citation is structured if its reference contains one or all of the following keys `{ id: "id", source: "source", version: "version"}` and is unstructured if its reference is plain text. This also has 2 methods `structured?` and `plain?` to check if citation is structured or not.
687
+ A bibliographic citation used in <<concept-source,ConceptSource>> entries. The
688
+ `ref` field is always a structured hash (`Citation::Ref`), never a plain string.
688
689
 
689
690
  Citation has the following attributes.
690
691
 
691
- ref:: A hash or string based on type of citation. Hash if citation is structured or string if citation is plain.
692
- clause:: Referred clause of the document.
693
- link:: Link to document.
692
+ ref:: A `Citation::Ref` object (always a hash). See below.
693
+ locality:: A `Locality` with `type`, `reference_from`, and `reference_to`.
694
+ link:: URL link to the source document.
695
+ original:: Pre-parsed original citation text.
696
+ custom_locality:: Array of `{ name:, value: }` pairs for non-standard locality types.
694
697
 
695
- There are two ways to initialize and populate a Citation
698
+ `Citation::Ref` inner class:
699
+
700
+ source:: String — the document series or termbase (e.g. `"ISO"`, `"IEC"`).
701
+ id:: String — the document identifier within the series (e.g. `"1087-1:2000"`).
702
+ version:: String — optional version of the document.
703
+
704
+ `Citation#label` returns a display string combining source and id.
696
705
 
697
- 1. Setting the fields by using a hash while initializing
698
- +
699
706
  [,ruby]
700
707
  ----
701
- # Unstructured Citation
702
- citation = Glossarist::Citation.new({
703
- ref: "plain text reference",
704
- clause: "clause",
705
- link: "link",
706
- })
708
+ # Create a Citation
709
+ citation = Glossarist::Citation.new(
710
+ ref: Glossarist::Citation::Ref.new(source: "ISO", id: "9000"),
711
+ locality: Glossarist::Locality.new(type: "clause", reference_from: "3.3.3"),
712
+ link: "https://www.iso.org/standard/45481.html",
713
+ )
707
714
 
708
- # Structured Citation
709
- citation = Glossarist::Citation.new({
710
- ref: { id: "123", source: "source", version: "1.1" },
711
- clause: "clause",
712
- link: "link",
713
- })
715
+ citation.label # => "ISO 9000"
714
716
  ----
715
717
 
716
- 2. Setting the fields after creating an object
717
- +
718
+ YAML serialization (always this shape):
719
+
720
+ [,yaml]
721
+ ----
722
+ origin:
723
+ ref:
724
+ source: ISO
725
+ id: "1087-1:2000"
726
+ locality:
727
+ type: clause
728
+ reference_from: "3.2.9"
729
+ link: https://www.iso.org/standard/20057.html
730
+ ----
731
+
732
+ === ConceptRef
733
+
734
+ A concept reference used in <<related-concept,RelatedConcept>> entries. Has
735
+ `source` and `id` only — no version, locality, or link.
736
+
737
+ [,ruby]
738
+ ----
739
+ ref = Glossarist::ConceptRef.new(source: "IEC", id: "102-01-01")
740
+ ----
741
+
742
+ === V2 and V3 Namespaces
743
+
744
+ Glossarist provides versioned model namespaces for forward and backward
745
+ compatibility:
746
+
747
+ * `Glossarist::V2::*` — loads V2 datasets where `ref` may be a plain string.
748
+ Maps string refs to a `text` attribute internally.
749
+ * `Glossarist::V3::*` — canonical V3 models with structured `Citation::Ref`
750
+ hashes, `BibliographyEntry`, `BibliographyFile`, `ImageEntry`, `ImageFile`.
751
+
752
+ The `ConceptDocument.for_version("2"|"3")` method dispatches to the correct
753
+ namespace. `ConceptCollector.detect_schema_version(dir)` auto-detects from the
754
+ data by checking `schema_version` in the first concept file.
755
+
756
+ === Concept Comparison
757
+
758
+ Compare two concept datasets to identify additions, removals, and changes:
759
+
760
+ [,bash]
761
+ ----
762
+ glossarist compare path/to/v1 path/to/v2
763
+ ----
764
+
765
+ Ruby API:
766
+
718
767
  [,ruby]
719
768
  ----
720
- citation = Glossarist::Citation.new
721
- citation.ref = <plain or structured ref>
722
- citation.clause = "some clause"
769
+ comparator = Glossarist::ConceptComparator.new
770
+ result = comparator.compare(old_concepts, new_concepts)
771
+ result.matched_count # concepts present in both
772
+ result.new_only_count # concepts only in new set
773
+ result.old_only_count # concepts only in old set
774
+ result.diffs # Array of ConceptDiff with similarity scores
723
775
  ----
724
776
 
725
777
  === NonVerbRep
@@ -753,7 +805,7 @@ Concept Source has the following fields
753
805
 
754
806
  status:: The status of the managed term in the present context, relative to the term as found in the bibliographic source.
755
807
  type:: The type of the managed term in the present context.
756
- origin:: The bibliographic <<citation,citation>> for the managed term. This is also aliased as `ref`.
808
+ origin:: The bibliographic <<citation,citation>> for the managed term.
757
809
  modification:: A description of the modification to the cited definition of the term, if any, as it is to be applied in the present context.
758
810
 
759
811
 
@@ -1278,6 +1330,15 @@ Glossarist::Validation::Rules::Registry.register(MyCustomRule)
1278
1330
  Custom rules are automatically picked up by `DatasetValidator`, `GcrValidator`,
1279
1331
  and `ConceptValidator` on the next validation run.
1280
1332
 
1333
+ === compare
1334
+
1335
+ Compare two concept datasets and report differences.
1336
+
1337
+ [,bash]
1338
+ ----
1339
+ glossarist compare PATH_OLD PATH_NEW [--format text|json|yaml]
1340
+ ----
1341
+
1281
1342
  === upgrade
1282
1343
 
1283
1344
  Upgrade a dataset to the current schema version.
data/glossarist.gemspec CHANGED
@@ -32,9 +32,11 @@ Gem::Specification.new do |spec|
32
32
  spec.require_paths = ["lib"]
33
33
 
34
34
  spec.add_dependency "lutaml-model", "~> 0.8.5"
35
+ spec.add_dependency "paint", "~> 2.3"
35
36
  spec.add_dependency "relaton", ">= 2.0.0", "< 3"
36
37
  spec.add_dependency "rubyzip", ">= 2.3", "< 3"
37
38
  spec.add_dependency "sts", "~> 0.5.6"
39
+ spec.add_dependency "table_tennis", "~> 0.0"
38
40
  spec.add_dependency "tbx", "~> 0.1"
39
41
  spec.add_dependency "thor"
40
42
  end
@@ -1,122 +1,41 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Glossarist
2
4
  class Citation < Lutaml::Model::Serializable
3
- # Unstructured (plain text) reference.
4
- # @return [String]
5
- attribute :text, :string
6
-
7
- # Source in structured reference.
8
- # @return [String]
9
- attribute :source, :string
10
-
11
- # Document ID in structured reference.
12
- # @return [String]
13
- attribute :id, :string
14
-
15
- # Document version in structured reference.
16
- # @return [String]
17
- attribute :version, :string
5
+ class Ref < Lutaml::Model::Serializable
6
+ attribute :source, :string
7
+ attribute :id, :string
8
+ attribute :version, :string
9
+
10
+ key_value do
11
+ map :source, to: :source
12
+ map :id, to: :id
13
+ map :version, to: :version
14
+ end
15
+ end
18
16
 
19
- # @return [String]
20
- # Referred locality of the document.
17
+ attribute :ref, Ref
21
18
  attribute :locality, Locality
22
-
23
- # Link to document.
24
- # @return [String]
25
19
  attribute :link, :string
26
-
27
- # Original ref text before parsing.
28
- # @return [String]
29
- # @note This attribute is likely to be removed or reworked in future.
30
- # It is arguably not relevant to Glossarist itself.
31
20
  attribute :original, :string
32
-
33
- attribute :ref, :string
34
-
35
21
  attribute :custom_locality, CustomLocality, collection: true
36
22
 
37
23
  key_value do
38
- map :id, to: :id, with: { from: :id_from_yaml, to: :id_to_yaml }
39
- map :text, to: :text, with: { from: :text_from_yaml, to: :text_to_yaml }
40
- map :source, to: :source,
41
- with: { from: :source_from_yaml, to: :source_to_yaml }
42
- map :version, to: :version,
43
- with: { from: :version_from_yaml, to: :version_to_yaml }
44
- map :ref, to: :ref, with: { from: :ref_from_yaml, to: :ref_to_yaml }
24
+ map :ref, to: :ref
45
25
  map %i[clause locality],
46
26
  to: :locality,
47
- with: { from: :clause_from_yaml, to: :clause_to_yaml }
27
+ with: { from: :locality_from_yaml, to: :locality_to_yaml }
48
28
  map :link, to: :link
49
29
  map :original, to: :original
50
30
  map %i[custom_locality customLocality], to: :custom_locality
51
31
  end
52
32
 
53
- def ref_from_yaml(model, value)
54
- model.ref = value
55
- end
56
-
57
- def ref_to_yaml(model, doc)
58
- doc["ref"] = if model.structured?
59
- ref_hash(model)
60
- else
61
- model.text
62
- end
63
- end
64
-
65
- def id_from_yaml(model, value)
66
- model.id = value
67
- end
68
-
69
- def id_to_yaml(_model, _doc)
70
- # skip, will be handled in ref
71
- end
72
-
73
- def text_from_yaml(model, value)
74
- model.text = value
75
- end
76
-
77
- def text_to_yaml(_model, _doc)
78
- # skip, will be handled in ref
33
+ def label
34
+ parts = [ref&.source, ref&.id].compact
35
+ parts.empty? ? nil : parts.join(" ")
79
36
  end
80
37
 
81
- def source_from_yaml(model, value)
82
- model.source = value
83
- end
84
-
85
- def source_to_yaml(_model, _doc)
86
- # skip, will be handled in ref
87
- end
88
-
89
- def version_from_yaml(model, value)
90
- model.version = value
91
- end
92
-
93
- def version_to_yaml(_model, _doc)
94
- # skip, will be handled in ref
95
- end
96
-
97
- def ref_hash(model = self)
98
- {
99
- "source" => model.source,
100
- "id" => model.id,
101
- "version" => model.version,
102
- }.compact
103
- end
104
-
105
- def ref=(ref)
106
- if ref.is_a?(Hash)
107
- @source = ref["source"]
108
- @id = ref["id"]
109
- @version = ref["version"]
110
- else
111
- @text = ref
112
- end
113
- end
114
-
115
- def clause_from_yaml(model, value) # rubocop:disable Metrics/AbcSize
116
- # accepts old format like
117
- # clause: "11"
118
- # or new format like
119
- # locality: { type: "clause", reference_from: "11", reference_to: "12" }
38
+ def locality_from_yaml(model, value)
120
39
  locality = Locality.new
121
40
 
122
41
  if value.is_a?(Hash)
@@ -132,29 +51,13 @@ module Glossarist
132
51
  model.locality = locality
133
52
  end
134
53
 
135
- def clause_to_yaml(model, doc) # rubocop:disable Metrics/AbcSize
136
- if model.locality
137
- doc["locality"] = {}
138
- doc["locality"]["type"] = model.locality.type
139
-
140
- if model.locality.reference_from
141
- doc["locality"]["reference_from"] = model.locality.reference_from
142
- end
143
-
144
- if model.locality.reference_to
145
- doc["locality"]["reference_to"] = model.locality.reference_to
146
- end
147
- end
148
- end
149
-
150
- def plain?
151
- (source && id && version).nil?
152
- end
54
+ def locality_to_yaml(model, doc)
55
+ return unless model.locality
153
56
 
154
- # Whether it is a structured ref.
155
- # @return [Boolean]
156
- def structured?
157
- !plain?
57
+ doc["locality"] = {}
58
+ doc["locality"]["type"] = model.locality.type
59
+ doc["locality"]["reference_from"] = model.locality.reference_from if model.locality.reference_from
60
+ doc["locality"]["reference_to"] = model.locality.reference_to if model.locality.reference_to
158
61
  end
159
62
  end
160
63
  end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "paint"
4
+
5
+ module Glossarist
6
+ class CLI
7
+ class CompareCommand
8
+ def initialize(new_path, old_path, options)
9
+ @new_path = new_path
10
+ @old_path = old_path
11
+ @options = options
12
+ end
13
+
14
+ def run
15
+ new_concepts = ConceptCollector.collect(@new_path)
16
+ old_concepts = ConceptCollector.collect(@old_path)
17
+
18
+ result = ConceptComparator.new(
19
+ new_concepts: new_concepts,
20
+ old_concepts: old_concepts,
21
+ ).compare(show_diffs: !@options[:no_diffs])
22
+
23
+ report(result)
24
+ end
25
+
26
+ private
27
+
28
+ def report(result)
29
+ case @options[:format]
30
+ when "json"
31
+ output result.to_json
32
+ when "yaml"
33
+ output result.to_yaml
34
+ else
35
+ print_text_report(result)
36
+ end
37
+ end
38
+
39
+ def print_text_report(result)
40
+ puts
41
+ puts Paint["Concept Comparison", :bold]
42
+ puts
43
+
44
+ print_counts(result)
45
+ print_new_only(result)
46
+ print_old_only(result)
47
+ print_similarity(result)
48
+
49
+ puts
50
+ end
51
+
52
+ def print_counts(result)
53
+ puts " #{Paint['New:', :bold]} #{result.new_count} concepts"
54
+ puts " #{Paint['Old:', :bold]} #{result.old_count} concepts"
55
+ puts " #{Paint['Matched:', :bold]} #{result.matched.length}"
56
+ puts " #{Paint['New only:', :bold]} #{result.new_only.length}"
57
+ puts " #{Paint['Old only:', :bold]} #{result.old_only.length}"
58
+ end
59
+
60
+ def print_new_only(result)
61
+ return unless result.new_only.any?
62
+
63
+ puts
64
+ puts " #{Paint['New concepts (not in old):', :green, :bold]}"
65
+ result.new_only.each { |id| puts " + #{id}" }
66
+ end
67
+
68
+ def print_old_only(result)
69
+ return unless result.old_only.any?
70
+
71
+ puts
72
+ puts " #{Paint['Removed concepts (not in new):', :red, :bold]}"
73
+ result.old_only.each { |id| puts " - #{id}" }
74
+ end
75
+
76
+ def print_similarity(result)
77
+ return unless result.diffs.any?
78
+
79
+ puts
80
+ puts " #{Paint['Per-concept similarity:', :bold]}"
81
+ result.diffs.each do |diff|
82
+ color = similarity_color(diff.similarity)
83
+ puts " #{diff.concept_id}: #{Paint["#{diff.similarity}%", color]}"
84
+ end
85
+ end
86
+
87
+ def similarity_color(value)
88
+ if value >= 100
89
+ :green
90
+ elsif value >= 90
91
+ :yellow
92
+ else
93
+ :red
94
+ end
95
+ end
96
+
97
+ def output(content)
98
+ if @options[:report]
99
+ File.write(@options[:report], content)
100
+ else
101
+ puts content
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -48,8 +48,8 @@ module Glossarist
48
48
  end
49
49
 
50
50
  def resolve_metadata_from_package(package)
51
- @options[:shortname] ||= package.metadata["shortname"]
52
- @options[:uri_prefix] ||= package.metadata["uri_prefix"]
51
+ @options[:shortname] ||= package.metadata.shortname
52
+ @options[:uri_prefix] ||= package.metadata.uri_prefix
53
53
  end
54
54
 
55
55
  def resolve_shortname
@@ -73,17 +73,15 @@ module Glossarist
73
73
  end
74
74
 
75
75
  def export_jsonld(concepts, name, output_dir)
76
- require "glossarist/transforms/concept_to_skos_transform"
77
- vocab = Transforms::ConceptToSkosTransform.transform_document(concepts,
78
- transform_options)
79
- File.write(File.join(output_dir, "#{name}.jsonld"), vocab.to_jsonld)
76
+ require "glossarist/transforms/concept_to_gloss_transform"
77
+ transform = Transforms::ConceptToGlossTransform.new(nil, transform_options)
78
+ File.write(File.join(output_dir, "#{name}.jsonld"), transform.to_jsonld(concepts))
80
79
  end
81
80
 
82
81
  def export_turtle(concepts, name, output_dir)
83
- require "glossarist/transforms/concept_to_skos_transform"
84
- vocab = Transforms::ConceptToSkosTransform.transform_document(concepts,
85
- transform_options)
86
- File.write(File.join(output_dir, "#{name}.ttl"), vocab.to_turtle)
82
+ require "glossarist/transforms/concept_to_gloss_transform"
83
+ transform = Transforms::ConceptToGlossTransform.new(nil, transform_options)
84
+ File.write(File.join(output_dir, "#{name}.ttl"), transform.to_turtle(concepts))
87
85
  end
88
86
 
89
87
  def export_tbx(concepts, name, output_dir)
@@ -94,12 +92,11 @@ module Glossarist
94
92
  end
95
93
 
96
94
  def export_jsonl(concepts, name, output_dir)
97
- require "glossarist/transforms/concept_to_skos_transform"
95
+ require "glossarist/transforms/concept_to_gloss_transform"
98
96
  File.open(File.join(output_dir, "#{name}.jsonl"), "w") do |f|
99
97
  concepts.each do |concept|
100
- skos = Transforms::ConceptToSkosTransform.transform(concept,
101
- transform_options)
102
- f.write(skos.to_jsonld)
98
+ transform = Transforms::ConceptToGlossTransform.new(concept, transform_options)
99
+ f.write(transform.to_jsonl_line)
103
100
  f.write("\n")
104
101
  end
105
102
  end