merriam_webster_plus 0.1.0
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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.byebug_history +256 -0
- data/.github/workflows/main.yml +21 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +68 -0
- data/LICENSE.txt +21 -0
- data/README.md +93 -0
- data/Rakefile +18 -0
- data/bin/console +15 -0
- data/bin/mwp +4 -0
- data/bin/setup +8 -0
- data/fixtures/.DS_Store +0 -0
- data/fixtures/vcr_cassettes/.DS_Store +0 -0
- data/fixtures/vcr_cassettes/empty_api_entries.yml +37 -0
- data/fixtures/vcr_cassettes/heteronym_entries.yml +277 -0
- data/fixtures/vcr_cassettes/invalid_api_entries.yml +41 -0
- data/fixtures/vcr_cassettes/invalid_dictionary_plus_lookup.yml +79 -0
- data/fixtures/vcr_cassettes/invalid_endpoint_api_entries.yml +132 -0
- data/fixtures/vcr_cassettes/main_entries_dictionary.yml +210 -0
- data/fixtures/vcr_cassettes/main_entries_thesaurus.yml +70 -0
- data/fixtures/vcr_cassettes/main_entry_dictionary.yml +210 -0
- data/fixtures/vcr_cassettes/main_entry_thesaurus.yml +70 -0
- data/fixtures/vcr_cassettes/non_heteronym_entries.yml +157 -0
- data/fixtures/vcr_cassettes/valid_api_entries.yml +210 -0
- data/fixtures/vcr_cassettes/valid_dictionary_plus_lookup.yml +277 -0
- data/fixtures/vcr_cassettes/word_medley_primary_entry_population.yml +1384 -0
- data/fixtures/vcr_cassettes/word_not_in_dictionary_primary_entry.yml +141 -0
- data/fixtures/vcr_cassettes/word_not_in_thesaurus_primary_entry.yml +144 -0
- data/lib/.DS_Store +0 -0
- data/lib/merriam_webster_plus/.DS_Store +0 -0
- data/lib/merriam_webster_plus/client.rb +88 -0
- data/lib/merriam_webster_plus/dictionary_entries.rb +41 -0
- data/lib/merriam_webster_plus/dictionary_entry.rb +124 -0
- data/lib/merriam_webster_plus/dictionary_plus.rb +46 -0
- data/lib/merriam_webster_plus/dictionary_sense.rb +57 -0
- data/lib/merriam_webster_plus/entry_audio_merger.rb +55 -0
- data/lib/merriam_webster_plus/populator.rb +31 -0
- data/lib/merriam_webster_plus/primary_entry_finder.rb +41 -0
- data/lib/merriam_webster_plus/thesaurus_entries.rb +13 -0
- data/lib/merriam_webster_plus/thesaurus_entry.rb +12 -0
- data/lib/merriam_webster_plus/thesaurus_sense.rb +47 -0
- data/lib/merriam_webster_plus/version.rb +5 -0
- data/lib/merriam_webster_plus.rb +9 -0
- data/merriam_webster_plus.gemspec +35 -0
- data/test_out.csv +11 -0
- metadata +219 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
http_interactions:
|
|
3
|
+
- request:
|
|
4
|
+
method: get
|
|
5
|
+
uri: https://www.dictionaryapi.com/api/v3/references/thesaurus/json/pardoned?key=<COLLEGIATE_THESAURUS_API_KEY>
|
|
6
|
+
body:
|
|
7
|
+
encoding: US-ASCII
|
|
8
|
+
string: ''
|
|
9
|
+
headers:
|
|
10
|
+
Accept-Encoding:
|
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
|
12
|
+
Accept:
|
|
13
|
+
- "*/*"
|
|
14
|
+
User-Agent:
|
|
15
|
+
- Ruby
|
|
16
|
+
response:
|
|
17
|
+
status:
|
|
18
|
+
code: 200
|
|
19
|
+
message: OK
|
|
20
|
+
headers:
|
|
21
|
+
Date:
|
|
22
|
+
- Tue, 21 Jun 2022 23:24:58 GMT
|
|
23
|
+
Content-Type:
|
|
24
|
+
- application/json; charset=utf-8
|
|
25
|
+
Content-Length:
|
|
26
|
+
- '1270'
|
|
27
|
+
Connection:
|
|
28
|
+
- keep-alive
|
|
29
|
+
Server:
|
|
30
|
+
- Apache
|
|
31
|
+
Cache-Control:
|
|
32
|
+
- max-age=86400, public
|
|
33
|
+
Pragma:
|
|
34
|
+
- cache
|
|
35
|
+
Vary:
|
|
36
|
+
- Accept-Encoding
|
|
37
|
+
Access-Control-Allow-Origin:
|
|
38
|
+
- "*"
|
|
39
|
+
body:
|
|
40
|
+
encoding: ASCII-8BIT
|
|
41
|
+
string: '[{"meta":{"id":"pardoned","uuid":"2ac7ae9c-5b1c-4f5a-9ff5-89ed65cd08ce","src":"coll_thes","section":"alpha","stems":["pardoned"],"syns":[["forgave"],["blinked
|
|
42
|
+
(at)","brushed (aside or off)","condoned","discounted","disregarded","excused","forgave","glossed
|
|
43
|
+
(over)","glozed (over)","ignored","overlooked","overpassed","papered over","passed
|
|
44
|
+
over","remitted","shrugged off","whitewashed","winked (at)"]],"ants":[["resented"]],"offensive":false},"hwi":{"hw":"pardoned"},"fl":"verb","sls":["past
|
|
45
|
+
tense of {d_link|pardon|pardon}"],"def":[{"sseq":[[["sense",{"sn":"1","dt":[["text","to
|
|
46
|
+
cease to have feelings of anger or bitterness toward "],["vis",[{"t":"he eventually
|
|
47
|
+
{it}pardoned{\/it} his sister after she apologized"}]]],"syn_list":[[{"wd":"forgave"}]],"rel_list":[[{"wd":"absolved"},{"wd":"acquitted"},{"wd":"cleared"},{"wd":"exculpated"},{"wd":"exonerated"},{"wd":"vindicated"}],[{"wd":"remitted"},{"wd":"shrived","wvrs":[{"wvl":"or","wva":"shrove"}]}],[{"wd":"condoned"},{"wd":"disregarded"},{"wd":"excused"},{"wd":"ignored"},{"wd":"passed
|
|
48
|
+
over"},{"wd":"shrugged off"}],[{"wd":"discharged"},{"wd":"liberated"},{"wd":"redeemed"},{"wd":"released"},{"wd":"unburdened"}]],"near_list":[[{"wd":"abhorred"},{"wd":"abominated"},{"wd":"despised"},{"wd":"detested"},{"wd":"disliked"},{"wd":"execrated"},{"wd":"hated"},{"wd":"loathed"}],[{"wd":"avenged"},{"wd":"redressed"},{"wd":"requited"},{"wd":"retaliated"},{"wd":"revenged"}],[{"wd":"disciplined"},{"wd":"penalized"},{"wd":"punished"}]],"ant_list":[[{"wd":"resented"}]]}]],[["sense",{"sn":"2","dt":[["text","to
|
|
49
|
+
dismiss as of little importance "],["vis",[{"t":"I\u0027m willing to {it}pardon{\/it}
|
|
50
|
+
a little sloppiness of dress in such a kind and loving person"}]]],"syn_list":[[{"wd":"blinked
|
|
51
|
+
(at)"},{"wd":"brushed (aside or off)"},{"wd":"condoned"},{"wd":"discounted"},{"wd":"disregarded"},{"wd":"excused"},{"wd":"forgave"},{"wd":"glossed
|
|
52
|
+
(over)"},{"wd":"glozed (over)"},{"wd":"ignored"},{"wd":"overlooked"},{"wd":"overpassed"},{"wd":"papered
|
|
53
|
+
over"},{"wd":"passed over"},{"wd":"remitted"},{"wd":"shrugged off"},{"wd":"whitewashed"},{"wd":"winked
|
|
54
|
+
(at)"}]],"rel_list":[[{"wd":"explained"},{"wd":"justified"},{"wd":"rationalized"}],[{"wd":"absolved"},{"wd":"acquitted"},{"wd":"cleared"},{"wd":"exculpated"},{"wd":"exonerated"},{"wd":"vindicated"}],[{"wd":"waived"},{"wd":"waved
|
|
55
|
+
(aside or off)"}]],"phrase_list":[[{"wd":"closed one\u0027s eyes to"},{"wd":"forgave
|
|
56
|
+
and forgot"}]],"near_list":[[{"wd":"heeded"},{"wd":"marked"},{"wd":"minded"},{"wd":"noted"},{"wd":"objected
|
|
57
|
+
(to)"}]]}]]]}],"shortdef":["to cease to have feelings of anger or bitterness
|
|
58
|
+
toward","to dismiss as of little importance"]},{"meta":{"id":"pardon","uuid":"a55237df-c637-48d1-b7ab-81eddc3dcb55","src":"coll_thes","section":"alpha","target":{"tuuid":"7e15693b-2866-457f-a3bb-d200dd996e5c","tsrc":"collegiate"},"stems":["pardon","pardoned","pardoning","pardons"],"syns":[["forgive"],["blink
|
|
59
|
+
(at)","brush (aside or off)","condone","discount","disregard","excuse","forgive","gloss
|
|
60
|
+
(over)","gloze (over)","ignore","overlook","overpass","paper over","pass over","remit","shrug
|
|
61
|
+
off","whitewash","wink (at)"]],"ants":[["resent"]],"offensive":false},"hwi":{"hw":"pardon"},"fl":"verb","def":[{"sseq":[[["sense",{"sn":"1","dt":[["text","to
|
|
62
|
+
cease to have feelings of anger or bitterness toward "],["vis",[{"t":"he eventually
|
|
63
|
+
{it}pardoned{\/it} his sister after she apologized"}]]],"syn_list":[[{"wd":"forgive"}]],"rel_list":[[{"wd":"absolve"},{"wd":"acquit"},{"wd":"clear"},{"wd":"exculpate"},{"wd":"exonerate"},{"wd":"vindicate"}],[{"wd":"remit"},{"wd":"shrive"}],[{"wd":"condone"},{"wd":"disregard"},{"wd":"excuse"},{"wd":"ignore"},{"wd":"pass
|
|
64
|
+
over"},{"wd":"shrug off"}],[{"wd":"discharge"},{"wd":"liberate"},{"wd":"redeem"},{"wd":"release"},{"wd":"unburden"}]],"near_list":[[{"wd":"abhor"},{"wd":"abominate"},{"wd":"despise"},{"wd":"detest"},{"wd":"dislike"},{"wd":"execrate"},{"wd":"hate"},{"wd":"loathe"}],[{"wd":"avenge"},{"wd":"redress"},{"wd":"requite"},{"wd":"retaliate"},{"wd":"revenge"}],[{"wd":"discipline"},{"wd":"penalize"},{"wd":"punish"}]],"ant_list":[[{"wd":"resent"}]]}]],[["sense",{"sn":"2","dt":[["text","to
|
|
65
|
+
dismiss as of little importance "],["vis",[{"t":"I\u0027m willing to {it}pardon{\/it}
|
|
66
|
+
a little sloppiness of dress in such a kind and loving person"}]]],"syn_list":[[{"wd":"blink
|
|
67
|
+
(at)"},{"wd":"brush (aside or off)"},{"wd":"condone"},{"wd":"discount"},{"wd":"disregard"},{"wd":"excuse"},{"wd":"forgive"},{"wd":"gloss
|
|
68
|
+
(over)"},{"wd":"gloze (over)"},{"wd":"ignore"},{"wd":"overlook"},{"wd":"overpass"},{"wd":"paper
|
|
69
|
+
over"},{"wd":"pass over"},{"wd":"remit"},{"wd":"shrug off"},{"wd":"whitewash"},{"wd":"wink
|
|
70
|
+
(at)"}]],"rel_list":[[{"wd":"explain"},{"wd":"justify"},{"wd":"rationalize"}],[{"wd":"absolve"},{"wd":"acquit"},{"wd":"clear"},{"wd":"exculpate"},{"wd":"exonerate"},{"wd":"vindicate"}],[{"wd":"waive"},{"wd":"wave
|
|
71
|
+
(aside or off)"}]],"phrase_list":[[{"wd":"close one\u0027s eyes to"},{"wd":"forgive
|
|
72
|
+
and forget"}]],"near_list":[[{"wd":"heed"},{"wd":"mark"},{"wd":"mind"},{"wd":"note"},{"wd":"object
|
|
73
|
+
(to)"}]]}]]]}],"shortdef":["to cease to have feelings of anger or bitterness
|
|
74
|
+
toward","to dismiss as of little importance"]}]'
|
|
75
|
+
recorded_at: Tue, 21 Jun 2022 23:24:58 GMT
|
|
76
|
+
- request:
|
|
77
|
+
method: get
|
|
78
|
+
uri: https://www.dictionaryapi.com/api/v3/references/collegiate/json/pardoned?key=<COLLEGIATE_DICTIONARY_API_KEY>
|
|
79
|
+
body:
|
|
80
|
+
encoding: US-ASCII
|
|
81
|
+
string: ''
|
|
82
|
+
headers:
|
|
83
|
+
Accept-Encoding:
|
|
84
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
|
85
|
+
Accept:
|
|
86
|
+
- "*/*"
|
|
87
|
+
User-Agent:
|
|
88
|
+
- Ruby
|
|
89
|
+
response:
|
|
90
|
+
status:
|
|
91
|
+
code: 200
|
|
92
|
+
message: OK
|
|
93
|
+
headers:
|
|
94
|
+
Date:
|
|
95
|
+
- Tue, 21 Jun 2022 23:24:58 GMT
|
|
96
|
+
Content-Type:
|
|
97
|
+
- application/json; charset=utf-8
|
|
98
|
+
Content-Length:
|
|
99
|
+
- '1085'
|
|
100
|
+
Connection:
|
|
101
|
+
- keep-alive
|
|
102
|
+
Server:
|
|
103
|
+
- Apache
|
|
104
|
+
Cache-Control:
|
|
105
|
+
- max-age=86400, public
|
|
106
|
+
Pragma:
|
|
107
|
+
- cache
|
|
108
|
+
Vary:
|
|
109
|
+
- Accept-Encoding
|
|
110
|
+
Access-Control-Allow-Origin:
|
|
111
|
+
- "*"
|
|
112
|
+
body:
|
|
113
|
+
encoding: ASCII-8BIT
|
|
114
|
+
string: '[{"meta":{"id":"pardon:2","uuid":"7e15693b-2866-457f-a3bb-d200dd996e5c","sort":"160068700","src":"collegiate","section":"alpha","stems":["pardon","pardoned","pardoning","pardons"],"offensive":false},"hom":2,"hwi":{"hw":"pardon"},"fl":"verb","ins":[{"if":"par*doned"},{"if":"par*don*ing","prs":[{"mw":"\u02c8p\u00e4rd-ni\u014b","sound":{"audio":"pardon02","ref":"c","stat":"1"}},{"mw":"\u02c8p\u00e4r-d\u1d4an-i\u014b"}]}],"def":[{"vd":"transitive
|
|
115
|
+
verb","sseq":[[["sense",{"sn":"1 a","dt":[["text","{bc}to absolve from the
|
|
116
|
+
consequences of a fault or crime"]]}],["sense",{"sn":"b","dt":[["text","{bc}to
|
|
117
|
+
allow (an offense) to pass without punishment {bc}{sx|forgive||}"]]}],["sense",{"sn":"c","dt":[["text","{bc}to
|
|
118
|
+
relieve of a penalty improperly assessed"]]}]],[["sense",{"sn":"2","dt":[["text","{bc}{sx|tolerate||}"]]}]]]}],"syns":[{"pl":"synonyms","pt":[["text","{sc}excuse{\/sc}
|
|
119
|
+
{sc}condone{\/sc} {sc}pardon{\/sc} {sc}forgive{\/sc} mean to exact neither
|
|
120
|
+
punishment nor redress. {sc}excuse{\/sc} may refer to specific acts especially
|
|
121
|
+
in social or conventional situations or the person responsible for these.
|
|
122
|
+
"],["vis",[{"t":"{it}excuse{\/it} an interruption"},{"t":"{it}excused{\/it}
|
|
123
|
+
them for interrupting"}]],["text"," Often the term implies extenuating circumstances.
|
|
124
|
+
"],["vis",[{"t":"injustice {it}excuses{\/it} strong responses"}]],["text","
|
|
125
|
+
{sc}condone{\/sc} implies that one overlooks without censure behavior (such
|
|
126
|
+
as dishonesty or violence) that involves a serious breach of a moral, ethical,
|
|
127
|
+
or legal code, and the term may refer to the behavior or to the agent responsible
|
|
128
|
+
for it. "],["vis",[{"t":"a society that {it}condones{\/it} alcohol but not
|
|
129
|
+
narcotics"}]],["text"," {sc}pardon{\/sc} implies that one remits a penalty
|
|
130
|
+
due for an admitted or established offense. "],["vis",[{"t":"{it}pardon{\/it}
|
|
131
|
+
a criminal"}]],["text"," {sc}forgive{\/sc} implies that one gives up all claim
|
|
132
|
+
to requital and to resentment or vengeful feelings. "],["vis",[{"t":"could
|
|
133
|
+
not {it}forgive{\/it} their rudeness"}]]]}],"et":[["text","Middle English,
|
|
134
|
+
from Anglo-French {it}parduner{\/it}, from Late Latin {it}perdonare{\/it}
|
|
135
|
+
to grant freely, from Latin {it}per-{\/it} thoroughly + {it}donare{\/it} to
|
|
136
|
+
give {ma}{mat|parboil|}, {mat|donation|}{\/ma}"]],"date":"15th century{ds||1|a|}","shortdef":["to
|
|
137
|
+
absolve from the consequences of a fault or crime","to allow (an offense)
|
|
138
|
+
to pass without punishment : forgive","to relieve of a penalty improperly
|
|
139
|
+
assessed"]}]'
|
|
140
|
+
recorded_at: Tue, 21 Jun 2022 23:24:58 GMT
|
|
141
|
+
recorded_with: VCR 6.1.0
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
http_interactions:
|
|
3
|
+
- request:
|
|
4
|
+
method: get
|
|
5
|
+
uri: https://www.dictionaryapi.com/api/v3/references/thesaurus/json/salmon?key=<COLLEGIATE_THESAURUS_API_KEY>
|
|
6
|
+
body:
|
|
7
|
+
encoding: US-ASCII
|
|
8
|
+
string: ''
|
|
9
|
+
headers:
|
|
10
|
+
Accept-Encoding:
|
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
|
12
|
+
Accept:
|
|
13
|
+
- "*/*"
|
|
14
|
+
User-Agent:
|
|
15
|
+
- Ruby
|
|
16
|
+
response:
|
|
17
|
+
status:
|
|
18
|
+
code: 200
|
|
19
|
+
message: OK
|
|
20
|
+
headers:
|
|
21
|
+
Date:
|
|
22
|
+
- Tue, 21 Jun 2022 23:24:57 GMT
|
|
23
|
+
Content-Type:
|
|
24
|
+
- application/json; charset=utf-8
|
|
25
|
+
Content-Length:
|
|
26
|
+
- '113'
|
|
27
|
+
Connection:
|
|
28
|
+
- keep-alive
|
|
29
|
+
Server:
|
|
30
|
+
- Apache
|
|
31
|
+
Cache-Control:
|
|
32
|
+
- max-age=86400, public
|
|
33
|
+
Pragma:
|
|
34
|
+
- cache
|
|
35
|
+
Vary:
|
|
36
|
+
- Accept-Encoding
|
|
37
|
+
Access-Control-Allow-Origin:
|
|
38
|
+
- "*"
|
|
39
|
+
body:
|
|
40
|
+
encoding: ASCII-8BIT
|
|
41
|
+
string: '["salon","saloon","saloons","daemon","daimon","gammon","sallow","salons","salvo","salvor","salvos","sermon","summon","psalmody","salesman","salesmen","almoner","calming","salamis","salient"]'
|
|
42
|
+
recorded_at: Tue, 21 Jun 2022 23:24:57 GMT
|
|
43
|
+
- request:
|
|
44
|
+
method: get
|
|
45
|
+
uri: https://www.dictionaryapi.com/api/v3/references/collegiate/json/salmon?key=<COLLEGIATE_DICTIONARY_API_KEY>
|
|
46
|
+
body:
|
|
47
|
+
encoding: US-ASCII
|
|
48
|
+
string: ''
|
|
49
|
+
headers:
|
|
50
|
+
Accept-Encoding:
|
|
51
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
|
52
|
+
Accept:
|
|
53
|
+
- "*/*"
|
|
54
|
+
User-Agent:
|
|
55
|
+
- Ruby
|
|
56
|
+
response:
|
|
57
|
+
status:
|
|
58
|
+
code: 200
|
|
59
|
+
message: OK
|
|
60
|
+
headers:
|
|
61
|
+
Date:
|
|
62
|
+
- Tue, 21 Jun 2022 23:24:57 GMT
|
|
63
|
+
Content-Type:
|
|
64
|
+
- application/json; charset=utf-8
|
|
65
|
+
Content-Length:
|
|
66
|
+
- '1941'
|
|
67
|
+
Connection:
|
|
68
|
+
- keep-alive
|
|
69
|
+
Server:
|
|
70
|
+
- Apache
|
|
71
|
+
Cache-Control:
|
|
72
|
+
- max-age=86400, public
|
|
73
|
+
Pragma:
|
|
74
|
+
- cache
|
|
75
|
+
Vary:
|
|
76
|
+
- Accept-Encoding
|
|
77
|
+
Access-Control-Allow-Origin:
|
|
78
|
+
- "*"
|
|
79
|
+
body:
|
|
80
|
+
encoding: ASCII-8BIT
|
|
81
|
+
string: '[{"meta":{"id":"salmon","uuid":"cb7ebb03-74af-4bd2-8191-5d88cee9dcbf","sort":"190315000","src":"collegiate","section":"alpha","stems":["Atlantic
|
|
82
|
+
salmon","salmon","salmons"],"offensive":false},"hwi":{"hw":"salm*on","prs":[{"mw":"\u02c8sa-m\u0259n","sound":{"audio":"salmon01","ref":"c","stat":"1"}}]},"fl":"noun","ins":[{"il":"plural","if":"salmon"},{"il":"also","if":"salm*ons"}],"def":[{"sseq":[[["sense",{"sn":"1
|
|
83
|
+
a","dt":[["text","{bc}a large anadromous {a_link|salmonid} fish ({it}Salmo
|
|
84
|
+
salar{\/it}) of the North Atlantic noted as a game and food fish "],["ca",{"intro":"called
|
|
85
|
+
also","cats":[{"cat":"Atlantic salmon"}]}]]}],["sense",{"sn":"b","dt":[["text","{bc}any
|
|
86
|
+
of various anadromous salmonid fishes other than the salmon"]],"sdsense":{"sd":"especially","dt":[["text","{bc}{sx|pacific
|
|
87
|
+
salmon||}"]]}}],["sense",{"sn":"c","dt":[["text","{bc}a fish (such as a barramundi)
|
|
88
|
+
resembling a salmon"]]}]],[["sense",{"sn":"2","dt":[["text","{bc}the variable
|
|
89
|
+
color of salmon\u0027s flesh averaging a strong yellowish pink"]]}]]]}],"et":[["text","Middle
|
|
90
|
+
English {it}samon{\/it}, from Anglo-French {it}salmon, samon{\/it}, from Latin
|
|
91
|
+
{it}salmon-, salmo{\/it}"]],"date":"13th century{ds||1|a|}","shortdef":["a
|
|
92
|
+
large anadromous salmonid fish (Salmo salar) of the North Atlantic noted as
|
|
93
|
+
a game and food fish \u2014called also Atlantic salmon","any of various anadromous
|
|
94
|
+
salmonid fishes other than the salmon; especially : pacific salmon","a fish
|
|
95
|
+
(such as a barramundi) resembling a salmon"]},{"meta":{"id":"Salmon:g","uuid":"a5f856eb-b391-47c0-a661-6436e1d1581a","sort":"282519000","src":"collegiate","section":"geog","stems":["Salmon"],"offensive":false},"hwi":{"hw":"Salm*on","prs":[{"mw":"\u02c8sa-m\u0259n","sound":{"audio":"ggsalm01","ref":"c","stat":"1"}}]},"fl":"geographical
|
|
96
|
+
name","def":[{"sseq":[[["sense",{"dt":[["text","river 420 miles (676 kilometers)
|
|
97
|
+
long in central Idaho flowing into the Snake River"]]}]]]}],"shortdef":["river
|
|
98
|
+
420 miles (676 kilometers) long in central Idaho flowing into the Snake River"]},{"meta":{"id":"salmon
|
|
99
|
+
pink","uuid":"0cd33845-1c8d-446b-8908-a83389918e7e","sort":"190321000","src":"collegiate","section":"alpha","stems":["salmon
|
|
100
|
+
pink","salmon pinks"],"offensive":false},"hwi":{"hw":"salmon pink"},"fl":"noun","def":[{"sseq":[[["sense",{"dt":[["text","{bc}a
|
|
101
|
+
strong yellowish pink"]]}]]]}],"date":"1882","shortdef":["a strong yellowish
|
|
102
|
+
pink"]},{"meta":{"id":"Salmon River Mountains:g","uuid":"2f208a45-3e68-48b1-b0b7-53cc0b7b483a","sort":"282520000","src":"collegiate","section":"geog","stems":["Salmon
|
|
103
|
+
River Mountains"],"offensive":false},"hwi":{"hw":"Salmon River Mountains"},"fl":"geographical
|
|
104
|
+
name","def":[{"sseq":[[["sense",{"dt":[["text","mountains in central Idaho
|
|
105
|
+
with many peaks over 9000 feet (2743 meters) high"]]}]]]}],"shortdef":["mountains
|
|
106
|
+
in central Idaho with many peaks over 9000 feet (2743 meters) high"]},{"meta":{"id":"Atlantic
|
|
107
|
+
salmon","uuid":"12ee4593-c04b-4ecc-9a25-806df767ad7e","sort":"014523000","src":"collegiate","section":"alpha","stems":["Atlantic
|
|
108
|
+
salmon","Atlantic salmons"],"offensive":false},"hwi":{"hw":"Atlantic salmon"},"fl":"noun","def":[{"sseq":[[["sense",{"dt":[["text","{bc}{sx|salmon||1a}"]]}]]]}],"date":"1813","shortdef":["salmon"]},{"meta":{"id":"black
|
|
109
|
+
salmon","uuid":"0a75d3f5-b816-430a-ab01-da53aa2fb41a","sort":"020261750","src":"collegiate","section":"alpha","stems":["black
|
|
110
|
+
salmon","black salmons"],"offensive":false},"hwi":{"hw":"black salmon"},"fl":"noun","def":[{"sseq":[[["sense",{"dt":[["text","{bc}{sx|chinook
|
|
111
|
+
salmon||}"]]}]]]}],"date":"1873","shortdef":["chinook salmon"]},{"meta":{"id":"Chinook
|
|
112
|
+
salmon","uuid":"1fa80af4-81c1-4a08-9f0b-578454e0eabe","sort":"032660000","src":"collegiate","section":"alpha","stems":["Chinook","Chinook
|
|
113
|
+
salmon","Chinooks","chinook","chinook jargon","chinook salmon","chinook salmons","chinookan","chinooks","king
|
|
114
|
+
salmon"],"offensive":false},"hwi":{"hw":"Chinook salmon"},"vrs":[{"vl":"or
|
|
115
|
+
less commonly","va":"chinook salmon"},{"vl":"or","va":"Chinook"},{"vl":"or","va":"chinook"}],"fl":"noun","def":[{"sseq":[[["sense",{"dt":[["text","{bc}a
|
|
116
|
+
large, usually red-fleshed, commercially important salmon ({it}Oncorhynchus
|
|
117
|
+
tshawytscha{\/it}) of the northern Pacific Ocean that is typically bluish-green
|
|
118
|
+
above with silvery sides, has a dark mouth with black gums, and attains an
|
|
119
|
+
average weight of about 30 to 40 pounds (13.5 to 18 kilograms) but may sometimes
|
|
120
|
+
exceed 120 pounds (54 kilograms) "],["ca",{"intro":"called also","cats":[{"cat":"black
|
|
121
|
+
salmon"},{"cat":"king salmon"}]}]]}]]]}],"art":{"artid":"chin_sa","capt":"Chinook
|
|
122
|
+
salmon"},"date":"1851","shortdef":["a large, usually red-fleshed, commercially
|
|
123
|
+
important salmon (Oncorhynchus tshawytscha) of the northern Pacific Ocean
|
|
124
|
+
that is typically bluish-green above with silvery sides, has a dark mouth
|
|
125
|
+
with black gums, and attains an average weight of about 30 to 40 pounds (13.5
|
|
126
|
+
to 18 kilograms) but may sometimes exceed 120 pounds (54 kilograms) \u2014called
|
|
127
|
+
also black salmon, king salmon"]},{"meta":{"id":"chum salmon","uuid":"a0d372d5-dd32-419f-b79f-5160e5f296c0","sort":"033065000","src":"collegiate","section":"alpha","stems":["chum","chum
|
|
128
|
+
salmon","chum salmons","chums","chumship","chumships"],"offensive":false},"hwi":{"hw":"chum
|
|
129
|
+
salmon"},"vrs":[{"vl":"or less commonly","va":"chum"}],"fl":"noun","def":[{"sseq":[[["sense",{"dt":[["text","{bc}a
|
|
130
|
+
metallic bluish green salmon ({it}Oncorhynchus keta{\/it}) of the northern
|
|
131
|
+
Pacific Ocean and Arctic Ocean that may reach a length of about 3.5 feet (1
|
|
132
|
+
meter) but is typically smaller "],["snote",[["t","Upon entering fresh water
|
|
133
|
+
to spawn, the male chum salmon develops large, sharp teeth and becomes dark
|
|
134
|
+
green to brown with reddish-purple vertical stripes."]]]]}]]]}],"et":[["text","{et_link|chum:5|chum:5}"]],"date":"1907","shortdef":["a
|
|
135
|
+
metallic bluish green salmon (Oncorhynchus keta) of the northern Pacific Ocean
|
|
136
|
+
and Arctic Ocean that may reach a length of about 3.5 feet (1 meter) but is
|
|
137
|
+
typically smaller"]},{"meta":{"id":"jack salmon","uuid":"d3d51ea4-f587-418d-a756-feb55f6795dc","sort":"100005100","src":"collegiate","section":"alpha","stems":["jack
|
|
138
|
+
salmon","jack salmons"],"offensive":false},"hwi":{"hw":"jack salmon"},"fl":"noun","def":[{"sseq":[[["sense",{"sn":"1","dt":[["text","{bc}{sx|walleye||3}"]]}]],[["sense",{"sn":"2
|
|
139
|
+
a","dt":[["text","{bc}{sx|grilse||}"]]}],["sense",{"sn":"b","dt":[["text","{bc}{sx|coho||}"]]}]]]}],"date":"1850{ds||1||}","shortdef":["walleye","grilse","coho"]},{"meta":{"id":"king
|
|
140
|
+
salmon","uuid":"9c8b42d9-a92d-4900-ae11-25f5bd6898cd","sort":"110049200","src":"collegiate","section":"alpha","stems":["king
|
|
141
|
+
salmon","king salmons"],"offensive":false},"hwi":{"hw":"king salmon"},"fl":"noun","def":[{"sseq":[[["sense",{"dt":[["text","{bc}{sx|chinook
|
|
142
|
+
salmon||}"]]}]]]}],"date":"1871","shortdef":["chinook salmon"]}]'
|
|
143
|
+
recorded_at: Tue, 21 Jun 2022 23:24:57 GMT
|
|
144
|
+
recorded_with: VCR 6.1.0
|
data/lib/.DS_Store
ADDED
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "httparty"
|
|
3
|
+
|
|
4
|
+
module MerriamWebsterPlus
|
|
5
|
+
class Client
|
|
6
|
+
MerriamWebsterAPIError = Class.new(StandardError)
|
|
7
|
+
BadRequestError = Class.new(MerriamWebsterAPIError)
|
|
8
|
+
UnauthorizedError = Class.new(MerriamWebsterAPIError)
|
|
9
|
+
ForbiddenError = Class.new(MerriamWebsterAPIError)
|
|
10
|
+
NotFoundError = Class.new(MerriamWebsterAPIError)
|
|
11
|
+
UnprocessableEntityError = Class.new(MerriamWebsterAPIError)
|
|
12
|
+
ApiError = Class.new(MerriamWebsterAPIError)
|
|
13
|
+
|
|
14
|
+
HTTP_OK_CODE = 200
|
|
15
|
+
|
|
16
|
+
HTTP_BAD_REQUEST_CODE = 400
|
|
17
|
+
HTTP_UNAUTHORIZED_CODE = 401
|
|
18
|
+
HTTP_FORBIDDEN_CODE = 403
|
|
19
|
+
HTTP_NOT_FOUND_CODE = 404
|
|
20
|
+
HTTP_UNPROCESSABLE_ENTITY_CODE = 429
|
|
21
|
+
|
|
22
|
+
COLLEGIATE_DICTIONARY_ENDPOINT = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/"
|
|
23
|
+
COLLEGIATE_THESAURUS_ENDPOINT = "https://www.dictionaryapi.com/api/v3/references/thesaurus/json/"
|
|
24
|
+
|
|
25
|
+
attr_reader :word, :title
|
|
26
|
+
|
|
27
|
+
def initialize(word:, title:)
|
|
28
|
+
@word = railsy_parameterize(word)
|
|
29
|
+
@title = title
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def api_entries
|
|
33
|
+
parsed_response
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def response
|
|
39
|
+
@response ||= HTTParty.get("#{endpoint}#{word}?key=#{api_key}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def parsed_response
|
|
43
|
+
return JSON.parse(response.body, symbolize_names: true) if response_successful?
|
|
44
|
+
|
|
45
|
+
raise error_class, "code: #{response.code}, message: #{response.message}, response: #{response.body}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def error_class
|
|
49
|
+
case response.code
|
|
50
|
+
when HTTP_BAD_REQUEST_CODE
|
|
51
|
+
BadRequestError
|
|
52
|
+
when HTTP_UNAUTHORIZED_CODE
|
|
53
|
+
UnauthorizedError
|
|
54
|
+
when HTTP_FORBIDDEN_CODE
|
|
55
|
+
ForbiddenError
|
|
56
|
+
when HTTP_NOT_FOUND_CODE
|
|
57
|
+
NotFoundError
|
|
58
|
+
when HTTP_UNPROCESSABLE_ENTITY_CODE
|
|
59
|
+
UnprocessableEntityError
|
|
60
|
+
else
|
|
61
|
+
ApiError
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def response_successful?
|
|
66
|
+
(response.code == HTTP_OK_CODE) && valid_json?(response.body)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def valid_json?(json)
|
|
70
|
+
JSON.parse(json)
|
|
71
|
+
true
|
|
72
|
+
rescue JSON::ParserError => e
|
|
73
|
+
false
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def endpoint
|
|
77
|
+
MerriamWebsterPlus::Client.const_get("#{title.upcase}_ENDPOINT")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def api_key
|
|
81
|
+
ENV["#{title.upcase}_API_KEY"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def railsy_parameterize(string)
|
|
85
|
+
string.gsub(/[^a-z0-9\-_]+/i, "_").downcase
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require "merriam_webster_plus/client"
|
|
2
|
+
require "merriam_webster_plus/dictionary_entry"
|
|
3
|
+
|
|
4
|
+
module MerriamWebsterPlus
|
|
5
|
+
class DictionaryEntries
|
|
6
|
+
attr_reader :word, :api_entries, :entry_parser
|
|
7
|
+
|
|
8
|
+
def initialize(word:)
|
|
9
|
+
@word = word
|
|
10
|
+
title_post_initialize
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def main_entries
|
|
14
|
+
main_entries = []
|
|
15
|
+
api_entries.each do |api_entry|
|
|
16
|
+
main_entry = main_entry(api_entry)
|
|
17
|
+
(main_entries << main_entry) if word_equals_entry_headword?(main_entry)
|
|
18
|
+
end
|
|
19
|
+
main_entries
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def title_post_initialize
|
|
25
|
+
@api_entries = MerriamWebsterPlus::Client.new(word: word, title: :collegiate_dictionary).api_entries
|
|
26
|
+
@entry_parser = DictionaryEntry
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def main_entry(api_entry)
|
|
30
|
+
entry_parser.new(api_entry: api_entry).main_entry if api_entry_valid?(api_entry)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def api_entry_valid?(api_entry)
|
|
34
|
+
(api_entry.is_a? Hash)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def word_equals_entry_headword?(entry)
|
|
38
|
+
entry && (word.downcase == entry[:word].downcase)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
require "merriam_webster_plus/dictionary_sense"
|
|
2
|
+
|
|
3
|
+
module MerriamWebsterPlus
|
|
4
|
+
class DictionaryEntry
|
|
5
|
+
AUDIO_MP3_ENDPOINT = "https://media.merriam-webster.com/audio/prons/en/us/mp3/"
|
|
6
|
+
|
|
7
|
+
attr_reader :api_entry, :sense_parser
|
|
8
|
+
|
|
9
|
+
def initialize(api_entry:)
|
|
10
|
+
@api_entry = api_entry
|
|
11
|
+
title_post_initialize
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def main_entry
|
|
15
|
+
{
|
|
16
|
+
word: headword,
|
|
17
|
+
class: word_class,
|
|
18
|
+
audio: audio,
|
|
19
|
+
senses: senses,
|
|
20
|
+
uuid: uuid,
|
|
21
|
+
target_uuid: target_uuid
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def title_post_initialize
|
|
28
|
+
@sense_parser = DictionarySense
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def headword
|
|
32
|
+
remove_non_letters(headword_information&.dig(:hw))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def word_class
|
|
36
|
+
functional_label
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def audio
|
|
40
|
+
("#{AUDIO_MP3_ENDPOINT}#{audio_subdirectory}/#{audio_filename}.mp3" if audio_filename)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def uuid
|
|
44
|
+
entry_metadata[:uuid]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def target_uuid
|
|
48
|
+
entry_metadata&.dig(:target, :tuuid)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def entry_metadata
|
|
52
|
+
api_entry[:meta]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def headword_information
|
|
56
|
+
api_entry[:hwi]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def functional_label
|
|
60
|
+
api_entry[:fl]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def definition_section
|
|
64
|
+
api_entry[:def]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def short_definition
|
|
68
|
+
api_entry[:shortdef]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def senses
|
|
72
|
+
return unless definition_section
|
|
73
|
+
|
|
74
|
+
senses = []
|
|
75
|
+
sense_sequence.each_with_index do |sense_group, index|
|
|
76
|
+
senses << primary_sense(sense_group, index)
|
|
77
|
+
end
|
|
78
|
+
senses.first(3)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def primary_sense(sense_group, index)
|
|
82
|
+
["#{index + 1}".to_i,
|
|
83
|
+
sense_parser.new(definition: definition(index), sense_group: sense_group).primary_sense]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def definition(index_num)
|
|
87
|
+
short_definition&.dig(index_num)&.chomp(": such as")&.chomp(":")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def sense_sequence
|
|
91
|
+
return parenthesized_sense_sequence if parenthesized_sense_sequence?
|
|
92
|
+
|
|
93
|
+
definition_section&.dig(0, :sseq)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def parenthesized_sense_sequence
|
|
97
|
+
definition_section&.dig(0, :sseq, 0, 0, 1)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def parenthesized_sense_sequence?
|
|
101
|
+
definition_section&.dig(0, :sseq, 0, 0, 0) == "pseq"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def audio_filename
|
|
105
|
+
headword_information&.dig(:prs, 0, :sound, :audio)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def audio_subdirectory
|
|
109
|
+
if audio_filename.start_with?("bix")
|
|
110
|
+
"bix"
|
|
111
|
+
elsif audio_filename.start_with?("gg")
|
|
112
|
+
"gg"
|
|
113
|
+
elsif audio_filename.chr.match?((/[^a-z ]/i))
|
|
114
|
+
"number"
|
|
115
|
+
else
|
|
116
|
+
audio_filename.chr
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def remove_non_letters(string)
|
|
121
|
+
string&.gsub(/[^a-z ]/i, "")
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "merriam_webster_plus/dictionary_entries"
|
|
2
|
+
require "merriam_webster_plus/thesaurus_entries"
|
|
3
|
+
require "merriam_webster_plus/entry_audio_merger"
|
|
4
|
+
require "merriam_webster_plus/primary_entry_finder"
|
|
5
|
+
|
|
6
|
+
module MerriamWebsterPlus
|
|
7
|
+
class DictionaryPlus
|
|
8
|
+
attr_reader :word, :thesaurus_entries, :dictionary_entries, :entry_audio_merger, :primary_entry_finder
|
|
9
|
+
|
|
10
|
+
def initialize(word:)
|
|
11
|
+
@word = word
|
|
12
|
+
@thesaurus_entries = MerriamWebsterPlus::ThesaurusEntries.new(word: word).main_entries
|
|
13
|
+
@dictionary_entries = MerriamWebsterPlus::DictionaryEntries.new(word: word).main_entries
|
|
14
|
+
@entry_audio_merger = MerriamWebsterPlus::EntryAudioMerger
|
|
15
|
+
@primary_entry_finder = PrimaryEntryFinder
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def primary_entry
|
|
19
|
+
primary_entry_with_audio if entries.any?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def entries
|
|
23
|
+
thesaurus_entries.any? ? thesaurus_entries_with_audio : dictionary_entries_with_audio
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def thesaurus_entries_with_audio
|
|
29
|
+
entry_audio_merger.new(dst_entries: thesaurus_entries, src_entries: dictionary_entries).merged_entries
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def dictionary_entries_with_audio
|
|
33
|
+
entry_audio_merger.new(dst_entries: dictionary_entries, src_entries: dictionary_entries).merged_entries
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def primary_entry_with_audio
|
|
37
|
+
primary_entry_finder.new(primary_src_entries: thesaurus_entries_with_audio,
|
|
38
|
+
secondary_src_entries: dictionary_entries_with_audio,
|
|
39
|
+
tertiary_src_entries: entries).primary_entry
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def railsy_blank(object)
|
|
43
|
+
object.nil? || object.empty?
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module MerriamWebsterPlus
|
|
2
|
+
class DictionarySense
|
|
3
|
+
attr_reader :definition, :sense_group
|
|
4
|
+
|
|
5
|
+
def initialize(definition:, sense_group:)
|
|
6
|
+
@definition = definition
|
|
7
|
+
@sense_group = sense_group
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def primary_sense
|
|
11
|
+
{
|
|
12
|
+
definition: definition,
|
|
13
|
+
example: example_sentence
|
|
14
|
+
}.compact
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def sense
|
|
20
|
+
sense_group&.select { |sense| sense[0] == "sense" }&.first&.dig(1)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def example_sentence
|
|
24
|
+
verbal_illustration unless lacking_letters?(verbal_illustration)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def defining_text_section
|
|
28
|
+
sense&.dig(:dt)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def defining_text_section_usage_notes
|
|
32
|
+
defining_text_section&.select { |section| section[0] == "uns" }&.dig(0, 1, 0)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def defining_text_section_supplemental_information_notes
|
|
36
|
+
defining_text_section&.select { |section| section[0] == "snote" }&.dig(0, 1)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def verbal_illustration_section
|
|
40
|
+
select_verbal_illustration_section(defining_text_section) ||
|
|
41
|
+
select_verbal_illustration_section(defining_text_section_usage_notes) ||
|
|
42
|
+
select_verbal_illustration_section(defining_text_section_supplemental_information_notes)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def select_verbal_illustration_section(containing_section)
|
|
46
|
+
containing_section&.select { |section| section[0] == "vis" }&.last
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def verbal_illustration
|
|
50
|
+
verbal_illustration_section&.dig(1, 0, :t)&.gsub(/\{.*?\}/, "")&.strip
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def lacking_letters?(string)
|
|
54
|
+
string.nil? || string.to_s[/\p{L}/].nil?
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|