latinverb 0.2.0 → 0.9.2
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.
- data/.gitignore +0 -1
- data/Gemfile +1 -2
- data/README.markdown +54 -240
- data/etc/irreg_skel.json +104 -0
- data/{latinirb.gemspec → latinverb.gemspec} +4 -4
- data/lib/latinverb/chart.rb +94 -0
- data/lib/latinverb/version.rb +10 -0
- data/lib/latinverb.rb +710 -0
- data/lib/linguistics/latin/verb/classification_types.rb +59 -0
- data/lib/linguistics/latin/verb/constants.rb +201 -0
- data/lib/linguistics/latin/verb/deponent_tense_methods.rb +98 -0
- data/lib/linguistics/latin/verb/infinitives.rb +212 -0
- data/lib/linguistics/latin/verb/irregulars.rb +4393 -0
- data/lib/linguistics/latin/verb/latinverb/auxiliary_classes.rb +208 -0
- data/lib/linguistics/latin/verb/latinverb/classmethods.rb +215 -0
- data/lib/linguistics/latin/verb/latinverb/data.rb +90 -0
- data/lib/linguistics/latin/verb/latinverb/display.rb +23 -0
- data/lib/linguistics/latin/verb/latinverb/metaprogramming.rb +79 -0
- data/lib/linguistics/latin/verb/latinverb/validation.rb +66 -0
- data/lib/linguistics/latin/verb/participles.rb +202 -0
- data/lib/linguistics/latin/verb/phonographia.rb +109 -0
- data/lib/linguistics/latin/verb/supine.rb +42 -0
- data/lib/linguistics/latin/verb/tense_methods.rb +950 -0
- data/test/testAmbiguousLookups.rb +30 -0
- data/test/testClusterResolution.rb +20 -0
- data/test/testDataStructures.rb +29 -0
- data/test/testDefectSemiImp.rb +111 -0
- data/test/testDeponentFirstConjugation.rb +64 -0
- data/test/testDeponentFourthConjugation.rb +64 -0
- data/test/testDeponentSecondConjugation.rb +64 -0
- data/test/testDeponentThirdConjugation.rb +64 -0
- data/test/testDeponentThirdIOConjugation.rb +64 -0
- data/test/testDeserializeInfinitives.rb +38 -0
- data/test/testFirstConjugation.rb +388 -0
- data/test/testFourthConjugation.rb +190 -0
- data/test/testFreakishVerbs.rb +93 -0
- data/test/testImperativeBlock.rb +27 -0
- data/test/testIrregularSum.rb +22 -0
- data/test/testIrregulars.rb +652 -0
- data/test/testLatinVerb.rb +195 -0
- data/test/testMacronRules.rb +19 -0
- data/test/testSecondConjugation.rb +189 -0
- data/test/testThirdConjugation.rb +190 -0
- data/test/testThirdIOConjugation.rb +190 -0
- metadata +70 -18
- data/bin/latinirb.rb +0 -7
- data/latinverb.rb +0 -544
- data/lib/LatinIRB.rb +0 -172
- data/lib/latinirb/paradigmatic_verbs.rb +0 -17
- data/lib/latinirb/version.rb +0 -10
- data/lib/latirb.rb +0 -20
@@ -0,0 +1,208 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'linguistics/latin/verb/phonographia'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module Linguistics
|
7
|
+
module Latin
|
8
|
+
module Verb
|
9
|
+
|
10
|
+
class ParticipleBlock
|
11
|
+
attr_reader :participle_methods
|
12
|
+
|
13
|
+
|
14
|
+
def initialize(s)
|
15
|
+
raise "ParticipleBlock instantiation argument was nil!" if s.nil?
|
16
|
+
|
17
|
+
if s.class == Hash
|
18
|
+
@participle_methods = s.keys
|
19
|
+
end
|
20
|
+
|
21
|
+
@participle_methods.each do |k|
|
22
|
+
v=s[k]
|
23
|
+
singleton_class.class_eval do
|
24
|
+
define_method k.to_sym do
|
25
|
+
return v
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
#
|
33
|
+
# Required for deserialization
|
34
|
+
#
|
35
|
+
##
|
36
|
+
def self.json_create(o)
|
37
|
+
new(o['data'])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
#-------------------------------------------------------------------------------
|
43
|
+
#-------------------------------------------------------------------------------
|
44
|
+
##
|
45
|
+
#
|
46
|
+
# The InfinitiveBlock holds the infinitives associated with a given
|
47
|
+
# verb. The known infinitives are the following:
|
48
|
+
#
|
49
|
+
# *
|
50
|
+
class InfinitiveBlock
|
51
|
+
attr_reader :infinitive_methods
|
52
|
+
def initialize(s)
|
53
|
+
if s.class == Hash
|
54
|
+
@infinitive_methods = s.keys
|
55
|
+
end
|
56
|
+
|
57
|
+
@infinitive_methods.each do |k|
|
58
|
+
v=s[k]
|
59
|
+
singleton_class.class_eval do
|
60
|
+
define_method k.to_sym do
|
61
|
+
return v
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
#
|
69
|
+
# Required for deserialization
|
70
|
+
#
|
71
|
+
##
|
72
|
+
def self.json_create(o)
|
73
|
+
new(o['data'])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class ImperativeBlock
|
78
|
+
def initialize(stem,ppi)
|
79
|
+
# In case we get an Array, for JSON revivification
|
80
|
+
if stem.class == Array
|
81
|
+
@results = stem
|
82
|
+
end
|
83
|
+
|
84
|
+
r = case
|
85
|
+
when ppi =~ /āre$/
|
86
|
+
[stem, stem+"te"]
|
87
|
+
when ppi =~ /ēre$/
|
88
|
+
[stem, stem+"te"]
|
89
|
+
when ppi =~ /ere$/
|
90
|
+
[stem+"e", stem+"ite"]
|
91
|
+
when ppi =~ /īre$/
|
92
|
+
[stem+"ī", stem+"īte"]
|
93
|
+
end
|
94
|
+
|
95
|
+
r << stem + "tō"
|
96
|
+
r << stem + "tōte"
|
97
|
+
|
98
|
+
r << stem + "tō"
|
99
|
+
r << stem + "ntō"
|
100
|
+
|
101
|
+
@results = r.map{|v| Linguistics::Latin::Phonographia.fix_macrons v}
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_s
|
105
|
+
return @results
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
#
|
110
|
+
# Required for serialization
|
111
|
+
#
|
112
|
+
##
|
113
|
+
def to_json(*a)
|
114
|
+
{
|
115
|
+
'json_class' => self.class.name,
|
116
|
+
'data' => @results.map{|i| i.to_json}
|
117
|
+
}.to_json(*a)
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
#
|
122
|
+
# Required for deserialization
|
123
|
+
#
|
124
|
+
##
|
125
|
+
def self.json_create(o)
|
126
|
+
new(o['data'])
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
#
|
131
|
+
# Provides Array-like interface to the collection of results.
|
132
|
+
#
|
133
|
+
##
|
134
|
+
def [](arg)
|
135
|
+
@results[arg]
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
#
|
140
|
+
# To Array, useful in serialization
|
141
|
+
#
|
142
|
+
##
|
143
|
+
def to_a
|
144
|
+
return @results
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
#
|
149
|
+
# Add array compatibility support
|
150
|
+
#
|
151
|
+
##
|
152
|
+
def length; return @results.length; end
|
153
|
+
|
154
|
+
##
|
155
|
+
#
|
156
|
+
# Returns the two, second person imperatives
|
157
|
+
#
|
158
|
+
##
|
159
|
+
def present(qualifier=nil)
|
160
|
+
j=@results[0,2]
|
161
|
+
return j if qualifier.nil?
|
162
|
+
qualifier = qualifier.to_s
|
163
|
+
return j[0] if qualifier =~ /singular/
|
164
|
+
return j[1] if qualifier =~ /plural/
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
#
|
169
|
+
# Returns the four, second and third person future imperatives
|
170
|
+
#
|
171
|
+
##
|
172
|
+
def future(qualifier=nil)
|
173
|
+
return j=@results[2,4] if qualifier.nil?
|
174
|
+
|
175
|
+
# case
|
176
|
+
# when qualifier =~ /second_person/
|
177
|
+
# if qualifier =~ /singular/
|
178
|
+
# return j[0]
|
179
|
+
# elsif qualifier =~ /plural/
|
180
|
+
# return j[2]
|
181
|
+
# else
|
182
|
+
# return [ j[0], j[2] ]
|
183
|
+
# end
|
184
|
+
# when qualifier =~ /third_person/
|
185
|
+
# if qualifier =~ /singular/
|
186
|
+
# return j[1]
|
187
|
+
# elsif qualifier =~ /plural/
|
188
|
+
# return j[3]
|
189
|
+
# else
|
190
|
+
# return [ j[1], j[3] ]
|
191
|
+
# end
|
192
|
+
# else
|
193
|
+
# raise "[future] could not parse this imperative"
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
end
|
197
|
+
|
198
|
+
def method_missing(sym,*args)
|
199
|
+
if (sym =~ /^(present|future)_tense_(.*)/)
|
200
|
+
self.send($1.to_sym, $2)
|
201
|
+
else
|
202
|
+
super
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Linguistics
|
4
|
+
module Latin
|
5
|
+
module Verb
|
6
|
+
class LatinVerb
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
##
|
11
|
+
#
|
12
|
+
# Deponent verbs can be conceived as being the <em>the passive</em> results of
|
13
|
+
# a regular verb where the passive form's result is then applied to the active
|
14
|
+
# vector specification. Ergo the dictum "passive in form but active in
|
15
|
+
# meaning." As such, when we realize we have a deponent verb, we will create
|
16
|
+
# its standard four principal part string sibling. This, in turn, could be
|
17
|
+
# used to create a LatinVerb. Then through some method deletion or aliasing,
|
18
|
+
# the active vector can be used to point to the (in fact) passive result
|
19
|
+
#
|
20
|
+
# For example:
|
21
|
+
#
|
22
|
+
# <pre>
|
23
|
+
# j = LatinVerb.new conor conārī conatus
|
24
|
+
# # create_pseudo_active_mask_for_deponent creates (conō, conāre, conāvī
|
25
|
+
# conatus)
|
26
|
+
# # Do magic so that active_voice_indicative_mood_present_tense points to
|
27
|
+
# passive_voice_indicative_mood_present_tense
|
28
|
+
# </pre>
|
29
|
+
#
|
30
|
+
# ===ARGUMENTS
|
31
|
+
#
|
32
|
+
# s :: A deponent description string to be pesudo-mapped
|
33
|
+
#
|
34
|
+
# ===RETURNS
|
35
|
+
#
|
36
|
+
# A pseudo-mapped, four principal-part string
|
37
|
+
#
|
38
|
+
##
|
39
|
+
def create_pseudo_active_mask_for_deponent(s)
|
40
|
+
parts = s.split /\s+/
|
41
|
+
|
42
|
+
# Turn the passive form into something that looks active
|
43
|
+
parts[0].sub! /or$/, 'ō'
|
44
|
+
|
45
|
+
# Turn the passive infinitive into something that looks active.
|
46
|
+
# There's a subtle difference between:
|
47
|
+
# 'vereor verērī veritum'
|
48
|
+
# 'sequor sequī secūtus'
|
49
|
+
# Applying the first's rule to the second results in 'seque' not
|
50
|
+
# 'sequere'. Ergo the conditional.
|
51
|
+
#
|
52
|
+
parts[1].sub! /ī$/, 'e'
|
53
|
+
|
54
|
+
# Fixes sequī -> sequere
|
55
|
+
parts[1] += 're' unless parts[1] =~ /[āīē]re/
|
56
|
+
|
57
|
+
# Set the 4th part to the value in the 3rd slot
|
58
|
+
parts[3] = parts[2]
|
59
|
+
|
60
|
+
# Another modification for third conjugation deponents
|
61
|
+
parts[3].sub! /us$/, 'um'
|
62
|
+
|
63
|
+
# This value shouldn't be used...(I don't think...)
|
64
|
+
parts[2] = "JUNK" #
|
65
|
+
|
66
|
+
parts.join(' ')
|
67
|
+
end
|
68
|
+
##
|
69
|
+
#
|
70
|
+
# == ARGUMENTS
|
71
|
+
#
|
72
|
+
# * s :: a "four principal parts" string whence can be derived
|
73
|
+
# the first person singular present indicative as well as the
|
74
|
+
# infinitive
|
75
|
+
#
|
76
|
+
# == RETURNS
|
77
|
+
#
|
78
|
+
# The classification, a subclass of VerbType
|
79
|
+
#
|
80
|
+
# == PURPOSE
|
81
|
+
#
|
82
|
+
# Given the principal parts as a string, decide which conjuation is
|
83
|
+
# in play
|
84
|
+
#
|
85
|
+
#
|
86
|
+
##
|
87
|
+
def classify(s)
|
88
|
+
|
89
|
+
if s.class == String
|
90
|
+
divided_string = s.split /\s+/
|
91
|
+
|
92
|
+
first_pres = divided_string[0]
|
93
|
+
infinitive = divided_string[1]
|
94
|
+
|
95
|
+
return Linguistics::Latin::Verb::VerbTypes::Defective if
|
96
|
+
Linguistics::Latin::Verb::LatinVerb::DEFECTIVE_VERBS.member? first_pres
|
97
|
+
|
98
|
+
return Linguistics::Latin::Verb::VerbTypes::Irregular if
|
99
|
+
Linguistics::Latin::Verb::LatinVerb::IRREGULAR_VERBS.member? first_pres
|
100
|
+
|
101
|
+
return Linguistics::Latin::Verb::VerbTypes::Semideponent if
|
102
|
+
( Linguistics::Latin::Verb::LatinVerb::SEMI_DEPONENTS.keys.any?{ |k| first_pres=~/#{k}$/} and
|
103
|
+
s !~ /JUNK/ )
|
104
|
+
|
105
|
+
return Linguistics::Latin::Verb::VerbTypes::Impersonal if
|
106
|
+
Linguistics::Latin::Verb::LatinVerb::IMPERSONAL_VERBS.member? s
|
107
|
+
|
108
|
+
if infinitive =~ /āre$/
|
109
|
+
return Linguistics::Latin::Verb::VerbTypes::First
|
110
|
+
elsif infinitive =~ /ēre$/
|
111
|
+
return Linguistics::Latin::Verb::VerbTypes::Second
|
112
|
+
elsif infinitive =~ /ere$/
|
113
|
+
if first_pres =~ /i.$/
|
114
|
+
return Linguistics::Latin::Verb::VerbTypes::ThirdIO
|
115
|
+
else
|
116
|
+
return Linguistics::Latin::Verb::VerbTypes::Third
|
117
|
+
end
|
118
|
+
elsif infinitive =~ /.+īre$/
|
119
|
+
return Linguistics::Latin::Verb::VerbTypes::Fourth
|
120
|
+
elsif (infinitive =~ /ī$/ and first_pres =~ /r$/)
|
121
|
+
return Linguistics::Latin::Verb::VerbTypes::Deponent
|
122
|
+
# Very irregular irregulars, A&G206, e/f
|
123
|
+
elsif s =~ %r'^(aiō|quaesō|ovāre)$'
|
124
|
+
return Linguistics::Latin::Verb::VerbTypes::Irregular
|
125
|
+
else
|
126
|
+
raise "Could not find a verb type for this verb #{infinitive} and #{first_pres}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
#
|
133
|
+
# == ARGUMENTS
|
134
|
+
#
|
135
|
+
# * pres_act_inf
|
136
|
+
#
|
137
|
+
# == RETURNS
|
138
|
+
#
|
139
|
+
# The “stem” of a Latin Verb
|
140
|
+
#
|
141
|
+
# == PURPOSE
|
142
|
+
#
|
143
|
+
# Based on the present active infinitive, identify the “stem” and set the +@stem+
|
144
|
+
# iVar. The method also returns the stem value.
|
145
|
+
#
|
146
|
+
##
|
147
|
+
def calculate_stem(pres_act_inf)
|
148
|
+
# TODO: For efficiency, if the iVar @stem is defined, don't go through this structure?
|
149
|
+
if pres_act_inf =~ /āre$/
|
150
|
+
return pres_act_inf.gsub(/(.*)āre$/,'\\1ā')
|
151
|
+
end
|
152
|
+
if pres_act_inf =~ /ēre$/
|
153
|
+
return pres_act_inf.gsub(/(.*)ēre$/,'\\1ē')
|
154
|
+
end
|
155
|
+
if pres_act_inf =~ /ere$/
|
156
|
+
if @first_pers_singular =~ /iō$/
|
157
|
+
return pres_act_inf.gsub(/(.*)ere$/,'\\1')
|
158
|
+
else
|
159
|
+
return pres_act_inf.gsub(/(.*)ere$/,'\\1')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
if pres_act_inf =~ /īre$/
|
163
|
+
return pres_act_inf.gsub(/(.*)īre$/,'\\1')
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
#
|
169
|
+
# == ARGUMENTS
|
170
|
+
#
|
171
|
+
# * first_person_singular
|
172
|
+
# * pres_act_inf
|
173
|
+
#
|
174
|
+
# == RETURNS
|
175
|
+
#
|
176
|
+
# The participial “stem” of a Latin Verb, used for participle
|
177
|
+
# formation
|
178
|
+
#
|
179
|
+
# == PURPOSE
|
180
|
+
#
|
181
|
+
# Calculate the participial stem, used in forming participles.
|
182
|
+
#
|
183
|
+
##
|
184
|
+
def calculate_participial_stem(first_pers_singular, pres_act_inf)
|
185
|
+
raise("pres_act_inf was nil![#{first_pers_singular} and #{pres_act_inf}]") if
|
186
|
+
pres_act_inf.empty? or first_pers_singular.empty?
|
187
|
+
|
188
|
+
if pres_act_inf.to_s =~ /(.*ā)re$/
|
189
|
+
return $1
|
190
|
+
end
|
191
|
+
|
192
|
+
if pres_act_inf.to_s =~ /(.*ē)re$/
|
193
|
+
return $1
|
194
|
+
end
|
195
|
+
|
196
|
+
if pres_act_inf.to_s =~ /(.*)ere$/
|
197
|
+
match=$1
|
198
|
+
if first_pers_singular =~ /iō/
|
199
|
+
return match + "iē"
|
200
|
+
else
|
201
|
+
return match + "e"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
if pres_act_inf.to_s =~ /(.*)īre$/
|
206
|
+
return $1 + "iē"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Linguistics
|
5
|
+
module Latin
|
6
|
+
module Verb
|
7
|
+
class LatinVerb
|
8
|
+
##
|
9
|
+
#
|
10
|
+
# Required method for JSON deserialization
|
11
|
+
#
|
12
|
+
##
|
13
|
+
def self.json_create(o)
|
14
|
+
new( o )
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
#
|
19
|
+
# Presents the LatinVerb expressed as a hash with the names of the TenseBlock
|
20
|
+
# specifiers as keys, and corresponding TenseBlock objects, converted to
|
21
|
+
# Arrays, as the values. It also contains the +original_string+.
|
22
|
+
#
|
23
|
+
##
|
24
|
+
def to_hash
|
25
|
+
@tense_list.each do |t|
|
26
|
+
ts = t.to_sym
|
27
|
+
@data_structure[ts]=self.send ts
|
28
|
+
end
|
29
|
+
@data_structure['original_string'] = @original_string
|
30
|
+
return @data_structure
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :to_h, :to_hash
|
34
|
+
|
35
|
+
##
|
36
|
+
#
|
37
|
+
# Takes the hash that results from to_hash and then converts it to
|
38
|
+
# YAML.
|
39
|
+
#
|
40
|
+
##
|
41
|
+
def to_yaml
|
42
|
+
@data_structure.empty? ?
|
43
|
+
to_hash.to_yaml:
|
44
|
+
@data_structure.to_yaml
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :to_y, :to_yaml
|
48
|
+
|
49
|
+
##
|
50
|
+
#
|
51
|
+
# Required method for JSON deserialization
|
52
|
+
#
|
53
|
+
##
|
54
|
+
def to_json(*a)
|
55
|
+
json_hash = {'json_class' => self.class.name}
|
56
|
+
|
57
|
+
# In the case that we're working with a regular verb, the only thing
|
58
|
+
# we need to save is the original string, since everything can be
|
59
|
+
# re-derived from it easily.
|
60
|
+
unless self.irregular?
|
61
|
+
# While this single string is sufficient to freeze and revivifty
|
62
|
+
# the verb, it means that the JSON structure is rather vacuous.
|
63
|
+
# Given this, the hash is enriched so that the JSON data is
|
64
|
+
# useful. Nevertheless, in the revivification process, only
|
65
|
+
# 'orig_string' is used.
|
66
|
+
%w{original_string classification stem}.each do |k|
|
67
|
+
json_hash[k] = self.send k.to_sym
|
68
|
+
end
|
69
|
+
json_hash['tense_list' ] = {}
|
70
|
+
@tense_list.each do |t|
|
71
|
+
json_hash['tense_list'][t.to_s] = self.send t.to_sym
|
72
|
+
end
|
73
|
+
json_hash['irregular'] = irregular?
|
74
|
+
return json_hash.to_json(*a)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
#
|
80
|
+
# Dumps the LatinVerb as pretty JSON
|
81
|
+
#
|
82
|
+
##
|
83
|
+
def pretty_generate
|
84
|
+
JSON.pretty_generate(@data_structure.keys.length < 1 ? to_hash : @data_structure)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Linguistics
|
3
|
+
module Latin
|
4
|
+
module Verb
|
5
|
+
class LatinVerb
|
6
|
+
|
7
|
+
##
|
8
|
+
#
|
9
|
+
# <b>You should not be using this, probably</b>
|
10
|
+
#
|
11
|
+
# This is a a convenience method so that you can print out the
|
12
|
+
# contents in a human-readable fashion. LatinVerb is a library that
|
13
|
+
# _should be implemented elsewhere_ where its results can be presented
|
14
|
+
# by more view-oriented libraries or applications.
|
15
|
+
##
|
16
|
+
def display
|
17
|
+
STDERR.puts "You should not be going much displaying here as this is a LIBRARY. Implement this elsewhere."
|
18
|
+
pretty_generate
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
#--
|
5
|
+
# The purpose of this module is to contain the metaprogramming modules
|
6
|
+
# method_missing and respond_to? in a place that's nice and neat.
|
7
|
+
# ++
|
8
|
+
=end
|
9
|
+
|
10
|
+
module Linguistics
|
11
|
+
module Latin
|
12
|
+
module Verb
|
13
|
+
class LatinVerb
|
14
|
+
|
15
|
+
=begin rdoc
|
16
|
+
|
17
|
+
=== DESCRIPTION
|
18
|
+
|
19
|
+
Override of the method_missing method. A lot of the magic of LatinVerb
|
20
|
+
happens here. This method has deep interactoion with the Verbvector results
|
21
|
+
called as part of the LatinVerb.initialize call path.
|
22
|
+
|
23
|
+
=== INTERNALS
|
24
|
+
|
25
|
+
Given a symbol that is undefined, we look to +@tense_list+ first. The typical
|
26
|
+
case would be a call on a 3/5ths vector identification. Therefore if the call
|
27
|
+
is pure nonsense, the symbol will not be found on the first evaluation and go
|
28
|
+
to super. Assuming that the symbol IS a partial vector call, it will match
|
29
|
+
through the iteration of the values in +@tense_list+. Based on the match, two
|
30
|
+
Regexp values are derived:
|
31
|
+
|
32
|
+
* the first 3/5ths (enough to get a TenseBlock), called a +tense_method+
|
33
|
+
* the last 2/5ths (enough to specify a value out of that TenseBlock), called a +vector_specifier+
|
34
|
+
|
35
|
+
Given those two names, the tense_method is called on the LatinVerb with +send+
|
36
|
+
and _that_ resultant value, a TenseBlock, undergoes a +send+ call to the
|
37
|
+
specifier, thus all 5/5 components of the fully-qualified vector can result in
|
38
|
+
unique match.
|
39
|
+
|
40
|
+
=end
|
41
|
+
def method_missing(symbol, *args ) # :nodoc:
|
42
|
+
super if @tense_list.nil?
|
43
|
+
@tense_list.find do |e|
|
44
|
+
if symbol.to_s.match /^(#{e})_(.*)/
|
45
|
+
tense_method, vector_specifier = $1, $2
|
46
|
+
# This is added to prevent stack-level too deep errors
|
47
|
+
begin
|
48
|
+
# Handle the base case
|
49
|
+
if self.respond_to?(tense_method.to_sym)
|
50
|
+
return send(tense_method.to_sym).send(vector_specifier.to_sym)
|
51
|
+
end
|
52
|
+
rescue SystemStackError => e
|
53
|
+
STDERR.puts "We encountered a SystemStackError when calling #{tense_method}"
|
54
|
+
STDERR.puts "WARNING: Failed to resolve [#{tense_method}] with [#{vector_specifier}]. \n\nMake sure #{tense_method} is defined."
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
#
|
64
|
+
# We override respond_to so that we respond to the normal object
|
65
|
+
# models as well as accept the method_missing utilized names as well.
|
66
|
+
# If it's in +respondable_methods+, we return true.
|
67
|
+
#
|
68
|
+
##
|
69
|
+
def respond_to?(symbol, include_private=false)
|
70
|
+
super if respondable_methods.nil?
|
71
|
+
super if respondable_methods.empty?
|
72
|
+
self.respondable_methods.grep(Regexp.new %Q/^#{symbol}$/).empty? ?
|
73
|
+
super : true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Linguistics
|
4
|
+
module Latin
|
5
|
+
module Verb
|
6
|
+
##
|
7
|
+
# == NAME
|
8
|
+
#
|
9
|
+
# Validation
|
10
|
+
#
|
11
|
+
# == DESCRIPTION
|
12
|
+
#
|
13
|
+
# This module contains the validity testing methods, when mixed into a
|
14
|
+
# LatinVerb, will provide it the ability to ensure its own sanity.
|
15
|
+
#
|
16
|
+
##
|
17
|
+
module Validation
|
18
|
+
|
19
|
+
##
|
20
|
+
#
|
21
|
+
# == DESCRIPTION
|
22
|
+
#
|
23
|
+
# This performs the basic task of evaluating the given string (cf.
|
24
|
+
# LatinVerb.initialize) for basic sanity.
|
25
|
+
#
|
26
|
+
# Here are its basic truths
|
27
|
+
#
|
28
|
+
# 1. Get +@original_string+ as an iVar
|
29
|
+
# 1. Derive a classification (+@classification+) from the string
|
30
|
+
# 1. Determine whether the string qualifies the verb as irregular
|
31
|
+
# 1. Identify a stem (+@stem+), provided the verb is regular
|
32
|
+
#
|
33
|
+
##
|
34
|
+
def valid?
|
35
|
+
os = @original_string
|
36
|
+
instance_eval do
|
37
|
+
begin
|
38
|
+
@classification = Linguistics::Latin::Verb::LatinVerb.classify(os)
|
39
|
+
@irregular =
|
40
|
+
@classification == Linguistics::Latin::Verb::VerbTypes::Irregular ?
|
41
|
+
true : false
|
42
|
+
unless @irregular
|
43
|
+
@stem ||= self.class.calculate_stem os.split(/\s+/)[1]
|
44
|
+
@deponent = (@classification == Linguistics::Latin::Verb::VerbTypes::Deponent) ?
|
45
|
+
true : false
|
46
|
+
@semideponent = (@classification == Linguistics::Latin::Verb::VerbTypes::Semideponent) ?
|
47
|
+
true : false
|
48
|
+
@impersonal= (@classification == Linguistics::Latin::Verb::VerbTypes::Impersonal) ?
|
49
|
+
true : false
|
50
|
+
end
|
51
|
+
rescue RuntimeError => detail
|
52
|
+
STDERR.puts "WARNING: Improper use of rescue for decision structure in latinverb_validation"
|
53
|
+
@irregular = true
|
54
|
+
rescue Exception => e
|
55
|
+
@classification_error = lambda do
|
56
|
+
raise e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|