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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15883cde9ccc6f1d81e6851314ef7cae3835fd679c320b961be4310eea0e3384
4
- data.tar.gz: b0821aa718dbc0caa858ff5d1ab0723937e4c527d9a98a6a182f4976637d32d0
3
+ metadata.gz: 6ef95bd483f8056cb7238fba5a2c701879f1d51250627250a8c10dec04da9df0
4
+ data.tar.gz: 9fe8e9bdc77e630c36edf6f8500b9b91d62a2c10395664798304719161860545
5
5
  SHA512:
6
- metadata.gz: 295691e8f62944ea642ed41861146e0d321ec2c793d519227d1ad1cdde174787d8ad9a219bfbe19a3d4b7eb60395a53c37f6375151cc5a89a707694367614be4
7
- data.tar.gz: 6a0c63bfd7b33bc7803e0daa685d677dc6bb061e4bf09be415878f10e72c3c836285d36b38da61628438ea7c9afb0d03eed566a1f8a9af5993990ffc6fe819c3
6
+ metadata.gz: e224dd6e334eecf6bf9e8cdfbca206aabfbfc42967479625db0f677dddabe6b6dc3c7d9eb77f2462e140aac762c0707d35b8252884879f71f3de727b37443e55
7
+ data.tar.gz: 0a17ff365ff523f83e553c376b4d53b58df84fd2916e00dbcb874a10a017eb5c78e9c3285bf1355de5f572faeb5bb5ae1aabc76611699e205368cfaf7bbf6a73
@@ -0,0 +1,15 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ name: rake
4
+
5
+ on:
6
+ push:
7
+ branches: [ master, main ]
8
+ tags: [ v* ]
9
+ pull_request:
10
+
11
+ jobs:
12
+ rake:
13
+ uses: metanorma/ci/.github/workflows/generic-rake.yml@main
14
+ secrets:
15
+ pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
@@ -0,0 +1,24 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ name: release
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ next_version:
9
+ description: |
10
+ Next release version. Possible values: x.y.z, major, minor, patch or pre|rc|etc
11
+ required: true
12
+ default: 'skip'
13
+ repository_dispatch:
14
+ types: [ do-release ]
15
+
16
+ jobs:
17
+ release:
18
+ uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
19
+ with:
20
+ next_version: ${{ github.event.inputs.next_version }}
21
+ secrets:
22
+ rubygems-api-key: ${{ secrets.GLOSSARIST_CI_RUBYGEMS_API_KEY }}
23
+ pat_token: ${{ secrets.GLOSSARIST_CI_PAT_TOKEN }}
24
+
data/.gitignore CHANGED
@@ -16,3 +16,5 @@
16
16
  .rubocop-http---*
17
17
  .rubocop-https---*
18
18
 
19
+ # Relaton local cache directory
20
+ localcache
data/.hound.yml CHANGED
@@ -1,3 +1,5 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
1
3
  ruby:
2
4
  enabled: true
3
- config_file: .rubocop.yml
5
+ config_file: .rubocop.yml
data/.rubocop.yml CHANGED
@@ -1,35 +1,10 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
1
3
  inherit_from:
2
4
  - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
3
5
 
4
6
  # local repo-specific modifications
7
+ # ...
5
8
 
6
9
  AllCops:
7
- TargetRubyVersion: 2.4
8
-
9
- # This one breaks plenty of RSpec idioms.
10
- Lint/AmbiguousBlockAssociation:
11
- Exclude:
12
- - "spec/**/*"
13
-
14
- # Defining a constant or class inside RSpec.describe block
15
- # sometimes makes sense.
16
- Lint/ConstantDefinitionInBlock:
17
- Exclude:
18
- - "spec/**/*"
19
-
20
- # This requirement is silly to me.
21
- Style/AccessModifierDeclarations:
22
- Enabled: false
23
-
24
- # Makes little sense for Glossarist models, as these attr_accessors should all
25
- # be documented eventually.
26
- Style/AccessorGrouping:
27
- Enabled: false
28
-
29
- # This requirement is silly to me.
30
- Style/ClassCheck:
31
- Enabled: false
32
-
33
- # This requirement is silly to me.
34
- Style/SingleArgumentDig:
35
- Enabled: false
10
+ TargetRubyVersion: 2.5
data/README.adoc CHANGED
@@ -1,5 +1,28 @@
1
1
  = Glossarist
