glossarist 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 34ea633c0a5f8f609e12c72d8a835fd8675f8cf52996633ed9c84c9d304f73cc
4
+ data.tar.gz: a855be248a3ae9d9435969643660210a30ae1f7912b0c714ed4a7d1ee09632f3
5
+ SHA512:
6
+ metadata.gz: b98c00342f4107b361ddc27f7e6323540c1335a339b54594c7944a4d45e1dcf4746070f38cd91934320a39d2616305055f9cf62b88253deb1842686f238cbed1
7
+ data.tar.gz: 8ec6121d3a5dd24e3c032bf92ab4e31ceefaf451aa81bf8f395c4d78e34e2ec1c594173f997c646af9f2a5b094db490a9f3fdcec1f8d4a57b8c79afa5107aa7b
data/.editorconfig ADDED
@@ -0,0 +1,15 @@
1
+ # EditorConfig is awesome: http://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ # Unix-style newlines with a newline ending every file
7
+ [*]
8
+ charset = utf-8
9
+ end_of_line = lf
10
+
11
+ [{*.adoc,*.html,*.js,*.json,*.rake,*.rb,*.rf,*.yaml,*.yml,Rakefile,rakefile}]
12
+ indent_style = space
13
+ indent_size = 2
14
+ insert_final_newline = true
15
+ trim_trailing_whitespace = true
@@ -0,0 +1,37 @@
1
+ name: Test
2
+
3
+ on:
4
+ - push
5
+ - pull_request
6
+ - workflow_dispatch
7
+
8
+ jobs:
9
+ build:
10
+ name: Ruby ${{ matrix.ruby }}
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby:
17
+ - "3.0"
18
+ - "2.7"
19
+ - "2.6"
20
+ - "2.5"
21
+ - "2.4"
22
+
23
+ name: Run tests
24
+ runs-on: ubuntu-latest
25
+
26
+ steps:
27
+ - name: Fetch source code
28
+ uses: actions/checkout@v2
29
+
30
+ - name: Set up Ruby
31
+ uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{ matrix.ruby }}
34
+ bundler-cache: true
35
+
36
+ - name: Run tests
37
+ run: bundle exec rspec
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ /Gemfile.lock
11
+
12
+ # RSpec failure tracking
13
+ .rspec_status
14
+
15
+ # RuboCop caches
16
+ .rubocop-http---*
17
+ .rubocop-https---*
18
+
data/.hound.yml ADDED
@@ -0,0 +1,3 @@
1
+ ruby:
2
+ enabled: true
3
+ config_file: .rubocop.yml
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ inherit_from:
2
+ - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
3
+
4
+ # local repo-specific modifications
5
+
6
+ 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
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2021, Ribose
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.adoc ADDED
@@ -0,0 +1,11 @@
1
+ = Glossarist
2
+
3
+ == Credits
4
+
5
+ This gem is developed, maintained and funded by
6
+ https://www.ribose.com[Ribose Inc.]
7
+
8
+ == License
9
+
10
+ The gem is available as open source under the terms of the
11
+ https://opensource.org/licenses/BSD-2-Clause[2-Clause BSD License].
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/glossarist/version"
4
+
5
+ all_files_in_git = Dir.chdir(File.expand_path(__dir__)) do
6
+ `git ls-files -z`.split("\x0")
7
+ end
8
+
9
+ Gem::Specification.new do |spec|
10
+ spec.name = "glossarist"
11
+ spec.version = Glossarist::VERSION
12
+ spec.authors = ["Ribose"]
13
+ spec.email = ["open.source@ribose.com"]
14
+
15
+ spec.summary =
16
+ "Concept models for terminology glossaries conforming ISO 10241-1."
17
+ spec.homepage = "https://github.com/glossarist/glossarist-ruby"
18
+ spec.license = "BSD-2-Clause"
19
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
20
+
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = spec.homepage
23
+ spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ spec.files = all_files_in_git
27
+ .reject { |f| f.match(%r{\A(?:test|spec|features|bin|\.)/}) }
28
+
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "pry", "~> 0.14.0"
34
+ spec.add_development_dependency "rake", "~> 13.0"
35
+ spec.add_development_dependency "rspec", "~> 3.10"
36
+ end
data/lib/glossarist.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ require "psych"
7
+
8
+ require_relative "glossarist/version"
9
+
10
+ require_relative "glossarist/model"
11
+ require_relative "glossarist/concept"
12
+ require_relative "glossarist/collection"
13
+ require_relative "glossarist/localized_concept"
14
+
15
+ module Glossarist
16
+ class Error < StandardError; end
17
+ # Your code goes here...
18
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ module Glossarist
7
+ # @todo Add support for lazy concept loading.
8
+ # @todo Consider extracting persistence backend to a separate class.
9
+ class Collection
10
+ include Enumerable
11
+
12
+ # Path to concepts directory.
13
+ # @return [String]
14
+ attr_accessor :path
15
+
16
+ # @param path [String]
17
+ # concepts directory path, either absolute or relative to CWD
18
+ def initialize(path: nil)
19
+ @path = path
20
+ @index = {}
21
+ end
22
+
23
+ def each(&block)
24
+ @index.each_value(&block)
25
+ end
26
+
27
+ # Returns concept with given ID, if it is present in collection, or +nil+
28
+ # otherwise.
29
+ #
30
+ # @param id [String]
31
+ # Concept ID
32
+ # @return [Concept, nil]
33
+ def fetch(id)
34
+ @index[id]
35
+ end
36
+
37
+ alias :[] :fetch
38
+
39
+ # If concept with given ID is present in this collection, returns that
40
+ # concept. Otherwise, instantiates a new concept, adds it to
41
+ # the collection, and returns it.
42
+ #
43
+ # @param id [String]
44
+ # Concept ID
45
+ # @return [Concept]
46
+ def fetch_or_initialize(id)
47
+ fetch(id) or store(Concept.new(id: id))
48
+ end
49
+
50
+ # Adds concept to the collection. If collection contains a concept with
51
+ # the same ID already, that concept is replaced.
52
+ #
53
+ # @param concept [Concept]
54
+ # concept about to be added
55
+ def store(concept)
56
+ @index[concept.id] = concept
57
+ end
58
+
59
+ alias :<< :store
60
+
61
+ # Reads all concepts from files.
62
+ def load_concepts
63
+ Dir.glob(concepts_glob) do |filename|
64
+ store(load_concept_from_file(filename))
65
+ end
66
+ end
67
+
68
+ private def load_concept_from_file(filename)
69
+ Concept.from_h(Psych.safe_load(File.read(filename)))
70
+ end
71
+
72
+ # Writes all concepts to files.
73
+ def save_concepts
74
+ @index.each_value &method(:save_concept_to_file)
75
+ end
76
+
77
+ private def save_concept_to_file(concept)
78
+ filename = File.join(path, "concept-#{concept.id}.yaml")
79
+ File.write(filename, Psych.dump(concept.to_h))
80
+ end
81
+
82
+ private def concepts_glob
83
+ File.join(path, "concept-*.{yaml,yml}")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ module Glossarist
7
+ class Concept < Model
8
+ # Concept ID.
9
+ # @return [String]
10
+ attr_accessor :id
11
+
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
17
+
18
+ def initialize(*)
19
+ @localizations = {}
20
+ super
21
+ end
22
+
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)
28
+ end
29
+
30
+ alias :add_l10n :add_localization
31
+
32
+ # Returns concept localization.
33
+ # @param lang [String] language code
34
+ # @return [LocalizedConcept]
35
+ def localization(lang)
36
+ localizations[lang]
37
+ end
38
+
39
+ alias :l10n :localization
40
+
41
+ def to_h
42
+ {
43
+ "termid" => id,
44
+ "term" => default_designation,
45
+ "related" => related_concepts,
46
+ **localizations.transform_values(&:to_h),
47
+ }.compact
48
+ end
49
+
50
+ # @deprecated For legacy reasons only.
51
+ # Implicit conversion (i.e. {#to_hash} alias) will be removed soon.
52
+ alias :to_hash :to_h
53
+
54
+ # rubocop:disable Metrics/AbcSize, Style/RescueModifier
55
+ def self.from_h(hash)
56
+ new.tap do |concept|
57
+ concept.id = hash.dig("termid")
58
+
59
+ hash.values
60
+ .grep(Hash)
61
+ .map { |subhash| LocalizedConcept.from_h(subhash) rescue nil }
62
+ .compact
63
+ .each { |lc| concept.add_l10n lc }
64
+
65
+ concept.l10n("eng")&.superseded_concepts = hash.dig("related_concepts")
66
+ end
67
+ end
68
+ # rubocop:enable Metrics/AbcSize, Style/RescueModifier
69
+
70
+ def default_designation
71
+ localized = localization("eng") || localizations.values.first
72
+ localized&.terms&.dig(0, "designation")
73
+ end
74
+
75
+ def related_concepts
76
+ # TODO Someday other relation types too
77
+ arr = [localization("eng")&.superseded_concepts].flatten.compact
78
+ arr.empty? ? nil : arr
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
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
+
12
+ # ISO 639-2 code for terminology.
13
+ # @see https://www.loc.gov/standards/iso639-2/php/code_list.php code list
14
+ # @return [String]
15
+ attr_accessor :language_code
16
+
17
+ # Concept designations.
18
+ # @todo Alias +terms+ exists only for legacy reasons and will be removed.
19
+ # @todo Right now accepts hashes for legacy reasons, but they will be
20
+ # replaced with dedicated classes.
21
+ # @return [Array<Hash>]
22
+ attr_accessor :designations
23
+ alias :terms :designations
24
+ alias :terms= :designations=
25
+
26
+ # @return [Array<String>]
27
+ attr_accessor :notes
28
+
29
+ # @return [Array<String>]
30
+ attr_accessor :examples
31
+
32
+ # Concept definition.
33
+ # @todo Support multiple definitions.
34
+ # @return [String]
35
+ attr_accessor :definition
36
+
37
+ # @todo Right now accepts hashes for legacy reasons, but they will be
38
+ # replaced with dedicated classes.
39
+ # @return [Hash]
40
+ attr_accessor :authoritative_source
41
+
42
+ # Must be one of the following:
43
+ # +notValid+, +valid+, +superseded+, +retired+.
44
+ # @todo Proper type checking.
45
+ # @note Works with strings, but soon they may be replaced with symbols.
46
+ # @return [String]
47
+ attr_accessor :entry_status
48
+
49
+ # Must be one of the following:
50
+ # +preferred+, +admitted+, +deprecated+.
51
+ # @todo Proper type checking.
52
+ # @note Works with strings, but soon they may be replaced with symbols.
53
+ # @return [String]
54
+ attr_accessor :classification
55
+
56
+ attr_accessor :review_date
57
+ attr_accessor :review_decision_date
58
+ attr_accessor :review_decision_event
59
+
60
+ attr_accessor :date_accepted
61
+ attr_accessor :date_amended
62
+
63
+ # @todo Here for legacy reasons. Will be moved to Concept.
64
+ # @todo Right now is an array of hashes for legacy reasons, but these hashes
65
+ # will be replaced with some dedicated class.
66
+ # @todo Should be read-only, but for now it is not for legacy reasons.
67
+ # Don't use the setter.
68
+ # @return [Array<Hash>]
69
+ attr_accessor :superseded_concepts
70
+
71
+ def initialize(*)
72
+ @examples = []
73
+ @notes = []
74
+ @designations = []
75
+ super
76
+ end
77
+
78
+ def to_h # rubocop:disable Metrics/MethodLength
79
+ {
80
+ "id" => id,
81
+ "terms" => terms,
82
+ "definition" => definition,
83
+ "language_code" => language_code,
84
+ "notes" => notes,
85
+ "examples" => examples,
86
+ "entry_status" => entry_status,
87
+ "classification" => classification,
88
+ "authoritative_source" => authoritative_source,
89
+ "date_accepted" => date_accepted,
90
+ "date_amended" => date_amended,
91
+ "review_date" => review_date,
92
+ "review_decision_date" => review_decision_date,
93
+ "review_decision_event" => review_decision_event,
94
+ }.compact
95
+ end
96
+
97
+ # @deprecated For legacy reasons only.
98
+ # Implicit conversion (i.e. {#to_hash} alias) will be removed soon.
99
+ alias :to_hash :to_h
100
+ end
101
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ module Glossarist
7
+ class Model
8
+ def initialize(attributes = {})
9
+ attributes.each_pair { |k, v| set_attribute(k, v) }
10
+ end
11
+
12
+ def set_attribute(name, value)
13
+ public_send("#{name}=", value)
14
+ rescue NoMethodError
15
+ raise ArgumentError, "#{self.class.name} does not have " +
16
+ "attribute #{name} defined or the attribute is read only."
17
+ end
18
+
19
+ def self.from_h(hash)
20
+ new(hash)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # (c) Copyright 2021 Ribose Inc.
4
+ #
5
+
6
+ module Glossarist
7
+ VERSION = "0.1.0"
8
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: glossarist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ribose
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-06-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.14.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.14.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.10'
55
+ description:
56
+ email:
57
+ - open.source@ribose.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".editorconfig"
63
+ - ".github/workflows/test.yml"
64
+ - ".gitignore"
65
+ - ".hound.yml"
66
+ - ".rspec"
67
+ - ".rubocop.yml"
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.adoc
71
+ - Rakefile
72
+ - glossarist.gemspec
73
+ - lib/glossarist.rb
74
+ - lib/glossarist/collection.rb
75
+ - lib/glossarist/concept.rb
76
+ - lib/glossarist/localized_concept.rb
77
+ - lib/glossarist/model.rb
78
+ - lib/glossarist/version.rb
79
+ homepage: https://github.com/glossarist/glossarist-ruby
80
+ licenses:
81
+ - BSD-2-Clause
82
+ metadata:
83
+ homepage_uri: https://github.com/glossarist/glossarist-ruby
84
+ source_code_uri: https://github.com/glossarist/glossarist-ruby
85
+ bug_tracker_uri: https://github.com/glossarist/glossarist-ruby/issues
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 2.4.0
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.1.4
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Concept models for terminology glossaries conforming ISO 10241-1.
105
+ test_files: []