verbs 2.2.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +14 -14
- data/.gitignore +2 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +55 -0
- data/CHANGELOG.md +161 -0
- data/Gemfile +3 -1
- data/README.md +85 -0
- data/Rakefile +7 -4
- data/bin/console +15 -0
- data/lib/verbs/conjugations.rb +201 -31
- data/lib/verbs/conjugator.rb +128 -78
- data/lib/verbs/improper_construction.rb +3 -1
- data/lib/verbs/verb.rb +21 -12
- data/lib/verbs/verblike.rb +6 -4
- data/lib/verbs/version.rb +3 -1
- data/lib/verbs.rb +10 -3
- data/tasks/release.rake +8 -0
- data/test/helper.rb +2 -3
- data/test/test_verbs.rb +348 -105
- data/verbs.gemspec +16 -14
- metadata +28 -9
- data/README.rdoc +0 -77
- data/VERSION +0 -1
data/lib/verbs/conjugator.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# The program conjugates most common english verbs with the following option:
|
2
|
-
# * :tense => :past or :present or :future
|
3
|
-
# * :person => :first or :second or :third
|
4
|
-
# * :plurality => :singular or :plural
|
5
|
-
# * :aspect => :habitual or :perfect or :perfective or :progressive or :prospective
|
6
|
-
# * :mood => :indicative or :imperative or :subjunctive
|
7
|
-
#
|
4
|
+
# * :tense => :past or :present or :future (default: :present)
|
5
|
+
# * :person => :first or :second or :third (default: :third)
|
6
|
+
# * :plurality => :singular or :plural (default: :singular)
|
7
|
+
# * :aspect => :habitual or :perfect or :perfective or :progressive or :prospective (default: :habitual, or :perfective for past tense)
|
8
|
+
# * :mood => :indicative or :imperative or :subjunctive (default: :indicative)
|
9
|
+
# * :diathesis => :active or :passive (default: :active)
|
8
10
|
#
|
9
11
|
# Author:: Andy Rossmeissl
|
10
12
|
# Copyright:: Copyright (c) 2009 Andy Rossmeissl
|
@@ -24,7 +26,9 @@ module Verbs
|
|
24
26
|
|
25
27
|
# Creates initial variables for class
|
26
28
|
def initialize
|
27
|
-
@irregulars
|
29
|
+
@irregulars = {}
|
30
|
+
@single_terminal_consonants = []
|
31
|
+
@copulars = {}
|
28
32
|
end
|
29
33
|
|
30
34
|
# Determines irregular verbs from the expression
|
@@ -38,9 +42,13 @@ module Verbs
|
|
38
42
|
# create new Verb object with infinitive and &blk
|
39
43
|
irregular = ::Verbs::Verb.new infinitive, &blk
|
40
44
|
else
|
41
|
-
|
45
|
+
unless preterite && past_participle
|
46
|
+
raise ArgumentError,
|
47
|
+
'Standard irregular verbs must specify preterite and past participle forms'
|
48
|
+
end
|
49
|
+
|
42
50
|
# create new Verb object with infinitive, preterite and past_participle
|
43
|
-
irregular = ::Verbs::Verb.new infinitive, :
|
51
|
+
irregular = ::Verbs::Verb.new infinitive, preterite: preterite, past_participle: past_participle
|
44
52
|
end
|
45
53
|
@irregulars[infinitive] = irregular
|
46
54
|
end
|
@@ -77,10 +85,10 @@ module Verbs
|
|
77
85
|
plurality = options[:plurality] || :singular # singular, plural
|
78
86
|
diathesis = options[:diathesis] || :active # active, passive
|
79
87
|
mood = options[:mood] || :indicative # imperative, subjunctive
|
80
|
-
aspect = options[:aspect] ||
|
88
|
+
aspect = options[:aspect] || default_aspect(options) # perfective, habitual, progressive, perfect, prospective
|
81
89
|
|
82
|
-
check_for_improper_constructions(tense, person, mood)
|
83
|
-
form = form_for(tense, aspect)
|
90
|
+
check_for_improper_constructions(infinitive, tense, person, mood, diathesis) # find incompatabilities
|
91
|
+
form = form_for(tense, aspect, diathesis) # find form array based on tense and aspect
|
84
92
|
|
85
93
|
# map form array to conjugation array, applying infinitive and options to the array
|
86
94
|
conjugation = form.map { |e| resolve e, infinitive, tense, person, plurality, mood }.join(' ').strip
|
@@ -99,15 +107,15 @@ module Verbs
|
|
99
107
|
# * options, list of options given to determine conjugation
|
100
108
|
def subject(options)
|
101
109
|
case [options[:person], options[:plurality]]
|
102
|
-
when [
|
110
|
+
when %i[first singular]
|
103
111
|
'I'
|
104
|
-
when [
|
112
|
+
when %i[first plural]
|
105
113
|
'we'
|
106
|
-
when [
|
114
|
+
when %i[second singular], %i[second plural]
|
107
115
|
'you'
|
108
|
-
when [
|
116
|
+
when %i[third singular]
|
109
117
|
'he'
|
110
|
-
when [
|
118
|
+
when %i[third plural]
|
111
119
|
'they'
|
112
120
|
end
|
113
121
|
end
|
@@ -143,13 +151,13 @@ module Verbs
|
|
143
151
|
# * plurality, an option given by the user
|
144
152
|
# * mood, an option given by the user
|
145
153
|
def inflect(infinitive, inflection, person, plurality, mood)
|
146
|
-
send(*
|
154
|
+
send(*[inflection, infinitive, person, plurality, mood][0, method(inflection).arity + 1])
|
147
155
|
end
|
148
156
|
|
149
157
|
def present(infinitive, person, plurality, mood)
|
150
|
-
if verb = conjugations.irregulars[infinitive]
|
151
|
-
conjugate_irregular(verb, :
|
152
|
-
elsif person == :third
|
158
|
+
if (verb = conjugations.irregulars[infinitive])
|
159
|
+
conjugate_irregular(verb, tense: :present, person: person, plurality: plurality, mood: mood)
|
160
|
+
elsif (person == :third) && (plurality == :singular) && (mood != :subjunctive)
|
153
161
|
present_third_person_singular_form_for infinitive
|
154
162
|
else
|
155
163
|
infinitive
|
@@ -163,8 +171,8 @@ module Verbs
|
|
163
171
|
# * plurality, an option given by the user
|
164
172
|
# * mood, an option given by the user
|
165
173
|
def past(infinitive, person, plurality, mood)
|
166
|
-
if verb = conjugations.irregulars[infinitive]
|
167
|
-
conjugate_irregular(verb, :
|
174
|
+
if (verb = conjugations.irregulars[infinitive])
|
175
|
+
conjugate_irregular(verb, tense: :past, person: person, plurality: plurality, mood: mood)
|
168
176
|
else
|
169
177
|
regular_preterite_for infinitive
|
170
178
|
end
|
@@ -174,36 +182,40 @@ module Verbs
|
|
174
182
|
# Params:
|
175
183
|
# * infinitive, the given verb
|
176
184
|
def present_participle(infinitive)
|
177
|
-
if infinitive.to_s.match(/#{CONSONANT_PATTERN}#{VOWEL_PATTERN}#{
|
178
|
-
|
179
|
-
|
180
|
-
infinitive.to_s.concat('king').to_sym
|
181
|
-
elsif infinitive.to_s.match(/^be$/) or infinitive.to_s.match(/ye$/) or infinitive.to_s.match(/oe$/) or infinitive.to_s.match(/nge$/) or infinitive.to_s.match(/ee$/)
|
182
|
-
infinitive.to_s.concat('ing').to_sym
|
183
|
-
elsif infinitive.to_s.match(/ie$/)
|
184
|
-
infinitive.to_s[0..-2].concat('ying').to_sym
|
185
|
-
elsif infinitive.to_s.match(/e$/)
|
186
|
-
infinitive.to_s[0..-2].concat('ing').to_sym
|
187
|
-
else
|
188
|
-
infinitive.to_s[0..-1].concat('ing').to_sym
|
185
|
+
if infinitive.to_s.match(/#{CONSONANT_PATTERN}#{VOWEL_PATTERN}#{CONSONANTS_WITHOUT_C_PATTERN}$/) &&
|
186
|
+
!conjugations.single_terminal_consonants.include?(infinitive.to_sym)
|
187
|
+
return present_participle_with_doubled_terminal_consonant_for infinitive
|
189
188
|
end
|
189
|
+
|
190
|
+
case infinitive.to_s
|
191
|
+
when /c$/
|
192
|
+
"#{infinitive}k"
|
193
|
+
when /(^be|ye|oe|nge|ee)$/
|
194
|
+
infinitive.to_s
|
195
|
+
when /ie$/
|
196
|
+
infinitive.to_s.gsub(/ie$/, 'y')
|
197
|
+
when /#{VOWEL_PATTERN}#{CONSONANT_PATTERN}e$/, /ue$/
|
198
|
+
infinitive.to_s[0..-2]
|
199
|
+
else # rubocop:disable Lint/DuplicateBranch
|
200
|
+
infinitive.to_s
|
201
|
+
end.dup.concat('ing').to_sym
|
190
202
|
end
|
191
203
|
|
192
204
|
# Forming verb to apply past tense endings
|
193
205
|
# Params:
|
194
206
|
# * infinitive, the given verb
|
195
207
|
def past_participle(infinitive)
|
196
|
-
if verb = conjugations.irregulars[infinitive]
|
197
|
-
conjugate_irregular(verb, :
|
208
|
+
if (verb = conjugations.irregulars[infinitive])
|
209
|
+
conjugate_irregular(verb, tense: :past, derivative: :participle)
|
198
210
|
else
|
199
211
|
regular_preterite_for infinitive
|
200
212
|
end
|
201
213
|
end
|
202
214
|
|
203
|
-
#
|
215
|
+
#
|
204
216
|
# Params:
|
205
|
-
# * verb,
|
206
|
-
# * options,
|
217
|
+
# * verb,
|
218
|
+
# * options,
|
207
219
|
def conjugate_irregular(verb, options)
|
208
220
|
return verb[options] if verb[options]
|
209
221
|
|
@@ -212,9 +224,9 @@ module Verbs
|
|
212
224
|
plurality = options[:plurality]
|
213
225
|
derivative = options[:derivative]
|
214
226
|
|
215
|
-
if [tense, person, plurality] == [
|
227
|
+
if [tense, person, plurality] == %i[present third singular]
|
216
228
|
present_third_person_singular_form_for verb
|
217
|
-
elsif [tense, derivative] == [
|
229
|
+
elsif [tense, derivative] == %i[past participle]
|
218
230
|
verb.past_participle
|
219
231
|
elsif tense == :present
|
220
232
|
verb.infinitive
|
@@ -229,14 +241,15 @@ module Verbs
|
|
229
241
|
def present_third_person_singular_form_for(verb)
|
230
242
|
infinitive = verb.is_a?(Verb) ? verb.infinitive.to_s : verb.to_s
|
231
243
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
244
|
+
case infinitive
|
245
|
+
when /[a-z&&#{CONSONANT_PATTERN}]y$/i
|
246
|
+
"#{infinitive[0..-2]}ies"
|
247
|
+
when /(ss|sh|t?ch|zz|x|#{CONSONANT_PATTERN}o)$/i
|
248
|
+
"#{infinitive}es"
|
249
|
+
when /[^s]s$/i
|
250
|
+
"#{infinitive}ses"
|
238
251
|
else
|
239
|
-
infinitive
|
252
|
+
"#{infinitive}s"
|
240
253
|
end
|
241
254
|
end
|
242
255
|
|
@@ -246,52 +259,81 @@ module Verbs
|
|
246
259
|
def regular_preterite_for(verb)
|
247
260
|
infinitive = verb.is_a?(Verb) ? verb.infinitive.to_s : verb.to_s
|
248
261
|
|
249
|
-
if verb.to_s.match(/#{CONSONANT_PATTERN}#{VOWEL_PATTERN}#{
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
262
|
+
if verb.to_s.match(/#{CONSONANT_PATTERN}#{VOWEL_PATTERN}#{DOUBLED_CONSONANT_WITHOUT_C_PATTERN}$/) &&
|
263
|
+
!conjugations.single_terminal_consonants.include?(verb.to_sym)
|
264
|
+
return regular_preterite_with_doubled_terminal_consonant_for verb
|
265
|
+
end
|
266
|
+
|
267
|
+
case verb.to_s
|
268
|
+
when /(#{CONSONANT_PATTERN}e|ye|oe|nge|ie|ee|ue)$/
|
269
|
+
infinitive.concat('d').to_sym
|
270
|
+
when /#{CONSONANT_PATTERN}y$/
|
271
|
+
infinitive.gsub(/y$/, 'ied').to_sym
|
272
|
+
when /c$/
|
273
|
+
infinitive.gsub(/c$/, 'cked').to_sym
|
255
274
|
else
|
256
|
-
infinitive.
|
275
|
+
infinitive.concat('ed').to_sym
|
257
276
|
end
|
258
277
|
end
|
259
278
|
|
260
279
|
# Apply proper rules to consonant endings
|
261
280
|
# Params:
|
262
|
-
# * verb, apply
|
281
|
+
# * verb, apply double consonant to this
|
263
282
|
def regular_preterite_with_doubled_terminal_consonant_for(verb)
|
264
|
-
regular_preterite_for verb.to_s.concat(verb.to_s[-1,1]).to_sym
|
283
|
+
regular_preterite_for verb.to_s.concat(verb.to_s[-1, 1]).to_sym
|
265
284
|
end
|
266
285
|
|
267
286
|
# Apply proper rules to consonant endings
|
268
287
|
# Params:
|
269
|
-
# * verb, apply
|
288
|
+
# * verb, apply double consonant to this
|
270
289
|
def present_participle_with_doubled_terminal_consonant_for(verb)
|
271
|
-
|
290
|
+
if /c$/ =~ verb.to_s
|
291
|
+
present_participle verb.to_sym
|
292
|
+
else
|
293
|
+
present_participle verb.to_s.concat(verb.to_s[-1, 1]).to_sym
|
294
|
+
end
|
272
295
|
end
|
273
296
|
|
274
297
|
# Add appropriate aspects to the tense of the conjugation
|
275
298
|
# Params:
|
276
299
|
# * tense, an option given by the user
|
277
300
|
# * aspect, an option given by the user
|
278
|
-
|
301
|
+
# * diathesis, an option given by the user
|
302
|
+
def form_for(tense, aspect, diathesis)
|
279
303
|
form = []
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
304
|
+
case diathesis
|
305
|
+
when :active
|
306
|
+
if tense == :future
|
307
|
+
form << 'will'
|
308
|
+
form << :infinitive if aspect == :habitual
|
309
|
+
form.concat ['have', :past_participle] if aspect == :perfect
|
310
|
+
form.concat ['be having', :past_participle] if aspect == :perfective
|
311
|
+
form.concat ['be', :present_participle] if aspect == :progressive
|
312
|
+
form.concat ['be about to', :infinitive] if aspect == :prospective
|
313
|
+
else
|
314
|
+
form.concat ['used to', :infinitive] if [tense, aspect] == %i[past habitual]
|
315
|
+
form.concat %i[have past_participle] if aspect == :perfect
|
316
|
+
form << :past if [tense, aspect] == %i[past perfective]
|
317
|
+
form.concat %i[be present_participle] if aspect == :progressive
|
318
|
+
form.concat [:be, 'about to', :infinitive] if aspect == :prospective
|
319
|
+
form << :present if [tense, aspect] == %i[present habitual]
|
320
|
+
form.concat [:be, 'having', :past_participle] if [tense, aspect] == %i[present perfective]
|
321
|
+
end
|
322
|
+
when :passive
|
323
|
+
if tense == :future
|
324
|
+
form << 'will'
|
325
|
+
form.concat ['be', :past_participle] if aspect == :habitual
|
326
|
+
form.concat ['have been', :past_participle] if aspect == :perfect
|
327
|
+
form.concat ['be being', :past_participle] if aspect == :progressive
|
328
|
+
form.concat ['be about to be', :past_participle] if aspect == :prospective
|
329
|
+
else
|
330
|
+
form.concat ['used to be', :past_participle] if [tense, aspect] == %i[past habitual]
|
331
|
+
form.concat [:have, 'been', :past_participle] if aspect == :perfect
|
332
|
+
form.concat %i[be past_participle] if [tense, aspect] == %i[past perfective]
|
333
|
+
form.concat [:be, 'being', :past_participle] if aspect == :progressive
|
334
|
+
form.concat [:be, 'about to be', :past_participle] if aspect == :prospective
|
335
|
+
form.concat %i[be past_participle] if [tense, aspect] == %i[present habitual]
|
336
|
+
end
|
295
337
|
end
|
296
338
|
form
|
297
339
|
end
|
@@ -301,10 +343,18 @@ module Verbs
|
|
301
343
|
# * tense, an option given by the user
|
302
344
|
# * person, how the conjugation refers to the subject
|
303
345
|
# * mood, an option given by the user
|
304
|
-
|
305
|
-
|
346
|
+
# * diathesis, an option given by the user
|
347
|
+
def check_for_improper_constructions(infinitive, tense, person, mood, diathesis)
|
348
|
+
if (mood == :imperative) && !((person == :second) && (tense == :present))
|
306
349
|
raise Verbs::ImproperConstruction, 'The imperative mood requires present tense and second person'
|
307
350
|
end
|
351
|
+
if (infinitive.to_sym == :be) && (diathesis == :passive)
|
352
|
+
raise Verbs::ImproperConstruction, 'There is no passive diathesis for the copula'
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def default_aspect(options)
|
357
|
+
options[:tense] == :past ? :perfective : :habitual
|
308
358
|
end
|
309
359
|
end
|
310
360
|
end
|
data/lib/verbs/verb.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Verbs
|
2
4
|
class Verb
|
3
5
|
attr_reader :infinitive, :preterite, :past_participle
|
4
|
-
|
5
|
-
def initialize(infinitive, options = {}
|
6
|
+
|
7
|
+
def initialize(infinitive, options = {})
|
6
8
|
@infinitive = infinitive
|
7
9
|
@forms = {}
|
8
10
|
if block_given?
|
@@ -12,29 +14,36 @@ module Verbs
|
|
12
14
|
@past_participle = options[:past_participle]
|
13
15
|
end
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
def form(word, options = {})
|
17
|
-
|
18
|
-
|
19
|
+
unless options[:tense] && (options[:derivative] || options[:mood] || (options[:person] && options[:plurality]))
|
20
|
+
raise ArgumentError,
|
21
|
+
'Irregular verb specifications must identify tense and must identify either derivative, mood, or person and plurality'
|
22
|
+
end
|
23
|
+
|
19
24
|
tense = options[:tense]
|
20
25
|
|
21
26
|
@forms[:present] ||= {}
|
22
27
|
@forms[:past] ||= {}
|
23
|
-
if derivative = options[:derivative]
|
28
|
+
if (derivative = options[:derivative])
|
24
29
|
@forms[tense][derivative] = word
|
25
|
-
elsif mood = options[:mood]
|
30
|
+
elsif (mood = options[:mood])
|
26
31
|
@forms[tense][mood] = word
|
27
|
-
elsif person = options[:person]
|
32
|
+
elsif (person = options[:person])
|
28
33
|
@forms[tense][person] ||= {}
|
29
34
|
@forms[tense][person][options[:plurality]] = word
|
30
35
|
end
|
31
36
|
end
|
32
|
-
|
37
|
+
|
33
38
|
def [](options = {})
|
34
|
-
tense
|
35
|
-
|
39
|
+
tense = options[:tense]
|
40
|
+
person = options[:person]
|
41
|
+
plurality = options[:plurality]
|
42
|
+
derivative = options[:derivative]
|
43
|
+
mood = options[:mood]
|
44
|
+
if tense && person && plurality && mood
|
36
45
|
@forms[tense].try(:[], mood) || @forms[tense].try(:[], person).try(:[], plurality)
|
37
|
-
elsif tense
|
46
|
+
elsif tense && derivative
|
38
47
|
@forms[tense].try(:[], derivative)
|
39
48
|
end
|
40
49
|
end
|
data/lib/verbs/verblike.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Verbs
|
2
4
|
module Verblike
|
3
5
|
class Wrapper
|
4
6
|
def initialize(base)
|
5
7
|
@base = base
|
6
8
|
end
|
7
|
-
|
9
|
+
|
8
10
|
def conjugate(options)
|
9
|
-
words = @base.to_s.split
|
11
|
+
words = @base.to_s.split
|
10
12
|
words.shift if words.first.downcase == 'to'
|
11
|
-
infinitive = words.shift.to_sym
|
13
|
+
infinitive = words.shift.downcase.to_sym
|
12
14
|
conjugation = ::Verbs::Conjugator.conjugate infinitive, options
|
13
15
|
conjugated = words.unshift(conjugation.to_s).join(' ')
|
14
16
|
@base.is_a?(Symbol) ? conjugated.to_sym : conjugated
|
15
17
|
end
|
16
18
|
end
|
17
|
-
|
19
|
+
|
18
20
|
module Access
|
19
21
|
def verb
|
20
22
|
::Verbs::Verblike::Wrapper.new self
|
data/lib/verbs/version.rb
CHANGED
data/lib/verbs.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'singleton'
|
4
|
+
require 'time'
|
2
5
|
require 'active_support'
|
3
6
|
require 'active_support/core_ext'
|
4
7
|
require 'verbs/verb'
|
@@ -8,10 +11,14 @@ require 'verbs/verblike'
|
|
8
11
|
require 'verbs/improper_construction'
|
9
12
|
|
10
13
|
module Verbs
|
11
|
-
CONSONANTS = %w
|
14
|
+
CONSONANTS = %w[b c d f g h j k l m n p q r s t v w x z].freeze
|
12
15
|
CONSONANT_PATTERN = "[#{CONSONANTS.join}]"
|
13
|
-
|
16
|
+
CONSONANTS_WITHOUT_C = (CONSONANTS - ['c']).freeze
|
17
|
+
CONSONANTS_WITHOUT_C_PATTERN = "[#{CONSONANTS_WITHOUT_C.join}]"
|
18
|
+
DOUBLED_CONSONANTS = (CONSONANTS - %w[v w x]).freeze
|
14
19
|
DOUBLED_CONSONANT_PATTERN = "[#{DOUBLED_CONSONANTS.join}]"
|
15
|
-
|
20
|
+
DOUBLED_CONSONANTS_WITHOUT_C = (DOUBLED_CONSONANTS - ['c']).freeze
|
21
|
+
DOUBLED_CONSONANT_WITHOUT_C_PATTERN = "[#{DOUBLED_CONSONANTS_WITHOUT_C.join}]"
|
22
|
+
VOWELS = %w[a e i o u y].freeze
|
16
23
|
VOWEL_PATTERN = "[#{VOWELS.join}]"
|
17
24
|
end
|