2
2
 
3
+ == Commands
4
+
5
+ generate_latex: Convert Concepts to Latex format
6
+
7
+ === Usage:
8
+ glossarist generate_latex p, --concepts-path=CONCEPTS_PATH
9
+
10
+ === Options:
11
+ [cols="1,1"]
12
+ |===
13
+ |p, --concepts-path
14
+ |Path to yaml concepts directory
15
+
16
+ |l, --latex-concepts
17
+ |File path having list of concepts that should be converted to LATEX format. If not provided all the concepts will be converted to the latex format
18
+
19
+ |o, --output-file
20
+ |Output file path. By default the output will pe printed to the console
21
+
22
+ |e, --extra-attributes
23
+ |List of extra attributes that are not in standard Glossarist Concept model. eg -e one two three
24
+ |===
25
+
3
26
  == Credits
4
27
 
5
28
  This gem is developed, maintained and funded by
data/config.yml ADDED
@@ -0,0 +1,83 @@
1
+ # This file can be used to configure enum attributes in the model.
2
+ # For example to add different allowed values for Abbreviation::Type
3
+ # you can change the values under abbreviation => type
4
+ #
5
+ # NOTE: All the keys in this file are needed for the script to run
6
+ # and should not be removed. You can change the values but atleast
7
+ # one option should be present in each list.
8
+
9
+ concept_source:
10
+ status:
11
+ - identical
12
+ - similar
13
+ - modified
14
+ - restyle
15
+ - context_added
16
+ - generalisation
17
+ - specialisation
18
+ - unspecified
19
+ - related
20
+ - not_equal
21
+ type:
22
+ - authoritative
23
+ - lineage
24
+
25
+ designation:
26
+ base:
27
+ normative_status:
28
+ - preferred
29
+ - deprecated
30
+ - admitted
31
+ - <símbolo> # in iev-data => '<symbol>'
32
+ - 티에스 # in iev-data => translates to 'TS' I think it is a synonym and not status.
33
+ - prąd startowy # in iev-data => 'starting current' I think it is a synonym and not status.
34
+
35
+ related_concept:
36
+ type:
37
+ - deprecates
38
+ - supersedes
39
+ - superseded_by
40
+ - narrower
41
+ - broader
42
+ - equivalent
43
+ - compare
44
+ - contrast
45
+ - see
46
+
47
+ abbreviation:
48
+ type:
49
+ - truncation
50
+ - acronym
51
+ - initialism
52
+
53
+ grammar_info:
54
+ boolean_attribute:
55
+ - preposition
56
+ - participle
57
+ - adj
58
+ - verb
59
+ - adverb
60
+ - noun
61
+ gender:
62
+ - m
63
+ - f
64
+ - n
65
+ - c
66
+ number:
67
+ - singular
68
+ - dual
69
+ - plural
70
+
71
+ concept:
72
+ status:
73
+ - draft
74
+ - not_valid
75
+ - valid
76
+ - superseded
77
+ - retired
78
+
79
+ concept_date:
80
+ type:
81
+ - accepted
82
+ - amended
83
+ - retired
data/exe/glossarist ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/glossarist"
4
+
5
+ class GlossaristCommand < Thor
6
+ desc "generate_latex", "Convert Concepts to Latex format"
7
+
8
+ option :concepts_path, aliases: :p, required: true, desc: "Path to yaml concepts directory"
9
+ option :latex_concepts, aliases: :l, desc: "File path having list of concepts that should be converted to LATEX format. If not provided all the concepts will be converted to the latex format"
10
+ option :output_file, aliases: :o, desc: "Output file path. By default the output will pe printed to the console"
11
+ option :extra_attributes, aliases: :e, type: :array, desc: "List of extra attributes that are not in standard Glossarist Concept model"
12
+ def generate_latex
13
+ assets = []
14
+ latex_concepts_file = options[:latex_concepts]
15
+
16
+ if options[:extra_attributes]
17
+ Glossarist.configure do |config|
18
+ config.register_extension_attributes(options[:extra_attributes])
19
+ end
20
+ end
21
+
22
+ concept_set = Glossarist::ConceptSet.new(options[:concepts_path], assets)
23
+ latex_str = concept_set.to_latex(latex_concepts_file)
24
+
25
+ output_file_path = options[:output_file]
26
+ if output_file_path
27
+ File.open(output_file_path, "w") do |file|
28
+ file.puts latex_str
29
+ end
30
+ else
31
+ puts latex_str
32
+ end
33
+ end
34
+
35
+ def method_missing(*args)
36
+ warn "No method found named: #{args[0]}"
37
+ warn "Run with `--help` or `-h` to see available options"
38
+ exit 1
39
+ end
40
+
41
+ def respond_to_missing?
42
+ true
43
+ end
44
+
45
+ def self.exit_on_failure?
46
+ true
47
+ end
48
+ end
49
+
50
+ GlossaristCommand.start(ARGV)
data/glossarist.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  "Concept models for terminology glossaries conforming ISO 10241-1."
17
17
  spec.homepage = "https://github.com/glossarist/glossarist-ruby"
