verbvector 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ pkg/*
2
+ *.swp
3
+ *.gem
4
+ .bundle
5
+ rdoc/
6
+ LOG
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in verbvector.gemspec
4
+ gemspec
data/README.textile ADDED
@@ -0,0 +1,96 @@
1
+ h1. Lingustics::Verbs::Verbvector::VerbvectorGenerator
2
+
3
+ This is, what I hope will become a burgeoning array of tools for those interested in languages and linguistics. Any given language's conjugation can be seen as a _vector_, an intersection of several _aspects_ that singularly identify the correct grammatical choice for a given utterance.
4
+
5
+ In Latin, for example, this is defined by *voice*, *mood*, *tense*, *number*, and *person*. Other languages have a more- or less-specific vector. The function of this module, therefore, is to make the exhaustive generation of these vectors simple.
6
+
7
+ h1. Usage
8
+
9
+ Usage is performed by passing a DSL into the module. The module then returns a module based on the _language_ parameter. This resultant module can be mixed-in to your class (say, *LanguageVerb*) to define all the possible method calls (for playing nice with responds_to in case *LanguageVerb* uses metaprogramming in its responses)
10
+
11
+ h1. DSL
12
+
13
+ Initial attempts at producing a verb tense generator wound up producing an incredibly confusing snarl of @eval@ statments and other oddities and wound up neither being specific enough to be easily used nor portable enough to be generally helpful.
14
+
15
+ The DSL is simple and recognizes the following statements:
16
+
17
+ h2. language :LanguageName _block_
18
+
19
+ The first statement. It takes a block that will be further processed and which contains other defining statements for the :Language. The only accepted argument is a symbol for the Language name.
20
+
21
+ h2. all_vectors :position _block_
22
+
23
+ This defines an aspect common to *all* vectors. Aspects are defined in an anonymous hash included in the block. The :position symbol is not presently used but instead stacks from left to right. This may have reason to change.
24
+
25
+ Inside the block one gives the _aspect_ as a symbol and then gives an array containing the valid specifications for that aspect.
26
+
27
+ Example:
28
+
29
+ <pre>
30
+ {
31
+ :voice => %w(active passive),
32
+ :mood => %w(indicative subjunctive imperative)
33
+ }
34
+ </pre>
35
+
36
+ h2. vectors_that Regexp _block_
37
+
38
+ This defines an aspect common to *all* vectors. Aspects are defined in an anonymous hash included in the block. Thus for all existing vectors in the vector stack that match the Regexp, this aspect/specification will be added
39
+
40
+ <pre>
41
+ {
42
+ :tense => %w(present imperfect future
43
+ perfect pastperfect futureperfect)
44
+ }
45
+ </pre>
46
+
47
+ h2. exception (:remove|:add), :branch _block_
48
+
49
+ Languages are not perfectly rational in their combinations. Occasionally you may need to manually add a vector or, more likely, prune a vector.
50
+
51
+ h1. Example
52
+
53
+ _Taken from the test/ directory_
54
+
55
+ <pre>
56
+
57
+ Lingustics::Verbs::Verbvector::VerbvectorGenerator.new do
58
+ language :Latin do
59
+ all_vectors :start_with do
60
+ {
61
+ :voice => %w(active passive),
62
+ :mood => %w(indicative subjunctive imperative)
63
+ }
64
+ end
65
+ vectors_that /.*_indicative_mood/ do
66
+ {
67
+ :tense => %w(present imperfect future
68
+ perfect pastperfect futureperfect)
69
+ }
70
+ end
71
+ vectors_that /.*_subjunctive_mood/ do
72
+ {
73
+ :tense => %w(present imperfect
74
+ perfect pastperfect)
75
+ }
76
+ end
77
+ vectors_that /.*_imperative_mood/ do
78
+ {
79
+ :tense => %w(present)
80
+ }
81
+ end
82
+ all_vectors :end_with do
83
+ {
84
+ :number => %w(singular plural),
85
+ :person => %w(first second third)
86
+ }
87
+ end
88
+ exception :remove, :passive_voice_imperative_mood_present_tense
89
+ end
90
+ end
91
+
92
+ </pre>
93
+
94
+ h1. Author
95
+
96
+ Steven G. Harms
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ #Added to get testing working
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new(:test)
7
+
8
+ require "rake/rdoctask"
9
+ Rake::RDocTask.new do |rd|
10
+ rd.rdoc_files.include("lib/**/*.rb")
11
+ rd.rdoc_dir = "rdoc"
12
+ end
data/lib/verbvector.rb ADDED
@@ -0,0 +1,295 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
2
+ require "verbvector"
3
+ require 'pp'
4
+
5
+ # Generalized module for handling lingustics processing
6
+ module Linguistics
7
+ # Generalized module related to the conjugation of verbs
8
+ module Verbs
9
+ # Each language's specific verb conjugation can be described in terms of a
10
+ # verbal vector, the particular intersection of its voice, tense, number,
11
+ # and person.
12
+ module Verbvector
13
+ # A class designed to generate a module that can be mixed in into a
14
+ # given type of verb (French, Latin, Spanish). I'm not trying to be
15
+ # obscure, but I'm trying to be very generalizable.
16
+ class VerbvectorGenerator
17
+ attr_reader :language, :aspect_list, :vector_list, :cluster_methods,
18
+ :respondable_methods
19
+
20
+ # Class methods go here
21
+ class << self
22
+ end
23
+
24
+ # Initialization
25
+ #
26
+ # Takes the descriptive block of the tense structure in a DSL format
27
+ def initialize(&b)
28
+ @aspect_list = []
29
+ @vector_list = []
30
+ @respondable_methods = []
31
+ @cluster_methods = {}
32
+ @language = ""
33
+
34
+ # Let's remember the difference between instance_ and class_eval.
35
+ #
36
+ # "class_eval sets things up as if you were in the body of a class
37
+ # definition, so method definitions will define instance methods:"
38
+ #
39
+ # "instance_eval on a class acts as if you were working inside the
40
+ # singleton class of self. Therefore, any methods you define will
41
+ # become class methods." - prog ruby 1.9 v3, prag programmers p.388
42
+ #
43
+ # As such, instance_eval here is about to apply this eval to the
44
+ # eigenclass. That means any instance of this class will have this
45
+ # method.
46
+ instance_eval &b
47
+
48
+ @aspect_list.sort!
49
+ end
50
+
51
+ # Vectors are specified at their most atomic
52
+ # Sometimes it is handy to return all the values that match
53
+ # "up to" a given aspect and then uniq'ify them
54
+
55
+ def match_vector_upto_aspect(s)
56
+ @vector_list.compact.sort.grep(/#{s}/).map{ |x|
57
+ x.sub(/(^.*#{s}).*/,%q(\1))
58
+ }.uniq
59
+ end
60
+
61
+ # Creates the anonymous module based on the contents of @vector_list.
62
+ # The method names in this module are just stubs _except_ those that
63
+ # are loaded into the @cluster_methods hash. By generating all the
64
+ # method names we allow +responds_to?+ to work as expected.
65
+
66
+ def method_extension_module
67
+ v = @vector_list
68
+ c = @cluster_methods
69
+ l = @language
70
+ r = @respondable_methods
71
+
72
+ Module.new do
73
+ # This defines instance methods on the Module
74
+ # m.instance_methods #=> [:say_foo, :say_bar, :say_bat]
75
+
76
+ # Note, you can't use @someArray in the iteration because
77
+ # self has changed to this anonymous module. Since a block
78
+ # is a binding, it has the local context (including 'v')
79
+ # bundled up with it -- despte self having changed!
80
+ # Therefore, the following works.
81
+
82
+ # Define a method for each name in vector_list.
83
+ raise("Language was not defined." ) if l.nil?
84
+
85
+ v.each do |m|
86
+ r << "#{m}"
87
+ define_method "#{l.downcase}_#{m}".to_sym do
88
+ end
89
+ end
90
+
91
+ # Write something to spit out the vectors as well.
92
+ define_method :vector_list do
93
+ return v
94
+ end
95
+
96
+ define_method :respondable_methods do
97
+ return r
98
+ end
99
+
100
+ # Spit out the clustered methods
101
+ c.each_pair do |k,v|
102
+ define_method k do
103
+ v.call
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+
110
+ # Language takes a symbol for +l+ the language whose verb we seek to
111
+ # model. It then takes a block for the sub-specification of the verbs
112
+ # of that language.
113
+ def language(*l,&b)
114
+ return @language if (l[0].nil? and not @language.nil?)
115
+ @language = l[0]
116
+ instance_eval &b
117
+ end
118
+
119
+ # Method generates tense vectors based on aspects that are assumed to
120
+ # apply to all possible vectors. These would be seen as the most
121
+ # general aspects possible For example, while only *some* vectors are
122
+ # present tense, *all* vectors have a voice.
123
+
124
+ def all_vectors(position,&b)
125
+ # Make sure there is a block given
126
+ return unless (block_given? or yield.first)
127
+
128
+ # Sentinel condition for stopping recursive call
129
+ return @vector_list unless yield.first
130
+
131
+ # Provided that there was a block, collect the DSL hash into
132
+ # specifications
133
+ specifications = yield
134
+
135
+ # Extract the first k/v
136
+ specification = specifications.first
137
+
138
+ # Based on the key for each row, take that content and postpend
139
+ # it.to_s to the ending of each value held in the hash element value
140
+ expanded_specification = combinatorialize(specification)
141
+
142
+ # Remove the expanded value from the specifications hash
143
+ specifications.delete(specification[0])
144
+
145
+ # Keep a record of aspects we have seen
146
+ @aspect_list.push specification[0]
147
+ @aspect_list.uniq!
148
+
149
+ # If it's the first go round put the first set of values in. In
150
+ # general these should be the leftmost and theremfore most general
151
+ if @vector_list.empty?
152
+ @vector_list = expanded_specification
153
+ else
154
+ # If there's already a definition in the tens list, for each of
155
+ # the _existing_ values add the array of strings seen in
156
+ # expanded_specifications thereunto. Hold them in 'temp' and then
157
+ # set @vector_list to temp.
158
+ temp = []
159
+ @vector_list.each do |base|
160
+ expanded_specification.each do |u|
161
+ temp.push base+"_#{u}"
162
+ end
163
+ end
164
+ @vector_list = temp
165
+ end
166
+
167
+ # Recursive call, sentnel contition is at the top of the method
168
+ all_vectors(position) do
169
+ specifications
170
+ end
171
+
172
+ instance_eval &b
173
+ end
174
+
175
+ # Method appends vector definitions _if_ the +condition+ (a RegEx) is satisfied
176
+ def vectors_that(condition,&b)
177
+ matching_stems = @vector_list.grep condition
178
+ temp = []
179
+
180
+ specifications = yield
181
+
182
+ # Extract the first k/v
183
+ specification = specifications.first
184
+
185
+ # Based on the key for each row, take that content and postpend
186
+ # it.to_s to the ending of each value held in the hash element value
187
+ expanded_specification = combinatorialize(specification)
188
+
189
+ # Remove the expanded value from the specifications hash
190
+ specifications.delete(specification[0])
191
+
192
+ # Keep a record of aspects we have seen
193
+ @aspect_list.push specification[0]
194
+ @aspect_list.uniq!
195
+
196
+ # So we grepped the desired stems and stored them in matching_stems
197
+ # First we delete those stems (becasue we're going to further specify) them
198
+ matching_stems.each do |x|
199
+ @vector_list.delete x
200
+ expanded_specification.each do |u|
201
+ temp.push x+"_#{u}"
202
+ end
203
+ end
204
+
205
+ # Combine the original list with the freshly expanded list
206
+ @vector_list = (@vector_list + temp).sort
207
+ end
208
+
209
+ # Languages are not entirely rational, while something _ought_ exist
210
+ # by the rules of rational combination, some times they simply _don't_
211
+ # exist. That's what this method is for.
212
+ #
213
+ # +action+ :: +:remove+ or +:add+
214
+ # +id+ :: method name to remove
215
+ # _block_ :: used to add
216
+ def exception(action, id, &b)
217
+ if action == :remove
218
+ @vector_list.delete_if {|x| x =~ /#{id.to_s}/ }
219
+ elsif action == :add
220
+ end
221
+ end
222
+
223
+ # Method to take a hash key where the key is an _aspect_ and the value
224
+ # is an array of specifications valid for that _aspect_.
225
+ def combinatorialize(h)
226
+ results = []
227
+ h[1].each do |k|
228
+ results.push "#{k}_#{h[0]}"
229
+ end
230
+ results
231
+ end
232
+
233
+ # Method to allow "clusters" of simiar vectors to be identified (see:
234
+ # +match_upto+) based on the 0th string match. These clusters can be
235
+ # called by the method namd provided as the 2nd argument (0-index)
236
+ #
237
+ # This allows
238
+ # active_voice_indicative_mood_imperfect_tense_singular_number_third_p
239
+ # erson and other such to be 'clustered' as
240
+ # active_voice_indicative_mood_imperfect_tense. This means the actual
241
+ # method will probably be done in the "cluster" and some sort of
242
+ # secondary logic (method_missing) will do the final resolution
243
+ #
244
+ # Nevertheless, per the logic of this library, by defining all the
245
+ # atomic, we play nice and give respond_to? all the information it
246
+ # needs
247
+ #
248
+ # *Example:* <tt>cluster_on /active_voice.*third/, "as method", :active_thirds</tt>
249
+ #
250
+ #
251
+ # This means you want to collect several method names that match the Regexp and make them identifiable by a call to the
252
+ # method +active_thirds+
253
+ #
254
+ # Alternatively, you might want to use a String or Symbol (making use of match_upto).
255
+ #
256
+ # *Example:* <tt>cluster_on :tense, "as method", :tense_list</tt>
257
+ #
258
+ # +match+ :: The String or Regex match_upto will use for matching
259
+ # +junk+ :: Syntactic sugar, a string that makes the DSL look sensible
260
+ # +method_name+ :: The method in the anonymous module that returns the matched method names. See +create_module+
261
+ def cluster_on(match, junk, method_name)
262
+
263
+ clustered_matches =
264
+ if match.class == Regexp
265
+ @vector_list.grep match
266
+ elsif match.class.to_s =~ /^(String|Symbol)/
267
+ # Get the items that match_upto the specified clustering token
268
+ match_vector_upto_aspect(match.to_s)
269
+ else
270
+ # This shouldn't happen, we should get a Regexp or a String/Symbol
271
+ raise "Didn't fire for clustered match: #{match}"
272
+ end
273
+
274
+ unless clustered_matches.nil?
275
+ # No, this should not be done:
276
+ # ...and add them to the @vector_list.
277
+ # @vector_list += clustered_matches
278
+ # Clustered methods need to be defined, for real, somewhere. We
279
+ # should not claim to respond to them here, but rather let the
280
+ # framework using verbvector have the responsibility for
281
+ # implementation.
282
+
283
+
284
+ # Now, define a Proc that can correspond to arg[2]
285
+ @cluster_methods[method_name] = Proc.new do
286
+ clustered_matches
287
+ end
288
+ end
289
+
290
+ end
291
+
292
+ end
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,8 @@
1
+ module Linguistics
2
+ module Verbs
3
+ module Verbvector
4
+ # Version of the gem
5
+ VERSION = "0.0.1"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ active_voice_imperative_mood_present_tense
2
+ active_voice_indicative_mood_present_tense
3
+ active_voice_indicative_mood_imperfect_tense
4
+ active_voice_indicative_mood_future_tense
5
+ active_voice_indicative_mood_perfect_tense
6
+ active_voice_indicative_mood_pastperfect_tense
7
+ active_voice_indicative_mood_futureperfect_tense
8
+ passive_voice_indicative_mood_present_tense
9
+ passive_voice_indicative_mood_imperfect_tense
10
+ passive_voice_indicative_mood_future_tense
11
+ passive_voice_indicative_mood_perfect_tense
12
+ passive_voice_indicative_mood_pastperfect_tense
13
+ passive_voice_indicative_mood_futureperfect_tense
14
+ active_voice_subjunctive_mood_present_tense
15
+ active_voice_subjunctive_mood_imperfect_tense
16
+ active_voice_subjunctive_mood_perfect_tense
17
+ active_voice_subjunctive_mood_pastperfect_tense
18
+ passive_voice_subjunctive_mood_present_tense
19
+ passive_voice_subjunctive_mood_imperfect_tense
20
+ passive_voice_subjunctive_mood_perfect_tense
21
+ passive_voice_subjunctive_mood_pastperfect_tense
@@ -0,0 +1,135 @@
1
+ require "test/unit"
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
+ require "verbvector"
5
+
6
+ class TestVerbVector < Test::Unit::TestCase
7
+ def setup
8
+ @vv =
9
+ Linguistics::Verbs::Verbvector::VerbvectorGenerator.new do
10
+ language :Latin do
11
+ all_vectors :start_with do
12
+ {
13
+ :voice => %w(active passive),
14
+ :mood => %w(indicative subjunctive imperative)
15
+ }
16
+ end
17
+ vectors_that /.*_indicative_mood/ do
18
+ {
19
+ :tense => %w(present imperfect future
20
+ perfect pastperfect futureperfect)
21
+ }
22
+ end
23
+ vectors_that /.*_subjunctive_mood/ do
24
+ {
25
+ :tense => %w(present imperfect
26
+ perfect pastperfect)
27
+ }
28
+ end
29
+ vectors_that /.*_imperative_mood/ do
30
+ {
31
+ :tense => %w(present)
32
+ }
33
+ end
34
+ all_vectors :end_with do
35
+ {
36
+ :number => %w(singular plural),
37
+ :person => %w(first second third)
38
+ }
39
+ end
40
+ exception :remove, :passive_voice_imperative_mood_present_tense
41
+ cluster_on :tense, "as method", :tense_list
42
+ end
43
+ end
44
+ end
45
+
46
+ def test_basics
47
+ v = Linguistics::Verbs::Verbvector::VerbvectorGenerator.new do
48
+ end
49
+
50
+ assert_not_nil(v)
51
+ assert_equal(:Latin, @vv.language)
52
+ end
53
+
54
+ def test_vector_matcher
55
+ assert_equal 2, @vv.match_vector_upto_aspect("voice").length
56
+ assert_equal 5, @vv.match_vector_upto_aspect("mood").length
57
+ assert_equal 21, @vv.match_vector_upto_aspect("tense").length
58
+ end
59
+
60
+ def test_tense_resolution
61
+ tense_list = Array.new(File.open(File.join(File.dirname(__FILE__), *%w[fixtures tense_list])).read.split /\s/)
62
+ tense_list.sort!
63
+
64
+ tc = Class.new
65
+ tc.extend @vv.method_extension_module
66
+
67
+ assert_equal tense_list, tc.tense_list
68
+ end
69
+
70
+ def test_clustering_with_regex
71
+ t =
72
+ Linguistics::Verbs::Verbvector::VerbvectorGenerator.new do
73
+ language :Latin do
74
+ all_vectors :start_with do
75
+ {
76
+ :voice => %w(active passive),
77
+ :mood => %w(indicative subjunctive imperative)
78
+ }
79
+ end
80
+ vectors_that /.*_indicative_mood/ do
81
+ {
82
+ :tense => %w(present imperfect future
83
+ perfect pastperfect futureperfect)
84
+ }
85
+ end
86
+ vectors_that /.*_subjunctive_mood/ do
87
+ {
88
+ :tense => %w(present imperfect
89
+ perfect pastperfect)
90
+ }
91
+ end
92
+ vectors_that /.*_imperative_mood/ do
93
+ {
94
+ :tense => %w(present)
95
+ }
96
+ end
97
+ all_vectors :end_with do
98
+ {
99
+ :number => %w(singular plural),
100
+ :person => %w(first second third)
101
+ }
102
+ end
103
+ exception :remove, :passive_voice_imperative_mood_present_tense
104
+ cluster_on /active_voice.*third/, "as method", :active_thirds
105
+ end
106
+ end
107
+ tc = Class.new
108
+ tc.extend t.method_extension_module
109
+ assert_respond_to(tc, :active_thirds)
110
+ assert_equal(22, tc.active_thirds.length)
111
+ end
112
+
113
+ def test_extension
114
+ tc = Class.new
115
+ tc.extend @vv.method_extension_module
116
+ assert_respond_to(tc, :latin_active_voice_indicative_mood_imperfect_tense_singular_number_third_person)
117
+ end
118
+
119
+ def test_clustering
120
+ assert_respond_to(@vv, :vectors_that)
121
+ assert_respond_to(@vv, :cluster_on)
122
+
123
+ tc = Class.new
124
+ tc.extend @vv.method_extension_module
125
+
126
+ # Make sure that each cluster method is /not/ defined. We want these to
127
+ # be defined "for real," not as a proxy.
128
+
129
+ cms=@vv.cluster_methods[:tense_list].call
130
+ cms.each do |m|
131
+ assert_true not(tc.respond_to? m.to_sym)
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "verbvector/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "verbvector"
7
+ s.version = Linguistics::Verbs::Verbvector::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Steven G. Harms"]
10
+ s.email = ["github@sgharms.oib.com"]
11
+ s.homepage = "http://rubygems.org/gems/verbvector"
12
+ s.summary = %q{Generates the verb tense "vectors" based on a DSL description syntax.}
13
+ s.description = %q{Use a DSL to describe the verb tense framework of a language and have it generate methods corresponding to each unique vector.}
14
+
15
+ s.rubyforge_project = "verbvector"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: verbvector
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Steven G. Harms
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-02 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: Use a DSL to describe the verb tense framework of a language and have it generate methods corresponding to each unique vector.
17
+ email:
18
+ - github@sgharms.oib.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - .gitignore
27
+ - Gemfile
28
+ - README.textile
29
+ - Rakefile
30
+ - lib/verbvector.rb
31
+ - lib/verbvector/version.rb
32
+ - test/fixtures/tense_list
33
+ - test/test_generator.rb
34
+ - verbvector.gemspec
35
+ homepage: http://rubygems.org/gems/verbvector
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project: verbvector
58
+ rubygems_version: 1.8.5
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Generates the verb tense "vectors" based on a DSL description syntax.
62
+ test_files:
63
+ - test/fixtures/tense_list
64
+ - test/test_generator.rb