glossarist 0.2.0 → 1.0.5

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +15 -0
  3. data/.github/workflows/release.yml +24 -0
  4. data/.gitignore +2 -0
  5. data/.hound.yml +3 -1
  6. data/.rubocop.yml +4 -29
  7. data/README.adoc +23 -0
  8. data/config.yml +83 -0
  9. data/exe/glossarist +50 -0
  10. data/glossarist.gemspec +4 -1
  11. data/lib/glossarist/asset.rb +22 -0
  12. data/lib/glossarist/citation.rb +89 -0
  13. data/lib/glossarist/collections/asset_collection.rb +11 -0
  14. data/lib/glossarist/collections/bibliography_collection.rb +25 -0
  15. data/lib/glossarist/collections.rb +2 -0
  16. data/lib/glossarist/concept.rb +96 -31
  17. data/lib/glossarist/concept_date.rb +20 -0
  18. data/lib/glossarist/concept_manager.rb +44 -0
  19. data/lib/glossarist/concept_set.rb +80 -0
  20. data/lib/glossarist/concept_source.rb +62 -0
  21. data/lib/glossarist/config.rb +54 -0
  22. data/lib/glossarist/designation/abbreviation.rb +23 -0
  23. data/lib/glossarist/designation/base.rb +37 -0
  24. data/lib/glossarist/designation/expression.rb +50 -0
  25. data/lib/glossarist/designation/grammar_info.rb +58 -0
  26. data/lib/glossarist/designation/graphical_symbol.rb +17 -0
  27. data/lib/glossarist/designation/letter_symbol.rb +19 -0
  28. data/lib/glossarist/designation/symbol.rb +21 -0
  29. data/lib/glossarist/designation.rb +27 -0
  30. data/lib/glossarist/detailed_definition.rb +31 -0
  31. data/lib/glossarist/glossary_definition.rb +29 -0
  32. data/lib/glossarist/localized_concept.rb +10 -59
  33. data/lib/glossarist/managed_concept.rb +116 -0
  34. data/lib/glossarist/managed_concept_collection.rb +79 -0
  35. data/lib/glossarist/model.rb +12 -2
  36. data/lib/glossarist/non_verb_rep.rb +18 -0
  37. data/lib/glossarist/related_concept.rb +31 -0
  38. data/lib/glossarist/utilities/boolean_attributes.rb +35 -0
  39. data/lib/glossarist/utilities/common_functions.rb +29 -0
  40. data/lib/glossarist/utilities/enum/class_methods.rb +99 -0
  41. data/lib/glossarist/utilities/enum/enum_collection.rb +45 -0
  42. data/lib/glossarist/utilities/enum/instance_methods.rb +55 -0
  43. data/lib/glossarist/utilities/enum.rb +21 -0
  44. data/lib/glossarist/utilities.rb +5 -0
  45. data/lib/glossarist/version.rb +1 -1
  46. data/lib/glossarist.rb +27 -2
  47. metadata +69 -7
  48. data/.github/workflows/test.yml +0 -34
  49. data/lib/glossarist/designations.rb +0 -82
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ class ConceptSet
5
+ # a `Glossarist::ManagedConceptCollection` object
6
+ attr_accessor :concepts
7
+
8
+ # a `BibliographyCollection` object
9
+ attr_accessor :bibliographies
10
+
11
+ # an `Collections::Asset` object
12
+ attr_accessor :assets
13
+
14
+ # @parameters
15
+ # concepts => a `Glossarist::ManagedConceptCollection` object or
16
+ # a string containing the path of the folder with concepts
17
+ # assets => a collection of Glossarist::Asset
18
+ def initialize(concepts, assets, options = {})
19
+ @concepts = read_concepts(concepts)
20
+ @assets = Glossarist::Collections::AssetCollection.new(assets)
21
+ @bibliographies = Glossarist::Collections::BibliographyCollection.new(
22
+ @concepts,
23
+ options.dig(:bibliography, :global_cache),
24
+ options.dig(:bibliography, :local_cache),
25
+ )
26
+ end
27
+
28
+ def to_latex(filename = nil)
29
+ return to_latex_from_file(filename) if filename
30
+
31
+ @concepts.map do |concept|
32
+ latex_template(concept)
33
+ end.join("\n")
34
+ end
35
+
36
+ private
37
+
38
+ def to_latex_from_file(entries_file)
39
+ File.readlines(entries_file).map do |concept_name|
40
+ concept = concept_map[concept_name.strip.downcase]
41
+
42
+ if concept.nil?
43
+ puts " [Not Found]: #{concept_name.strip}"
44
+ else
45
+ latex_template(concept)
46
+ end
47
+ end.compact.join("\n")
48
+ end
49
+
50
+ def read_concepts(concepts)
51
+ return concepts if concepts.is_a?(Glossarist::ManagedConceptCollection)
52
+
53
+ collection = Glossarist::ManagedConceptCollection.new
54
+ collection.load_from_files(concepts)
55
+ collection
56
+ end
57
+
58
+ def latex_template(concept)
59
+ <<~TEMPLATE
60
+ \\newglossaryentry{#{concept.default_designation.gsub('_', '-')}}
61
+ {
62
+ name={#{concept.default_designation.gsub('_', '\_')}}
63
+ description={#{normalize_definition(concept.default_definition)}}
64
+ }
65
+ TEMPLATE
66
+ end
67
+
68
+ def normalize_definition(definition)
69
+ definition.gsub(/{{([^}]*)}}/) do |match|
70
+ "\\textbf{\\gls{#{Regexp.last_match[1].gsub('_', '-')}}}"
71
+ end
72
+ end
73
+
74
+ def concept_map
75
+ @concept_map ||= concepts.managed_concepts.map do |concept|
76
+ [concept.default_designation.downcase, concept]
77
+ end.to_h
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ class ConceptSource < Model
5
+ include Glossarist::Utilities::Enum
6
+ include Glossarist::Utilities::CommonFunctions
7
+
8
+ register_enum :status, Glossarist::GlossaryDefinition::CONCEPT_SOURCE_STATUSES
9
+ register_enum :type, Glossarist::GlossaryDefinition::CONCEPT_SOURCE_TYPES
10
+
11
+ attr_reader :origin
12
+ alias_method :ref, :origin
13
+
14
+ attr_accessor :modification
15
+
16
+ def initialize(attributes = {})
17
+ if rel = attributes.delete("relationship")
18
+ self.status = rel["type"]
19
+ self.modification = rel["modification"]
20
+ end
21
+
22
+ self.origin = slice_keys(attributes, ref_param_names)
23
+
24
+ remaining_attributes = attributes.dup
25
+ ref_param_names.each { |k| remaining_attributes.delete(k) }
26
+
27
+ super(remaining_attributes)
28
+ end
29
+
30
+ def origin=(origin)
31
+ @origin = Citation.new(origin)
32
+ end
33
+
34
+ alias_method :ref=, :origin=
35
+
36
+ def to_h
37
+ origin_hash = self.origin.to_h.empty? ? nil : self.origin.to_h
38
+
39
+ {
40
+ "type" => type.to_s,
41
+ "status" => status&.to_s,
42
+ "origin" => origin_hash,
43
+ "modification" => modification,
44
+ }.compact
45
+ end
46
+
47
+ private
48
+
49
+ def ref_param_names
50
+ %w[
51
+ ref
52
+ text
53
+ source
54
+ id
55
+ version
56
+ clause
57
+ link
58
+ original
59
+ ]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module Glossarist
6
+ class Config
7
+ include Singleton
8
+
9
+ DEFAULT_CLASSES = {
10
+ localized_concept: Glossarist::LocalizedConcept,
11
+ }.freeze
12
+
13
+ attr_reader :registered_classes
14
+
15
+ def initialize
16
+ @registered_classes = DEFAULT_CLASSES.dup
17
+ @extension_attributes = []
18
+ end
19
+
20
+ def class_for(name)
21
+ @registered_classes[name.to_sym]
22
+ end
23
+
24
+ def register_class(class_name, klass)
25
+ @registered_classes[class_name] = klass
26
+ end
27
+
28
+ def extension_attributes
29
+ @extension_attributes
30
+ end
31
+
32
+ def register_extension_attributes(attributes)
33
+ @extension_attributes = attributes
34
+ end
35
+
36
+ class << self
37
+ def class_for(name)
38
+ self.instance.class_for(name)
39
+ end
40
+
41
+ def extension_attributes
42
+ self.instance.extension_attributes
43
+ end
44
+
45
+ def register_class(class_name, klass)
46
+ self.instance.register_class(class_name, klass)
47
+ end
48
+
49
+ def register_extension_attributes(attributes)
50
+ self.register_extension_attributes(attributes)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "expression"
4
+ require_relative "../utilities"
5
+
6
+ module Glossarist
7
+ module Designation
8
+ class Abbreviation < Expression
9
+ include Glossarist::Utilities::Enum
10
+
11
+ register_enum :type, Glossarist::GlossaryDefinition::ABBREVIATION_TYPES
12
+
13
+ attr_accessor :international
14
+
15
+ def to_h
16
+ super().merge({
17
+ "type" => type.to_s,
18
+ "international" => international,
19
+ }).compact
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ module Designation
5
+ class Base < Model
6
+ include Glossarist::Utilities::Enum
7
+
8
+ # @note This is not entirely aligned with agreed schema and may be
9
+ # changed.
10
+ attr_accessor :designation
11
+
12
+ attr_accessor :geographical_area
13
+ register_enum :normative_status, Glossarist::GlossaryDefinition::DESIGNATION_BASE_NORMATIVE_STATUSES
14
+
15
+ def self.from_h(hash)
16
+ type = hash["type"]
17
+
18
+ if type.nil? || /\w/ !~ type
19
+ raise ArgumentError, "designation type is missing"
20
+ end
21
+
22
+ designation_subclass = SERIALIZED_TYPES[type]
23
+
24
+ if self == Base
25
+ # called on Base class, delegate it to proper subclass
26
+ SERIALIZED_TYPES[type].from_h(hash)
27
+ else
28
+ # called on subclass, instantiate object
29
+ unless SERIALIZED_TYPES[self] == type
30
+ raise ArgumentError, "unexpected designation type: #{type}"
31
+ end
32
+ super(hash.reject { |k, _| k == "type" })
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Glossarist
6
+ module Designation
7
+ class Expression < Base
8
+ attr_accessor :prefix
9
+ attr_accessor :usage_info
10
+
11
+ # List of grammar info.
12
+ # @return [Array<GrammarInfo>]
13
+ attr_reader :grammar_info
14
+
15
+ def grammar_info=(grammar_info)
16
+ @grammar_info = grammar_info.map { |g| GrammarInfo.new(g) }
17
+ end
18
+
19
+ # @todo Added to cater for current iev-data implementation,
20
+ # might be removed in the future.
21
+ def self.from_h(hash)
22
+ gender = hash.delete("gender") || hash.delete(:gender)
23
+ number = hash.delete("plurality") || hash.delete(:plurality)
24
+ part_of_speech = hash.delete("part_of_speech") || hash.delete(:part_of_speech)
25
+
26
+ if gender || number || part_of_speech
27
+ hash["grammar_info"] = [{
28
+ "gender" => gender,
29
+ "number" => number,
30
+ part_of_speech => part_of_speech,
31
+ }.compact]
32
+ end
33
+
34
+ super
35
+ end
36
+
37
+ def to_h
38
+ {
39
+ "type" => "expression",
40
+ "prefix" => prefix,
41
+ "normative_status" => normative_status,
42
+ "usage_info" => usage_info,
43
+ "designation" => designation,
44
+ "geographical_area" => geographical_area,
45
+ "grammar_info" => grammar_info&.map(&:to_h),
46
+ }.compact
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../utilities"
4
+
5
+ module Glossarist
6
+ module Designation
7
+ class GrammarInfo
8
+ include Glossarist::Utilities::Enum
9
+ include Glossarist::Utilities::BooleanAttributes
10
+ include Glossarist::Utilities::CommonFunctions
11
+
12
+ register_enum :gender, Glossarist::GlossaryDefinition::GRAMMAR_INFO_GENDERS, multiple: true
13
+ register_enum :number, Glossarist::GlossaryDefinition::GRAMMAR_INFO_NUMBERS, multiple: true
14
+
15
+ register_boolean_attributes Glossarist::GlossaryDefinition::GRAMMAR_INFO_BOOLEAN_ATTRIBUTES
16
+
17
+ def initialize(options = {})
18
+ sanitized_options(options).each do |attr, value|
19
+ public_send("#{attr}=", value)
20
+ end
21
+ end
22
+
23
+ def part_of_speech=(pos)
24
+ public_send("#{pos}=", pos)
25
+ end
26
+
27
+ def to_h
28
+ {
29
+ "preposition" => preposition?,
30
+ "participle" => participle?,
31
+ "adj" => adj?,
32
+ "verb" => verb?,
33
+ "adverb" => adverb?,
34
+ "noun" => noun?,
35
+ "gender" => gender,
36
+ "number" => number,
37
+ }
38
+ end
39
+
40
+ private
41
+
42
+ def sanitized_options(options)
43
+ hash = symbolize_keys(options)
44
+ slice_keys(hash, [
45
+ :gender,
46
+ :number,
47
+ :preposition,
48
+ :participle,
49
+ :adj,
50
+ :verb,
51
+ :adverb,
52
+ :noun,
53
+ :part_of_speech,
54
+ ])
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ module Designation
5
+ class GraphicalSymbol < Symbol
6
+ attr_accessor :text
7
+ attr_accessor :image
8
+
9
+ def to_h
10
+ super.merge(
11
+ "text" => text,
12
+ "image" => image,
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ module Designation
5
+ class LetterSymbol < Symbol
6
+ attr_accessor :text
7
+ attr_accessor :language
8
+ attr_accessor :script
9
+
10
+ def to_h
11
+ super.merge(
12
+ "text" => text,
13
+ "language" => language,
14
+ "script" => script,
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Glossarist
6
+ module Designation
7
+ class Symbol < Base
8
+ attr_accessor :international
9
+
10
+ def to_h
11
+ {
12
+ "type" => Glossarist::Designation::SERIALIZED_TYPES[self.class],
13
+ "normative_status" => normative_status,
14
+ "geographical_area" => geographical_area,
15
+ "designation" => designation,
16
+ "international" => international,
17
+ }.compact
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ require_relative "designation/abbreviation"
7
+ require_relative "designation/base"
8
+ require_relative "designation/expression"
9
+ require_relative "designation/grammar_info"
10
+ require_relative "designation/symbol"
11
+ require_relative "designation/graphical_symbol"
12
+ require_relative "designation/letter_symbol"
13
+
14
+ module Glossarist
15
+ module Designation
16
+ # Bi-directional class-to-string mapping for STI-like serialization.
17
+ SERIALIZED_TYPES = {
18
+ Expression => "expression",
19
+ Symbol => "symbol",
20
+ Abbreviation => "abbreviation",
21
+ GraphicalSymbol => "graphical_symbol",
22
+ LetterSymbol => "letter_symbol",
23
+ }
24
+ .tap { |h| h.merge!(h.invert) }
25
+ .freeze
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ class DetailedDefinition < Model
5
+
6
+ def initialize(attributes = {})
7
+ if attributes.is_a?(Hash)
8
+ super
9
+ else
10
+ self.content = attributes
11
+ end
12
+ end
13
+
14
+ # @return [String]
15
+ attr_accessor :content
16
+
17
+ # @return [Array<ConceptSource>]
18
+ attr_reader :sources
19
+
20
+ def sources=(sources)
21
+ @sources = sources.map { |s| ConceptSource.new(s) }
22
+ end
23
+
24
+ def to_h
25
+ {
26
+ "content" => content,
27
+ "sources" => sources&.map(&:to_h),
28
+ }.compact
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Glossarist
6
+ module GlossaryDefinition
7
+ config = YAML.load_file(File.expand_path("../../../config.yml", __FILE__)) || {}
8
+
9
+ CONCEPT_SOURCE_STATUSES = config.dig("concept_source", "status").freeze
10
+
11
+ CONCEPT_SOURCE_TYPES = config.dig("concept_source", "type").freeze
12
+
13
+ RELATED_CONCEPT_TYPES = config.dig("related_concept", "type").freeze
14
+
15
+ ABBREVIATION_TYPES = config.dig("abbreviation", "type").freeze
16
+
17
+ GRAMMAR_INFO_BOOLEAN_ATTRIBUTES = config.dig("grammar_info", "boolean_attribute").freeze
18
+
19
+ GRAMMAR_INFO_GENDERS = config.dig("grammar_info", "gender").freeze
20
+
21
+ GRAMMAR_INFO_NUMBERS = config.dig("grammar_info", "number").freeze
22
+
23
+ DESIGNATION_BASE_NORMATIVE_STATUSES = config.dig("designation", "base", "normative_status").freeze
24
+
25
+ CONCEPT_DATE_TYPES = config.dig("concept_date", "type").freeze
26
+
27
+ CONCEPT_STATUSES = config.dig("concept", "status").freeze
28
+ end
29
+ end
@@ -4,43 +4,12 @@
4
4
  #
5
5
 
6
6
  module Glossarist
7
- class LocalizedConcept < Model
8
- # Needs to be identical with {Concept#id}.
9
- # @todo Here for legacy reasons. Will be removed eventually.
10
- attr_accessor :id
11
-
7
+ class LocalizedConcept < Concept
12
8
  # ISO 639-2 code for terminology.
13
9
  # @see https://www.loc.gov/standards/iso639-2/php/code_list.php code list
14
10
  # @return [String]
15
11
  attr_accessor :language_code
16
12
 
17
- # Concept designations.
18
- # @todo Alias +terms+ exists only for legacy reasons and will be removed.
19
- # @return [Array<Designations::Base>]
20
- attr_accessor :designations
21
- alias :terms :designations
22
- alias :terms= :designations=
23
-
24
- # @return [Array<String>]
25
- attr_accessor :notes
26
-
27
- # @return [Array<String>]
28
- attr_accessor :examples
29
-
30
- # Concept definition.
31
- # @todo Support multiple definitions.
32
- # @return [String]
33
- attr_accessor :definition
34
-
35
- # @todo Right now accepts hashes for legacy reasons, but they will be
36
- # replaced with dedicated classes.
37
- # @todo Alias +authoritative_source+ exists for legacy reasons and may be
38
- # removed.
39
- # @return [Array<Hash>]
40
- attr_accessor :sources
41
- alias :authoritative_source :sources
42
- alias :authoritative_source= :sources=
43
-
44
13
  # Must be one of the following:
45
14
  # +notValid+, +valid+, +superseded+, +retired+.
46
15
  # @todo Proper type checking.
@@ -59,48 +28,30 @@ module Glossarist
59
28
  attr_accessor :review_decision_date
60
29
  attr_accessor :review_decision_event
61
30
 
62
- attr_accessor :date_accepted
63
- attr_accessor :date_amended
64
-
65
- # @todo Here for legacy reasons. Will be moved to Concept.
66
- # @todo Right now is an array of hashes for legacy reasons, but these hashes
67
- # will be replaced with some dedicated class.
68
- # @todo Should be read-only, but for now it is not for legacy reasons.
69
- # Don't use the setter.
70
- # @return [Array<Hash>]
71
- attr_accessor :superseded_concepts
72
-
73
31
  def initialize(*)
74
32
  @examples = []
75
- @notes = []
76
- @designations = []
77
- @superseded_concepts = []
78
- @sources = []
33
+
79
34
  super
80
35
  end
81
36
 
82
37
  def to_h # rubocop:disable Metrics/MethodLength
83
- {
84
- "id" => id,
85
- "terms" => (terms&.map(&:to_h) || []),
86
- "definition" => definition,
38
+ super.merge({
87
39
  "language_code" => language_code,
88
- "notes" => notes,
89
- "examples" => examples,
90
40
  "entry_status" => entry_status,
41
+ "sources" => sources.empty? ? nil : sources&.map(&:to_h),
91
42
  "classification" => classification,
92
- "authoritative_source" => (sources if sources&.any?),
93
- "date_accepted" => date_accepted,
94
- "date_amended" => date_amended,
43
+ "dates" => dates&.map(&:to_h),
95
44
  "review_date" => review_date,
96
45
  "review_decision_date" => review_decision_date,
97
46
  "review_decision_event" => review_decision_event,
98
- }.compact
47
+ }.compact).merge(@extension_attributes)
99
48
  end
100
49
 
101
50
  def self.from_h(hash)
102
- terms = hash["terms"]&.map { |h| Designations::Base.from_h(h) } || []
103
- super(hash.merge({"terms" => terms}))
51
+ terms = hash["terms"]&.map { |h| Designation::Base.from_h(h) } || []
52
+ sources = hash["authoritative_source"]&.each { |source| source.merge({ "type" => "authoritative"}) }
53
+
54
+ super(hash.merge({"terms" => terms, "sources" => sources}))
104
55
  end
105
56
 
106
57
  # @deprecated For legacy reasons only.