18
18
  spec.license = "BSD-2-Clause"
19
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
19
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
20
20
 
21
21
  spec.metadata["homepage_uri"] = spec.homepage
22
22
  spec.metadata["source_code_uri"] = spec.homepage
@@ -30,6 +30,9 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ["lib"]
32
32
 
33
+ spec.add_dependency "relaton", "~>1.13.0"
34
+ spec.add_dependency "thor"
35
+
33
36
  spec.add_development_dependency "pry", "~> 0.14.0"
34
37
  spec.add_development_dependency "rake", "~> 13.0"
35
38
  spec.add_development_dependency "rspec", "~> 3.10"
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ module Glossarist
7
+ class Asset
8
+ attr_accessor :path
9
+
10
+ def initialize(path)
11
+ @path = path
12
+ end
13
+
14
+ def eql?(asset)
15
+ path == asset.path
16
+ end
17
+
18
+ def hash
19
+ path.hash
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ module Glossarist
7
+ class Citation < Model
8
+ # Unstructured (plain text) reference.
9
+ # @return [String]
10
+ attr_accessor :text
11
+
12
+ # Source in structured reference.
13
+ # @return [String]
14
+ attr_accessor :source
15
+
16
+ # Document ID in structured reference.
17
+ # @return [String]
18
+ attr_accessor :id
19
+
20
+ # Document version in structured reference.
21
+ # @return [String]
22
+ attr_accessor :version
23
+
24
+ # @return [String]
25
+ # Referred clause of the document.
26
+ attr_accessor :clause
27
+
28
+ # Link to document.
29
+ # @return [String]
30
+ attr_accessor :link
31
+
32
+ # Original ref text before parsing.
33
+ # @return [String]
34
+ # @note This attribute is likely to be removed or reworked in future.
35
+ # It is arguably not relevant to Glossarist itself.
36
+ attr_accessor :original
37
+
38
+ # Whether it is a plain text ref.
39
+ # @return [Boolean]
40
+ def plain?
41
+ (source && id && version).nil?
42
+ end
43
+
44
+ # Whether it is a structured ref.
45
+ # @return [Boolean]
46
+ def structured?
47
+ !plain?
48
+ end
49
+
50
+ def to_h
51
+ {
52
+ "ref" => ref_to_h,
53
+ "clause" => clause,
54
+ "link" => link,
55
+ "original" => original,
56
+ }.compact
57
+ end
58
+
59
+ def self.from_h(hash)
60
+ hash = hash.dup
61
+
62
+ ref_val = hash.delete("ref")
63
+ hash.merge!(Hash === ref_val ? ref_val : {"text" => ref_val})
64
+ hash.compact!
65
+
66
+ super(hash)
67
+ end
68
+
69
+ def ref=(ref)
70
+ if ref.is_a?(Hash)
71
+ @source = ref["source"]
72
+ @id = ref["id"]
73
+ @version = ref["version"]
74
+ else
75
+ @text = ref
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def ref_to_h
82
+ if structured?
83
+ { "source" => source, "id" => id, "version" => version }.compact
84
+ else
85
+ text
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ module Collections
5
+ class AssetCollection < Set
6
+ def initialize(assets)
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "relaton"
4
+
5
+ module Glossarist
6
+ module Collections
7
+ class BibliographyCollection < Relaton::Db
8
+ def initialize(concepts, global_cache, local_cache)
9
+ super(global_cache, local_cache)
10
+ end
11
+
12
+ private
13
+
14
+ def populate_bibliographies(concepts)
15
+ concepts.each do |concept|
16
+ concept.default_lang.sources.each do |source|
17
+ next if source.origin.text.nil?
18
+
19
+ fetch(source.origin.text)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ require_relative "collections/asset_collection"
2
+ require_relative "collections/bibliography_collection"
@@ -8,44 +8,108 @@ module Glossarist
8
8
  # Concept ID.
