latinverb 0.2.0 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|