latinverb 0.2.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +0 -1
  2. data/Gemfile +1 -2
  3. data/README.markdown +54 -240
  4. data/etc/irreg_skel.json +104 -0
  5. data/{latinirb.gemspec → latinverb.gemspec} +4 -4
  6. data/lib/latinverb/chart.rb +94 -0
  7. data/lib/latinverb/version.rb +10 -0
  8. data/lib/latinverb.rb +710 -0
  9. data/lib/linguistics/latin/verb/classification_types.rb +59 -0
  10. data/lib/linguistics/latin/verb/constants.rb +201 -0
  11. data/lib/linguistics/latin/verb/deponent_tense_methods.rb +98 -0
  12. data/lib/linguistics/latin/verb/infinitives.rb +212 -0
  13. data/lib/linguistics/latin/verb/irregulars.rb +4393 -0
  14. data/lib/linguistics/latin/verb/latinverb/auxiliary_classes.rb +208 -0
  15. data/lib/linguistics/latin/verb/latinverb/classmethods.rb +215 -0
  16. data/lib/linguistics/latin/verb/latinverb/data.rb +90 -0
  17. data/lib/linguistics/latin/verb/latinverb/display.rb +23 -0
  18. data/lib/linguistics/latin/verb/latinverb/metaprogramming.rb +79 -0
  19. data/lib/linguistics/latin/verb/latinverb/validation.rb +66 -0
  20. data/lib/linguistics/latin/verb/participles.rb +202 -0
  21. data/lib/linguistics/latin/verb/phonographia.rb +109 -0
  22. data/lib/linguistics/latin/verb/supine.rb +42 -0
  23. data/lib/linguistics/latin/verb/tense_methods.rb +950 -0
  24. data/test/testAmbiguousLookups.rb +30 -0
  25. data/test/testClusterResolution.rb +20 -0
  26. data/test/testDataStructures.rb +29 -0
  27. data/test/testDefectSemiImp.rb +111 -0
  28. data/test/testDeponentFirstConjugation.rb +64 -0
  29. data/test/testDeponentFourthConjugation.rb +64 -0
  30. data/test/testDeponentSecondConjugation.rb +64 -0
  31. data/test/testDeponentThirdConjugation.rb +64 -0
  32. data/test/testDeponentThirdIOConjugation.rb +64 -0
  33. data/test/testDeserializeInfinitives.rb +38 -0
  34. data/test/testFirstConjugation.rb +388 -0
  35. data/test/testFourthConjugation.rb +190 -0
  36. data/test/testFreakishVerbs.rb +93 -0
  37. data/test/testImperativeBlock.rb +27 -0
  38. data/test/testIrregularSum.rb +22 -0
  39. data/test/testIrregulars.rb +652 -0
  40. data/test/testLatinVerb.rb +195 -0
  41. data/test/testMacronRules.rb +19 -0
  42. data/test/testSecondConjugation.rb +189 -0
  43. data/test/testThirdConjugation.rb +190 -0
  44. data/test/testThirdIOConjugation.rb +190 -0
  45. metadata +70 -18
  46. data/bin/latinirb.rb +0 -7
  47. data/latinverb.rb +0 -544
  48. data/lib/LatinIRB.rb +0 -172
  49. data/lib/latinirb/paradigmatic_verbs.rb +0 -17
  50. data/lib/latinirb/version.rb +0 -10
  51. data/lib/latirb.rb +0 -20
