Skip to content

Commit 4dc8cf4

Browse files
committed
Add TYPES constant and .entailed_term factory to TermNote
- Add TYPES hash with standard DCA termNote type values (usageStatus, termType, grammaticalGender, grammaticalNumber, partOfSpeech, entailedTerm) per ISO 30042:2019 - Add .entailed_term class method for creating cross-reference termNotes with type and target attributes - Add comprehensive spec with 14 tests covering types, serialization, and round-trip
1 parent 446d878 commit 4dc8cf4

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

lib/tbx/term_note.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
module Tbx
44
class TermNote < Lutaml::Model::Serializable
5+
# Standard DCA termNote type values per ISO 30042:2019
6+
TYPES = {
7+
usage_status: "usageStatus",
8+
term_type: "termType",
9+
grammatical_gender: "grammaticalGender",
10+
grammatical_number: "grammaticalNumber",
11+
part_of_speech: "partOfSpeech",
12+
entailed_term: "entailedTerm",
13+
}.freeze
14+
515
attribute :id, :string
616
attribute :lang, Lutaml::Xml::W3c::XmlLangType
717
attribute :target, :string
@@ -31,5 +41,13 @@ class TermNote < Lutaml::Model::Serializable
3141
map_element "ph", to: :ph
3242
map_element "sc", to: :sc
3343
end
44+
45+
class << self
46+
def entailed_term(target:, content: nil)
47+
opts = { type: TYPES[:entailed_term], target: target }
48+
opts[:content] = [content] if content
49+
new(**opts)
50+
end
51+
end
3452
end
3553
end

spec/tbx/term_note_spec.rb

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
RSpec.describe Tbx::TermNote do
6+
describe "TYPES constants" do
7+
it "defines usageStatus type" do
8+
expect(described_class::TYPES[:usage_status]).to eq("usageStatus")
9+
end
10+
11+
it "defines termType type" do
12+
expect(described_class::TYPES[:term_type]).to eq("termType")
13+
end
14+
15+
it "defines grammaticalGender type" do
16+
expect(described_class::TYPES[:grammatical_gender]).to eq("grammaticalGender")
17+
end
18+
19+
it "defines grammaticalNumber type" do
20+
expect(described_class::TYPES[:grammatical_number]).to eq("grammaticalNumber")
21+
end
22+
23+
it "defines partOfSpeech type" do
24+
expect(described_class::TYPES[:part_of_speech]).to eq("partOfSpeech")
25+
end
26+
27+
it "defines entailedTerm type" do
28+
expect(described_class::TYPES[:entailed_term]).to eq("entailedTerm")
29+
end
30+
end
31+
32+
describe ".entailed_term" do
33+
it "creates a termNote with entailedTerm type and target" do
34+
note = described_class.entailed_term(target: "c1")
35+
expect(note.type).to eq("entailedTerm")
36+
expect(note.target).to eq("c1")
37+
expect(note.content).to be_nil
38+
end
39+
40+
it "creates a termNote with content" do
41+
note = described_class.entailed_term(target: "c2", content: "related term")
42+
expect(note.type).to eq("entailedTerm")
43+
expect(note.target).to eq("c2")
44+
expect(note.content).to eq(["related term"])
45+
end
46+
47+
it "serializes to valid XML" do
48+
note = described_class.entailed_term(target: "c1", content: "term text")
49+
xml = note.to_xml
50+
doc = Nokogiri::XML(xml)
51+
expect(doc.errors).to be_empty
52+
el = doc.at_xpath("//tbx:termNote", "tbx" => Tbx::Namespace.uri)
53+
expect(el["type"]).to eq("entailedTerm")
54+
expect(el["target"]).to eq("c1")
55+
expect(el.text).to eq("term text")
56+
end
57+
58+
it "serializes without content" do
59+
note = described_class.entailed_term(target: "c1")
60+
xml = note.to_xml
61+
doc = Nokogiri::XML(xml)
62+
el = doc.at_xpath("//tbx:termNote", "tbx" => Tbx::Namespace.uri)
63+
expect(el["type"]).to eq("entailedTerm")
64+
expect(el["target"]).to eq("c1")
65+
end
66+
67+
it "round-trips through XML" do
68+
original = described_class.entailed_term(target: "c3", content: "another term")
69+
xml = original.to_xml
70+
parsed = described_class.from_xml(xml)
71+
expect(parsed.type).to eq("entailedTerm")
72+
expect(parsed.target).to eq("c3")
73+
expect(parsed.content.join).to eq("another term")
74+
end
75+
end
76+
77+
describe "standard termNote creation" do
78+
it "creates a usageStatus note" do
79+
note = described_class.new(type: described_class::TYPES[:usage_status], content: ["admittedTerm"])
80+
expect(note.type).to eq("usageStatus")
81+
expect(note.content).to eq(["admittedTerm"])
82+
end
83+
84+
it "creates a termType note" do
85+
note = described_class.new(type: described_class::TYPES[:term_type], content: ["fullForm"])
86+
expect(note.type).to eq("termType")
87+
end
88+
89+
it "creates a grammaticalGender note" do
90+
note = described_class.new(type: described_class::TYPES[:grammatical_gender], content: ["masculine"])
91+
expect(note.type).to eq("grammaticalGender")
92+
end
93+
end
94+
end

0 commit comments

Comments
 (0)