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.
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