9
9
  # @return [String]
10
10
  attr_accessor :id
11
+ alias :termid= :id=
11
12
 
12
- # All localizations for this concept.
13
- #
14
- # Keys are language codes and values are instances of {LocalizedConcept}.
15
- # @return [Hash<String, LocalizedConcept>]
16
- attr_reader :localizations
13
+ # Concept designations.
14
+ # @todo Alias +terms+ exists only for legacy reasons and will be removed.
15
+ # @return [Array<Designations::Base>]
16
+ attr_reader :designations
17
+ alias :terms :designations
18
+
19
+ # <<BasicDocument>>LocalizedString
20
+ # @return [String]
21
+ attr_accessor :domain
22
+
23
+ # <<BasicDocument>>LocalizedString
24
+ # @return [String]
25
+ attr_accessor :subject
26
+
27
+ # Concept definition.
28
+ # @return [Array<DetailedDefinition>]
29
+ attr_reader :definition
30
+
31
+ # Non verbal representation of the concept.
32
+ # @return [NonVerbRep]
33
+ attr_accessor :non_verb_rep
34
+
35
+ # Concept notes
36
+ # @return [Array<DetailedDefinition>]
37
+ attr_reader :notes
38
+
39
+ # Concept examples
40
+ # @return [Array<DetailedDefinition>]
41
+ attr_reader :examples
42
+
43
+ # Contains list of extended attributes
44
+ attr_accessor :extension_attributes
17
45
 
18
46
  def initialize(*)
19
47
  @localizations = {}
48
+ @sources = []
49
+ @related = []
50
+ @notes = []
51
+ @designations = []
52
+ @extension_attributes = {}
53
+
20
54
  super
21
55
  end
22
56
 
23
- # Adds concept localization.
24
- # @param localized_concept [LocalizedConcept]
25
- def add_localization(localized_concept)
26
- lang = localized_concept.language_code
27
- localizations.store(lang, localized_concept)
57
+ # List of authorative sources.
58
+ # @todo Alias +authoritative_source+ exists for legacy reasons and may be
59
+ # removed.
60
+ # @return [Array<ConceptSource>]
61
+ attr_reader :sources
62
+ alias :authoritative_source :sources
63
+
64
+ # return [Array<ConceptDate>]
65
+ attr_reader :dates
66
+
67
+ def examples=(examples)
68
+ @examples = examples&.map { |e| DetailedDefinition.new(e) }
28
69
  end
29
70
 
30
- alias :add_l10n :add_localization
71
+ def notes=(notes)
72
+ @notes = notes&.map { |n| DetailedDefinition.new(n) }
73
+ end
74
+
75
+ def definition=(definition)
76
+ @definition = definition&.map { |d| DetailedDefinition.new(d) }
77
+ end
31
78
 
32
- # Returns concept localization.
33
- # @param lang [String] language code
34
- # @return [LocalizedConcept]
35
- def localization(lang)
36
- localizations[lang]
79
+ def designations=(designations)
80
+ @designations = designations&.map do |designation|
81
+ Designation::Base.from_h(designation)
82
+ end
37
83
  end
38
84
 
39
- alias :l10n :localization
85
+ alias :terms= :designations=
86
+
87
+ def dates=(dates)
88
+ @dates = dates&.map { |d| ConceptDate.new(d) }
89
+ end
90
+
91
+ def sources=(sources)
92
+ @sources = sources&.map do |source|
93
+ ConceptSource.new(source)
94
+ end || []
95
+ end
96
+
97
+ def authoritative_source=(sources)
98
+ self.sources = sources&.map do |source|
99
+ source.merge({ "type" => "authoritative" })
100
+ end
101
+ end
40
102
 