data/lib/latinverb.rb ADDED
@@ -0,0 +1,710 @@
1
+ # encoding: UTF-8
2
+ #------------------------------------------------------------------------------
3
+ # DEPENDENCIES
4
+ #------------------------------------------------------------------------------
5
+ # External dependencies
6
+ require 'verbvector'
7
+ require 'yaml'
8
+ require 'json'
9
+ require 'active_support'
10
+
11
+ ##
12
+ #--
13
+ # Internal dependencies
14
+ # If the library is in the latin/verb, then it is a feature of the actual
15
+ # Latin language as abstracted into Ruby. If it is in the latin/verb/latinverb directory, it is part
16
+ # of the mechanics of the representation of that language as Ruby, i.e. this
17
+ # program. It's the difference between "This is part of Latin" and "This is
18
+ # Part of the machinery I use to represent Latin in Ruby."
19
+ #++
20
+ ##
21
+
22
+ require 'linguistics/latin/verb/classification_types'
23
+ require 'linguistics/latin/verb/tense_methods'
24
+ require 'linguistics/latin/verb/deponent_tense_methods'
25
+ require 'linguistics/latin/verb/supine'
26
+ require 'linguistics/latin/verb/phonographia'
27
+ require 'linguistics/latin/verb/constants'
28
+ require 'linguistics/latin/verb/infinitives'
29
+ require 'linguistics/latin/verb/participles'
30
+ require 'linguistics/latin/verb/irregulars'
31
+
32
+ require 'linguistics/latin/verb/latinverb/classmethods'
33
+ require 'linguistics/latin/verb/latinverb/metaprogramming'
34
+ require 'linguistics/latin/verb/latinverb/validation'
35
+ require 'linguistics/latin/verb/latinverb/data'
36
+ require 'linguistics/latin/verb/latinverb/display'
37
+
38
+ require 'latinverb/version'
39
+ require 'latinverb/chart.rb'
40
+
41
+ =begin rdoc
42
+
43
+ ==DESCRIPTION
44
+
45
+ Linguistics is a module that forms a primordial node for storing Modules and classes dealing with lingustics. The namespace is immediately sub-divided by language (e.g. Latin, Spanish) then part of speech (e.g. Noun, Verb) or function (e.g. Phonographia).
46
+
47
+ =end
48
+
49
+ module Linguistics
50
+ # Generalized module for handling lingustics related to Latin
51
+ module Latin
52
+ # Generalized module for handling lingustics related to Latin's verbal aspects
53
+ module Verb
54
+ ##
55
+ # == SYNOPSIS
56
+ #
57
+ # Abstraction of a Verb in the Latin language.
58
+ #
59
+ # == DESCRIPTION
60
+ #
61
+ # LatinVerb is:
62
+ # * a tool to help the student of Latin understand the rules of
63
+ # conjugation's heuristics by presenting said heuristics in Ruby
64
+ # * a way to get out of having to lug the 501 Latin Verbs book around
65
+ # (when wrapped in an application ;) )
66
+ # * a way to discover some of the interesting metacongnitive structures
67
+ # between natural language and programming language
68
+ # * <em>...and so much more...</em>
69
+ #
70
+ # === OPERATION
71
+ #
72
+ # LatinVerb operates by instantiating a LatinVerb based on a string
73
+ # containing the "four principal parts" that are used to describe a
74
+ # Latin verb. From this simple entry, one calls "vectors' upon the
75
+ # object. Vectors represent the unique, "fully-qualified" locus of a
76
+ # conjugated form. A feature that was of paramount importance in its
77
+ # implementation was that the conjugation <b>should occur by
78
+ # heruristic</b> in the exact same way that <b>humans have been
79
+ # taught</b> in Latin classes for _milennia_!
80
+ #
81
+ # An example should illustrate:
82
+ #
83
+ # === EXAMPLE
84
+ #
85
+ # <pre>
86
+ # to_love = LatinVerb.new("amō amāre amāvī amatum")
87
+ # to_love.active_voice_indicative_mood_present_tense_second_person_singular_number #=> amās
88
+ # to_love.active_voice_indicative_mood_present_tense_third_person_singular_number #=> amat
89
+ # </pre>
90
+ #
91
+ # === EXPLICATION
92
+ #
93
+ # Considering the above example, when the object was insantiated, it
94
+ # realized what its conjugation was, realized what its stem ("amā") was,
95
+ # and then added to itself support for
96
+ # <tt>active_voice_indicative_mood_present_tense</tt> which is defined
97
+ # as "take the stem and postpend "ō, s, t, mus, tis, nt" to the stem and
98
+ # return it as an array. It is through (mis-?)use of method_missing
99
+ # that this simple "vector" method for interfacing with a verb is
100
+ # possible. <em>Puto hoc bonum esse</em>.
101
+ #
102
+ # === MACRONS / QUANTITY
103
+ #
104
+ # In reference texts, quanitiy of vowel duration ("long" or "short") is
105
+ # marked with a macron. *LatinVerb assumes it will be provided strings
106
+ # with macrons*. This makes sense as per the previous section, the
107
+ # conjugation is done by heuristic. What isn't there cannot be altered.
108
+ # <em>Si hoc non aderit, non mutabitur</em>. To make this easier I
109
+ # wrote the MacronConversion library which supports conversion of
110
+ # LaTeX-styled ASCII macron transgraphia (e.g. \={a} => ā).
111
+ #
112
+ #
113
+ # === REFERENCE
114
+ #
115
+ # ==== Voices
116
+ # A&G Sec. 156:
117
+ #
118
+ # The Active and Passive Voices in Latin generally correspond to the
119
+ # active and passive in English; but --
120
+ #
121
+ # a. The passive voice often has a reflexive meaning: --
122
+ # b. Many verbs are passive in form, but active or reflexive in
123
+ # meaning. These are called Deponents (sec 190.)...
124
+ # c. Some verbs with active meaning have the passive form in the
125
+ # perfect tenses; these are called Semi-Deponents
126
+ #
127
+ # ==== Moods
128
+ #
129
+ # a. The Indicative Mood is used for most <em>direct assertions</em>
130
+ # and <em>interrogations</em>
131
+ # b. The Subjunctive Mood has many idiomatic uses, as in
132
+ # <em>commands</em>, <em>conditions</em>, and various <em>dependent
133
+ # clauses</em>.
134
+ # c. The Imperative is used for <em>exhortation</em>,
135
+ # <em>entreaty</em>, or <em>command</em>; but the Subjunctive is often
136
+ # used instead
137
+ #
138
+ # === WORKS CITED
139
+ #
140
+ # Allen, J.H. Allen and Greenough's New Latin Grammar. Dover,
141
+ # Mineola: 2006. Cited herein as "A&G."
142
+ #
143
+ # Wheelock, Frederic M. Wheelock's Latin. Collins, New York: 2005.
144
+ # Cited herein as "Wheelock."
145
+ #
146
+ ##
147
+ class LatinVerb
148
+ # Modules used to validate the input in initialize
149
+ include Linguistics::Latin::Verb::Validation
150
+ include Linguistics::Latin::Verb::Participles
151
+ include Linguistics::Latin::Verb::Infinitives
152
+
153
+ # Attributes for storing submitted data. This will help remember the origin state
154
+ attr_reader :original_string
155
+
156
+ # Attributes for storing calculated status.
157
+ attr_reader :classification, :classification_error, :principal_parts,
158
+ :four_pp, :irregular, :stem, :first_pers_singular, :pres_act_inf,
159
+ :first_pers_perf, :pass_perf_part, :participial_stem, :verb_methods,
160
+ :data_structure
161
+
162
+ # Access the Module that provides all the methods
163
+ attr_reader :latin_verbvector_generator, :latin_verb_methods
164
+
165
+ # Accessors for "odd forms"
166
+ attr_reader :present_only
167
+
168
+ alias_method :conjugation, :classification
169
+ alias_method :irregular?, :irregular
170
+
171
+ ##
172
+ #
173
+ # The constructor for a Latinverb
174
+ #
175
+ # ===ARGUMENTS
176
+ #
177
+ # *s:* :: +s+ is class-tested and supports String or Hash classes,
178
+ # with the standard path having been designed to accept a string
179
+ # containing 4 words ("four principal parts"). Latin's principal
180
+ # irregular verbs are also accepted (see CONSTANTS) as possible
181
+ # entries. +s+ also accepts a Hash as input. This is used for
182
+ # deserialization from JSON which initialized based on a Hash.
183
+ #
184
+ # == SEE ALSO
185
+ #
186
+ # #initialize does very little work. Therefore special attention
187
+ # should be paid to the #_init_by_string and _add_vector_methods.
188
+ # These are the workhorses of this class and do most of the decoration
189
+ # activity. In the case of extending to support irregular verbs,
190
+ # #_irregular_handler is a critical path to explore.
191
+ #
192
+ # == TODO
193
+ #
194
+ # * Array support for the argument
195
+ #
196
+ ##
197
+ def initialize(s)
198
+ raise SyntaxError if s.nil?
199
+
200
+ if s.class == String
201
+ _init_by_string(s)
202
+ _impersonal_handler if @impersonal
203
+ _irregular_handler if @irregular
204
+ _deponent_handler if ( @deponent || @semideponent )
205
+ end
206
+
207
+ if (s.class == Hash )
208
+ if (s['irregular'] == false and
209
+ s.has_key?('original_string'))
210
+ # We're restoring a standard verb
211
+ _init_by_string(s['original_string'])
212
+ end
213
+ end
214
+
215
+ if s.class == Array
216
+ # TODO: Fill this out.
217
+ end
218
+
219
+ # Load up the specialized vector complement of methods
220
+ #
221
+ unless @impersonal
222
+ _add_vector_methods
223
+
224
+ # Given the use of method_missing to handle resolution, it's wise to
225
+ # make sure that every cluster method /is/ actually defined.
226
+ @tense_list.each do |m|
227
+ raise "FAILURE: Critical method #{m} was not defined." unless
228
+ (self.respond_to? m.to_sym)
229
+ end
230
+ end
231
+
232
+ # Placeholder the data structure that holds all the answers (a hash
233
+ # of TenseBlocks). This may be the typical case, but the
234
+ # calculation is an expensive operation compared to the simple
235
+ # vector query, so this won't actually get defined unless #to_hash
236
+ # is called (cf. latinverb/display).
237
+ # TODO: This probably needs some work, make it useful in the
238
+ # to_json methods
239
+
240
+ @data_structure = {}
241
+
242
+ # In a bit of cleverness, if the verb is deponent, we have built out
243
+ # this verb as if it were regular, but we have also created a
244
+ # @proxyVerb which is the active 'pseudo verb' corresponding to this
245
+ # verb. We should be able to take this verb's active formulations
246
+ # and set their results to the @proxyVerb's passive formulations
247
+ #
248
+ # Ergo: miror/mirari/miratus =~ miro/mirare/JUNK/miratus
249
+ # Therefore make a LatinVerb.new(miro/mirare/JUNK/miratus). Take
250
+ # its passives and set them to this verb's actives. This is
251
+ # actually what students do heuristically in Latin classes.
252
+ apply_deponent_masking if @deponent
253
+
254
+ # Previously @deponent and @semideponent followed the same paths,
255
+ # but in semideponents, the "present system" is handled as normal
256
+ # (completed by _add_vector_methods, supra). We need only mask, as
257
+ # A&G #192 says: "the completed methods" i.e. the perfect system.
258
+ apply_semideponent_masking if @semideponent
259
+
260
+ # Per A&G206, some verbs are to have their perfect system
261
+ # conjugations removed.
262
+ remove_perfect_tenses if present_only?
263
+ end
264
+
265
+ ######################################################################
266
+ # Instance methods
267
+ ######################################################################
268
+
269
+ ##
270
+ #
271
+ # Some verbs only take a active/indic/pres/3rd/sg ("it rains"). For
272
+ # these we will not add the full vectors of methods, but will only
273
+ # respond to THAT vector. It's a bit of an identity relationship and
274
+ # seems a bit silly to return, but I think it keeps the proper
275
+ # completeness
276
+ #
277
+ ##
278
+
279
+ def _impersonal_handler
280
+ singleton_class.class_eval do
281
+ def active_voice_indicative_mood_present_tense
282
+ TenseBlock.new ["", "", @original_string,
283
+ "", "", ""]
284
+ end
285
+ def active_voice_indicative_mood_present_tense_third_person_singular_number
286
+ return active_voice_indicative_mood_present_tense[2]
287
+ end
288
+ end
289
+ end
290
+
291
+ ##
292
+ #
293
+ # Removes perfect-system tenses by blanking them out.
294
+ #
295
+ ##
296
+ def remove_perfect_tenses
297
+ # Get perfect system methods
298
+ tense_blocks_to_eclipse =
299
+ self.methods.grep /^(active|passive).*(_|past|future)perfect_/
300
+
301
+ # Re-assgin their methods to point to a blank TenseBlock, thus
302
+ # eclipsing any values thatm ight come in.
303
+ tense_blocks_to_eclipse.each do |s|
304
+ singleton_class.class_eval do
305
+ define_method s do
306
+ return TenseBlock.new [ '', '', '', '', '', '']
307
+ end
308
+ end
309
+ end
310
+ end
311
+
312
+ ##
313
+ #
314
+ # Determines whether a verb should have its perfect tenses removed.
315
+ # This is an exceptional behavior described in A&G206
316
+ #
317
+ ##
318
+
319
+ def present_only?
320
+ @present_only =
321
+ (
322
+ Linguistics::Latin::Verb::LatinVerb::PRESENT_ONLY.member?(@pres_act_inf) ||
323
+ Linguistics::Latin::Verb::LatinVerb::PRESENT_ONLY.member?(@first_pers_singular)
324
+ ) ? true : false
325
+ end
326
+ ##
327
+ #
328
+ # Imports replacements to the standard tense_methods and thus
329
+ # overwrites the old method definitions defined by verbvector
330
+ #
331
+ ##
332
+ def apply_semideponent_masking
333
+ self.singleton_class.class_eval do
334
+ include Linguistics::Latin::Verb::DeponentTenseMethods
335
+ end
336
+ end
337
+
338
+ ##
339
+ #
340
+ # Top-level method used to call the sub-methods which create a facade so that
341
+ # active_ vectors can be called on a deponent which actually forwards that
342
+ # call to a "fake" non-deponent (+@proxyVerb+) whose passives fit the correct
343
+ # morphology
344
+ #
345
+ # It calls the following methods, each of which applies the masking to a
346
+ # certain collection of vectors:
347
+ #
348
+ # * +deponent_swap+ :: active_voice* remaps "standard" calls like
349
+ # +active_voice_indicative_mood_present_tense...+
350
+ # * +deponent_imperative_mutations+ :: masks the imperatives
351
+ # * +deponent_participle_mutations+ :: masks the participles
352
+ # * +deponent_infinitive_mutations+ :: masks the infinitives
353
+ #
354
+ ##
355
+ def apply_deponent_masking
356
+ deponent_swap
357
+ deponent_imperative_mutations
358
+ deponent_participle_mutations
359
+ deponent_infinitive_mutations
360
+ end
361
+
362
+ ##
363
+ #
364
+ # The deponent's imperatives require a bit of consideration. They don't
365
+ # follow the stem/stem+'ite' format.
366
+ #
367
+ ##
368
+
369
+ def deponent_imperative_mutations # :nodoc:
370
+ self.singleton_class.class_eval do
371
+ def active_voice_imperative_mood_present_tense_second_person_singular_number
372
+ return @proxyVerb.instance_variable_get '@pres_act_inf'
373
+ end
374
+ def active_voice_imperative_mood_present_tense_second_person_plural_number
375
+ return @proxyVerb.send :passive_voice_indicative_mood_present_tense_second_person_plural_number
376
+ end
377
+ def active_voice_imperative_mood_future_tense_second_person_singular_number
378
+ k=@proxyVerb.send :passive_voice_indicative_mood_present_tense_second_person_plural_number
379
+ k.sub! /minī$/, ''
380
+ k += 'tor'
381
+ Linguistics::Latin::Phonographia.fix_macrons k
382
+ end
383
+ end
384
+ end
385
+
386
+ def deponent_participle_mutations # :nodoc:
387
+ self.singleton_class.class_eval do
388
+ def present_active_participle
389
+ return @proxyVerb.present_active_participle
390
+ end
391
+
392
+ def future_active_participle
393
+ return @proxyVerb.future_active_participle
394
+ end
395
+
396
+ def perfect_active_participle
397
+ return @proxyVerb.perfect_passive_participle
398
+ end
399
+
400
+ def future_passive_participle
401
+ return @proxyVerb.future_passive_participle
402
+ end
403
+
404
+ # Mask the supine
405
+ def supine
406
+ return @proxyVerb.supine
407
+ end
408
+ end
409
+ end
410
+
411
+ def deponent_infinitive_mutations # :nodoc:
412
+ self.singleton_class.class_eval do
413
+ def present_active_infinitive
414
+ return @proxyVerb.send :present_passive_infinitive
415
+ end
416
+ def perfect_active_infinitive
417
+ return @proxyVerb.send :perfect_passive_infinitive
418
+ end
419
+ def future_active_infinitive
420
+ return @proxyVerb.send :future_active_infinitive
421
+ end
422
+ end
423
+ end
424
+
425
+ ##
426
+ #
427
+ # Swaps this verb's active_ vectors and replaces them with
428
+ # @proxyVerb's passive_ vectors. This is pretty darned sneaky. See
429
+ # Also deponent_swap
430
+ #
431
+ ##
432
+ def deponent_swap
433
+ # First, get the methods that were defined in the proxy as passive
434
+
435
+ storage = {}
436
+
437
+ @proxyVerb.methods.grep(/^passive/).each do |pass|
438
+ # Find the active correlate
439
+ active_corr = pass.to_s.sub /^passive(.*)/, "active\\1"
440
+
441
+ # Keep @proxyVerb in the binding scope
442
+ pV = @proxyVerb
443
+
444
+ # In self, find the passive and save it's resultant object into a
445
+ # hash for future use.
446
+ self.singleton_class.class_eval do
447
+ storage[active_corr.to_sym] = pV.send(pass)
448
+ end
449
+ end
450
+
451
+ # Take the stored hashes and define instance methods on self such
452
+ # that we intercept the mixed-in methods ( C-c-c-combo breaker! ).
453
+ storage.each_pair do |k,v|
454
+ self.singleton_class.class_eval do
455
+ define_method k, lambda { return v }
456
+ end
457
+ end
458
+ end
459
+
460
+ # Returns the "short" version, sans the module specifier. in previous
461
+ # versions, the classification was expressed as a String. While this
462
+ # had a certain amount of simplicity, building function is based on
463
+ # these classifications seems a linkely future direction.
464
+ #
465
+ # Furthermore, it is not the case that these are actuallly Strings,
466
+ # they are entities of an ontological sttus of their own and it seems
467
+ # "off" to consider them as mere strings.
468
+ def short_class
469
+ return @classification.to_s.gsub(/.*::(\w+)$/,"\\1")
470
+ end
471
+
472
+ ##
473
+ #
474
+ # Returns the four principal parts and regularity designation
475
+ ##
476
+ def to_s
477
+ return "#{self.class}: [EMPTY PP]" if @four_pp.nil?
478
+ return self.class if @four_pp.empty?
479
+ @four_pp.join(', ') + " [Irregular?: #{@irregular.to_s}]"
480
+ end
481
+
482
+ ##
483
+ #
484
+ # When working in irb or LatinIRB it's good to find out what the
485
+ # instance methods are on this
486
+ def instance_methods
487
+ self.latin_verbvector_generator.vector_list
488
+ end
489
+
490
+ private
491
+
492
+ def _deponent_handler
493
+ @proxyVerb = Linguistics::Latin::Verb::LatinVerb.new @deponent_proxy
494
+ end
495
+
496
+ def _irregular_handler
497
+ begin
498
+ # Translation added to account for Ruby not liking constants /^/
499
+ # with a multibyte. Probably a bug.
500
+ #
501
+ # This buy can be discovered by running #constants on
502
+ # Linguistics::Latin::Verb and seeing that Ōxxx is not found. To
503
+ # fix this i had to store it as ODI_. To make /that/ hack work, I
504
+ # had to add this bit beginning two lines below :-/
505
+ o = ActiveSupport::Multibyte::Chars.new( @original_string.gsub(/\s+/,'_') ).upcase
506
+
507
+ if o.match /^([ĀĒĪŌŪ])(.*)/
508
+ x=o[0,1].tr 'ĀĒĪŌŪ', 'AEIOU'
509
+ y=o[1,o.length]
510
+ o= x+y
511
+ end
512
+
513
+ o_upcase_and_symbolic = o.to_sym
514
+ json_string = Linguistics::Latin::Verb.const_get o_upcase_and_symbolic
515
+
516
+
517
+ raise "Found a JSON string with null length!" if json_string.length <= 10
518
+ revivified_data_structure = JSON.parse json_string
519
+ rescue JSON::ParserError => e
520
+ puts "We were unable to parse JSON for #{@original_string} [o:#{o}] [o_sym:#{o_upcase_and_symbolic}]. Please verify your syntax."
521
+ raise e
522
+ rescue NameError => e
523
+ puts "We were unable to find a definition for #{@original_string} [o:#{o}] [o_sym:#{o_upcase_and_symbolic}]. Please provide one."
524
+ raise e
525
+ rescue => error
526
+ warn "#{@original_string} was identified as irregular but did not have a definition provided."
527
+ raise error
528
+ end
529
+
530
+ revivified_data_structure['tense_blocks'].each_pair do |k,v|
531
+ singleton_class.class_eval do
532
+ define_method k.to_sym do
533
+ TenseBlock.new v, { :meaning => MEANINGS[k.to_sym] }
534
+ end
535
+ end
536
+ end
537
+
538
+ @irregular_infinitives = revivified_data_structure['infinitives']
539
+ @irregular_participles = revivified_data_structure['participles']
540
+
541
+ return if @irregular_infinitives.nil?
542
+ return if @irregular_participles.nil?
543
+
544
+ singleton_class.class_eval do
545
+ def present_active_infinitive; return @irregular_infinitives.present_active_infinitive; end
546
+ def present_passive_infinitive; return @irregular_infinitives.present_passive_infinitive; end
547
+ def perfect_active_infinitive; return @irregular_infinitives.perfect_active_infinitive; end
548
+ def perfect_passive_infinitive; return @irregular_infinitives.perfect_passive_infinitive; end
549
+ def future_passive_infinitive; return @irregular_infinitives.future_passive_infinitive; end
550
+ def future_active_infinitive; return @irregular_infinitives.future_active_infinitive; end
551
+ end
552
+ singleton_class.class_eval do
553
+ def present_active_participle; return @irregular_participles.present_active_participle; end
554
+ def future_active_participle; return @irregular_participles.future_active_participle; end
555
+ def perfect_passive_participle; return @irregular_participles.perfect_passive_participle; end
556
+ def future_passive_participle; return @irregular_participles.future_passive_participle; end
557
+ def gerundive; return @irregular_participles.gerundive; end
558
+ def gerund; return @irregular_participles.d; end
559
+ end
560
+
561
+ end
562
+
563
+ def respondable_methods
564
+ end
565
+
566
+ def _init_by_string(s)
567
+ # Store the original input
568
+ @original_string = s
569
+ @classification_error = nil
570
+
571
+ # pre-validate the string
572
+ self.valid?
573
+
574
+ # If the error callback has been created, then call it
575
+ @classification_error.call unless @classification_error.nil?
576
+
577
+ # Derive from the original, valid string useful specifiers in handy data structures
578
+
579
+ unless ( @deponent or @semideponent or @impersonal)
580
+ _derive_parts_from_given_string s
581
+
582
+ # Derive iVar from derived variables
583
+ (@participial_stem ||= calculate_participial_stem) unless @irregular
584
+ else
585
+ unless @impersonal
586
+ fake_string = Linguistics::Latin::Verb::LatinVerb.create_pseudo_active_mask_for_deponent(s)
587
+ #_derive_parts_from_given_string fake_string
588
+ @deponent_proxy = fake_string
589
+ end
590
+ end
591
+
592
+ end
593
+
594
+ def _add_vector_methods
595
+ ##
596
+ # Generates all the methods to which a verb must be able to respond
597
+ # by implementing Linguistics::Verbs::Verbvector::VerbvectorGenerator.
598
+ #
599
+ # This conforms to the definition provided in Allen & Greenough Sec.
600
+ # 154:
601
+ #
602
+ # Through its conjugation the Verb expresses Voice, Mood, Tense
603
+ # Person, and Number.
604
+ #
605
+ # a. The Voices are two: Active and Passive
606
+ # b. The Moods are four: Indicative,Subjuncitve, Imperative, and
607
+ # Infinitive
608
+ #
609
+ # ...
610
+ #
611
+ # c. The Tenses are six, viz: --
612
+ # 1. For continued action: Present, Imperfect, Future
613
+ # 2. For completed action, Perfect, Pluperfect, Future Perfect
614
+ #
615
+ # The Indicative Mood has all six tenses, but the Subjunctive has
616
+ # no future or future perfect and the Imperative has only the
617
+ # present and the future. The Infinitive has the present, perfect,
618
+ # and future.
619
+ #
620
+ # d. The Persons are three: First, Secon, Third.
621
+ # e. The Numbers are two: Singular and Plural
622
+ ##
623
+ @latin_verbvector_generator =
624
+ Linguistics::Verbs::Verbvector::VerbvectorGenerator.new do
625
+ language :Latin do
626
+ all_vectors :start_with do
627
+ {
628
+ :voice => %w(active passive),
629
+ :mood => %w(indicative subjunctive imperative)
630
+ }
631
+ end
632
+ vectors_that /.*_indicative_mood/ do
633
+ {
634
+ :tense => %w(present imperfect future
635
+ perfect pastperfect futureperfect)
636
+ }
637
+ end
638
+ vectors_that /.*_subjunctive_mood/ do
639
+ {
640
+ :tense => %w(present imperfect
641
+ perfect pastperfect)
642
+ }
643
+ end
644
+ vectors_that /.*_imperative_mood/ do
645
+ {
646
+ :tense => %w(present future)
647
+ }
648
+ end
649
+ all_vectors :end_with do
650
+ {
651
+ :person => %w(first second third),
652
+ :number => %w(singular plural)
653
+ }
654
+ end
655
+ exception :remove, :passive_voice_imperative_mood_present_tense
656
+ exception :remove, :passive_voice_imperative_mood_future_tense
657
+ cluster_on :tense, "as method", :tense_list
658
+ end
659
+ end
660
+
661
+ # This provides methods of the form #{language_name}_#{fake_name}.
662
+ # They are actually called sans #{language_name} so that
663
+ # method_missing is called.
664
+ @verb_methods = @latin_verbvector_generator.method_extension_module
665
+
666
+ # Make sure all the cluster methods are defined. Ensure we don't
667
+ # get infinite stack method_missing lookups
668
+ @tense_list =
669
+ @latin_verbvector_generator.cluster_methods[:tense_list].call
670
+
671
+ # POWER-UP with the vector methods
672
+ self.extend @verb_methods
673
+ end
674
+
675
+ def _derive_parts_from_given_string(s)
676
+ @principal_parts
677
+ @first_pers_singular,
678
+ @pres_act_inf,
679
+ @first_pers_perf,
680
+ @pass_perf_part = @four_pp = @principal_parts = s.split(/\s+/)
681
+ end
682
+
683
+ def calculate_participial_stem
684
+ raise("@pres_act_inf was nil!") if
685
+ @pres_act_inf.nil? or @first_pers_singular.nil?
686
+
687
+ if @pres_act_inf.to_s =~ /(.*ā)re$/
688
+ return $1
689
+ end
690
+
691
+ if @pres_act_inf.to_s =~ /(.*ē)re$/
692
+ return $1
693
+ end
694
+
695
+ if @pres_act_inf.to_s =~ /(.*)ere$/
696
+ match=$1
697
+ if @first_pers_singular =~ /iō/
698
+ return match + "iē"
699
+ else
700
+ return match + "e"
701
+ end end
702
+
703
+ if @pres_act_inf.to_s =~ /(.*)īre$/
704
+ return $1 + "iē"
705
+ end
706
+ end
707
+ end
708
+ end
709
+ end
710
+ end