glossarist-new 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +15 -0
- data/.github/workflows/test.yml +34 -0
- data/.gitignore +18 -0
- data/.hound.yml +3 -0
- data/.rspec +3 -0
- data/.rubocop.yml +35 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +23 -0
- data/README.adoc +11 -0
- data/Rakefile +8 -0
- data/config.yml +83 -0
- data/glossarist.gemspec +36 -0
- data/lib/glossarist/citation.rb +85 -0
- data/lib/glossarist/collection.rb +86 -0
- data/lib/glossarist/concept.rb +143 -0
- data/lib/glossarist/concept_date.rb +20 -0
- data/lib/glossarist/concept_manager.rb +44 -0
- data/lib/glossarist/concept_source.rb +62 -0
- data/lib/glossarist/designation/abbreviation.rb +23 -0
- data/lib/glossarist/designation/base.rb +37 -0
- data/lib/glossarist/designation/expression.rb +50 -0
- data/lib/glossarist/designation/grammar_info.rb +58 -0
- data/lib/glossarist/designation/graphical_symbol.rb +17 -0
- data/lib/glossarist/designation/letter_symbol.rb +19 -0
- data/lib/glossarist/designation/symbol.rb +21 -0
- data/lib/glossarist/designation.rb +27 -0
- data/lib/glossarist/detailed_definition.rb +31 -0
- data/lib/glossarist/glossary_definition.rb +29 -0
- data/lib/glossarist/localized_concept.rb +61 -0
- data/lib/glossarist/managed_concept.rb +107 -0
- data/lib/glossarist/managed_concept_collection.rb +79 -0
- data/lib/glossarist/model.rb +29 -0
- data/lib/glossarist/non_verb_rep.rb +18 -0
- data/lib/glossarist/related_concept.rb +31 -0
- data/lib/glossarist/utilities/boolean_attributes.rb +35 -0
- data/lib/glossarist/utilities/common_functions.rb +29 -0
- data/lib/glossarist/utilities/enum/class_methods.rb +99 -0
- data/lib/glossarist/utilities/enum/enum_collection.rb +45 -0
- data/lib/glossarist/utilities/enum/instance_methods.rb +55 -0
- data/lib/glossarist/utilities/enum.rb +21 -0
- data/lib/glossarist/utilities.rb +5 -0
- data/lib/glossarist/version.rb +8 -0
- data/lib/glossarist.rb +31 -0
- metadata +131 -0
@@ -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,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
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) Copyright 2021 Ribose Inc.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Glossarist
|
7
|
+
class LocalizedConcept < Concept
|
8
|
+
# ISO 639-2 code for terminology.
|
9
|
+
# @see https://www.loc.gov/standards/iso639-2/php/code_list.php code list
|
10
|
+
# @return [String]
|
11
|
+
attr_accessor :language_code
|
12
|
+
|
13
|
+
# Must be one of the following:
|
14
|
+
# +notValid+, +valid+, +superseded+, +retired+.
|
15
|
+
# @todo Proper type checking.
|
16
|
+
# @note Works with strings, but soon they may be replaced with symbols.
|
17
|
+
# @return [String]
|
18
|
+
attr_accessor :entry_status
|
19
|
+
|
20
|
+
# Must be one of the following:
|
21
|
+
# +preferred+, +admitted+, +deprecated+.
|
22
|
+
# @todo Proper type checking.
|
23
|
+
# @note Works with strings, but soon they may be replaced with symbols.
|
24
|
+
# @return [String]
|
25
|
+
attr_accessor :classification
|
26
|
+
|
27
|
+
attr_accessor :review_date
|
28
|
+
attr_accessor :review_decision_date
|
29
|
+
attr_accessor :review_decision_event
|
30
|
+
|
31
|
+
def initialize(*)
|
32
|
+
@examples = []
|
33
|
+
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_h # rubocop:disable Metrics/MethodLength
|
38
|
+
super.merge({
|
39
|
+
"language_code" => language_code,
|
40
|
+
"entry_status" => entry_status,
|
41
|
+
"sources" => sources.empty? ? nil : sources&.map(&:to_h),
|
42
|
+
"classification" => classification,
|
43
|
+
"dates" => dates&.map(&:to_h),
|
44
|
+
"review_date" => review_date,
|
45
|
+
"review_decision_date" => review_decision_date,
|
46
|
+
"review_decision_event" => review_decision_event,
|
47
|
+
}.compact)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.from_h(hash)
|
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}))
|
55
|
+
end
|
56
|
+
|
57
|
+
# @deprecated For legacy reasons only.
|
58
|
+
# Implicit conversion (i.e. {#to_hash} alias) will be removed soon.
|
59
|
+
alias :to_hash :to_h
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Glossarist
|
4
|
+
class ManagedConcept < Model
|
5
|
+
include Glossarist::Utilities::Enum
|
6
|
+
include Glossarist::Utilities::CommonFunctions
|
7
|
+
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :id
|
10
|
+
alias :termid= :id=
|
11
|
+
|
12
|
+
# @return [Array<RelatedConcept>]
|
13
|
+
attr_reader :related
|
14
|
+
|
15
|
+
# @return [String]
|
16
|
+
register_enum :status, Glossarist::GlossaryDefinition::CONCEPT_STATUSES
|
17
|
+
|
18
|
+
# return [Array<ConceptDate>]
|
19
|
+
attr_reader :dates
|
20
|
+
|
21
|
+
# return [Array<LocalizedConcept>]
|
22
|
+
attr_reader :localized_concepts
|
23
|
+
|
24
|
+
# All localizations for this concept.
|
25
|
+
#
|
26
|
+
# Keys are language codes and values are instances of {LocalizedConcept}.
|
27
|
+
# @return [Hash<String, LocalizedConcept>]
|
28
|
+
attr_accessor :localizations
|
29
|
+
|
30
|
+
def initialize(attributes = {})
|
31
|
+
@localizations = {}
|
32
|
+
self.localized_concepts = attributes.values.grep(Hash)
|
33
|
+
|
34
|
+
attributes = symbolize_keys(attributes)
|
35
|
+
super(slice_keys(attributes, managed_concept_attributes))
|
36
|
+
end
|
37
|
+
|
38
|
+
def localized_concepts=(localized_concepts_hash)
|
39
|
+
@localized_concepts = localized_concepts_hash.map { |l| LocalizedConcept.new(l) }.compact
|
40
|
+
|
41
|
+
@localized_concepts.each do |l|
|
42
|
+
add_l10n(l)
|
43
|
+
end
|
44
|
+
|
45
|
+
@localized_concepts
|
46
|
+
end
|
47
|
+
|
48
|
+
def related=(related)
|
49
|
+
@related = related&.map { |r| RelatedConcept.new(r) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def dates=(dates)
|
53
|
+
@dates = dates&.map { |d| ConceptDate.new(d) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Adds concept localization.
|
57
|
+
# @param localized_concept [LocalizedConcept]
|
58
|
+
def add_localization(localized_concept)
|
59
|
+
lang = localized_concept.language_code
|
60
|
+
localizations.store(lang, localized_concept)
|
61
|
+
end
|
62
|
+
|
63
|
+
alias :add_l10n :add_localization
|
64
|
+
|
65
|
+
# Returns concept localization.
|
66
|
+
# @param lang [String] language code
|
67
|
+
# @return [LocalizedConcept]
|
68
|
+
def localization(lang)
|
69
|
+
localizations[lang]
|
70
|
+
end
|
71
|
+
|
72
|
+
alias :l10n :localization
|
73
|
+
|
74
|
+
def to_h
|
75
|
+
{
|
76
|
+
"termid" => id,
|
77
|
+
"term" => default_designation,
|
78
|
+
"related" => related&.map(&:to_h),
|
79
|
+
"dates" => dates&.empty? ? nil : dates&.map(&:to_h),
|
80
|
+
}.merge(localizations.transform_values(&:to_h)).compact
|
81
|
+
end
|
82
|
+
|
83
|
+
def default_designation
|
84
|
+
localized = localization("eng") || localizations.values.first
|
85
|
+
localized&.terms&.first&.designation
|
86
|
+
end
|
87
|
+
|
88
|
+
def managed_concept_attributes
|
89
|
+
%i[
|
90
|
+
id
|
91
|
+
termid
|
92
|
+
related
|
93
|
+
status
|
94
|
+
dates
|
95
|
+
localized_concepts
|
96
|
+
].compact
|
97
|
+
end
|
98
|
+
|
99
|
+
Glossarist::GlossaryDefinition::RELATED_CONCEPT_TYPES.each do |type|
|
100
|
+
# List of related concepts of the specified type.
|
101
|
+
# @return [Array<RelatedConcept>]
|
102
|
+
define_method("#{type}_concepts") do
|
103
|
+
related&.select { |concept| concept.type == type.to_s } || []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Glossarist
|
4
|
+
class ManagedConceptCollection
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@managed_concepts = {}
|
9
|
+
@concept_manager = ConceptManager.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Array<ManagedConcept>]
|
13
|
+
def managed_concepts
|
14
|
+
@managed_concepts.values
|
15
|
+
end
|
16
|
+
|
17
|
+
def managed_concepts=(managed_concepts = [])
|
18
|
+
managed_concepts.each do |managed_concept|
|
19
|
+
store(ManagedConcept.new(managed_concept))
|
20
|
+
end
|
21
|
+
|
22
|
+
@managed_concepts.values
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_h
|
26
|
+
{
|
27
|
+
"managed_concepts" => managed_concepts.map(&:to_h),
|
28
|
+
}.compact
|
29
|
+
end
|
30
|
+
|
31
|
+
def each(&block)
|
32
|
+
@managed_concepts.each_value(&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns concept with given ID, if it is present in collection, or +nil+
|
36
|
+
# otherwise.
|
37
|
+
#
|
38
|
+
# @param id [String]
|
39
|
+
# ManagedConcept ID
|
40
|
+
# @return [ManagedConcept, nil]
|
41
|
+
def fetch(id)
|
42
|
+
@managed_concepts[id]
|
43
|
+
end
|
44
|
+
|
45
|
+
alias :[] :fetch
|
46
|
+
|
47
|
+
# If ManagedConcept with given ID is present in this collection, then
|
48
|
+
# returns it. Otherwise, instantiates a new ManagedConcept, adds it to
|
49
|
+
# the collection, and returns it.
|
50
|
+
#
|
51
|
+
# @param id [String]
|
52
|
+
# ManagedConcept ID
|
53
|
+
# @return [ManagedConcept]
|
54
|
+
def fetch_or_initialize(id)
|
55
|
+
fetch(id) or store(ManagedConcept.new(id: id))
|
56
|
+
end
|
57
|
+
|
58
|
+
# Adds concept to the collection. If collection contains a concept with
|
59
|
+
# the same ID already, that concept is replaced.
|
60
|
+
#
|
61
|
+
# @param managed_concept [ManagedConcept]
|
62
|
+
# ManagedConcept about to be added
|
63
|
+
def store(managed_concept)
|
64
|
+
@managed_concepts[managed_concept.id] = managed_concept
|
65
|
+
end
|
66
|
+
|
67
|
+
alias :<< :store
|
68
|
+
|
69
|
+
def load_from_files(path)
|
70
|
+
@concept_manager.path = path
|
71
|
+
@concept_manager.load_from_files(collection: self)
|
72
|
+
end
|
73
|
+
|
74
|
+
def save_to_files(path)
|
75
|
+
@concept_manager.path = path
|
76
|
+
@concept_manager.save_to_files(@managed_concepts)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# (c) Copyright 2021 Ribose Inc.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Glossarist
|
7
|
+
class Model
|
8
|
+
def self.new(params = {})
|
9
|
+
return params if params.is_a?(self)
|
10
|
+
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(attributes = {})
|
15
|
+
attributes.each_pair { |k, v| set_attribute(k, v) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_attribute(name, value)
|
19
|
+
public_send("#{name}=", value)
|
20
|
+
rescue NoMethodError
|
21
|
+
raise ArgumentError, "#{self.class.name} does not have " +
|
22
|
+
"attribute #{name} defined or the attribute is read only."
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_h(hash)
|
26
|
+
new(hash)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Glossarist
|
4
|
+
class NonVerbRep
|
5
|
+
attr_accessor :image
|
6
|
+
attr_accessor :table
|
7
|
+
attr_accessor :formula
|
8
|
+
|
9
|
+
# @return [Array<ConceptSource>]
|
10
|
+
attr_reader :sources
|
11
|
+
|
12
|
+
def sources=(sources)
|
13
|
+
@sources = sources&.map do |source|
|
14
|
+
ConceptSource.new(source)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|