41
103
  def to_h
42
104
  {
43
- "termid" => id,
44
- "term" => default_designation,
45
- "related" => related_concepts,
105
+ "id" => id,
106
+ "related" => related&.map(&:to_h),
107
+ "terms" => (terms&.map(&:to_h) || []),
108
+ "definition" => definition&.map(&:to_h),
109
+ "notes" => notes&.map(&:to_h),
110
+ "examples" => examples&.map(&:to_h),
46
111
  }
47
112
  .compact
48
- .merge(localizations.transform_values(&:to_h))
49
113
  end
50
114
 
51
115
  # @deprecated For legacy reasons only.
@@ -56,27 +120,28 @@ module Glossarist
56
120
  def self.from_h(hash)
57
121
  new.tap do |concept|
58
122
  concept.id = hash.dig("termid")
123
+ concept.sources = hash.dig("sources")
124
+ concept.related = hash.dig("related")
125
+ concept.definition = hash.dig("definition")
59
126
 
60
127
  hash.values
61
128
  .grep(Hash)
62
- .map { |subhash| LocalizedConcept.from_h(subhash) rescue nil }
129
+ .map { |subhash| Config.class_for(:localized_concept).from_h(subhash) rescue nil }
63
130
  .compact
64
- .each { |lc| concept.add_l10n lc }
65
131
 
66
- concept.l10n("eng")&.superseded_concepts = hash.dig("related") || []
132
+ concept.related = hash.dig("related") || []
67
133
  end
68
134
  end
69
135
  # rubocop:enable Metrics/AbcSize, Style/RescueModifier
70
136
 
71
- def default_designation
72
- localized = localization("eng") || localizations.values.first
73
- localized&.terms&.first&.designation
137
+ # All Related Concepts
138
+ # @return [Array<RelatedConcept>]
139
+ def related
140
+ @related.empty? ? nil : @related
74
141
  end
75
142
 
76
- def related_concepts
77
- # TODO Someday other relation types too
78
- arr = [localization("eng")&.superseded_concepts].flatten.compact
79
- arr.empty? ? nil : arr
143
+ def related=(related)
144
+ @related = related&.map { |r| RelatedConcept.new(r) } || []
80
145
  end
81
146
  end
82
147
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ class ConceptDate < Model
5
+ include Glossarist::Utilities::Enum
6
+
7
+ # Iso8601 date
8
+ # @return [String]
9
+ attr_accessor :date
10
+
11
+ register_enum :type, Glossarist::GlossaryDefinition::CONCEPT_DATE_TYPES
12
+
13
+ def to_h
14
+ {
15
+ "type" => type,
16
+ "date" => date,
17
+ }.compact
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ class ConceptManager
5
+ # Path to concepts directory.
6
+ # @return [String]
7
+ attr_accessor :path
8
+
9
+ # @param path [String]
10
+ # concepts directory path, either absolute or relative to CWD
11
+ def initialize(path: nil)
12
+ @path = path
13
+ end
14
+
15
+ # Reads all concepts from files.
16
+ def load_from_files(collection: nil)
17
+ collection ||= ManagedConceptCollection.new
18
+
19
+ Dir.glob(concepts_glob) do |filename|
20
+ collection.store(load_concept_from_file(filename))
21
+ end
22
+ end
23
+
24
+ # Writes all concepts to files.
25
+ def save_to_files(managed_concepts)
26
+ managed_concepts.each_value &method(:save_concept_to_file)
27
+ end
28
+
29
+ def load_concept_from_file(filename)
30
+ ManagedConcept.new(Psych.safe_load(File.read(filename)))
31
+ end
32
+
33
+ def save_concept_to_file(concept)
34
+ filename = File.join(path, "concept-#{concept.id}.yaml")
35
+ File.write(filename, Psych.dump(concept.to_h))
36
+ end
37
+
38
+ private
39
+
40
+ def concepts_glob
41
+ File.join(path, "concept-*.{yaml,yml}")
42
+ end
43
+ end
44
+ end