inflection 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## Rubinius
17
+ *.rbc
18
+
19
+ ## PROJECT::GENERAL
20
+ *.gem
21
+ coverage
22
+ rdoc
23
+ pkg
24
+ tmp
25
+ doc
26
+ log
27
+ .yardoc
28
+ measurements
29
+
30
+ ## BUNDLER
31
+ .bundle
32
+ Gemfile.local
33
+ Gemfile.lock
34
+
35
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Dan Kubb
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = inflection
2
+
3
+ Support library that provies english inflection.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Simon Hafner. See LICENSE for details.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{inflection}
5
+ s.version = "0.1"
6
+
7
+ s.authors = ["Dan Kubb", "Simon Hafner"]
8
+ s.description = %q{Support library for inflections}
9
+ s.extra_rdoc_files = [
10
+ "LICENSE",
11
+ "README.rdoc"
12
+ ]
13
+ s.files = `git ls-files`.split("\n")
14
+ s.homepage = %q{http://github.com/Tass/extlib}
15
+ s.rdoc_options = ["--charset=UTF-8"]
16
+ s.require_paths = ["lib"]
17
+ s.rubygems_version = %q{1.3.7}
18
+ s.summary = %q{Provies english inflection.}
19
+ end
20
+
data/lib/inflection.rb ADDED
@@ -0,0 +1,358 @@
1
+ # encoding: utf-8
2
+
3
+ # = English Nouns Number Inflection.
4
+ #
5
+ # This module provides english singular <-> plural noun inflections.
6
+ module Inflection
7
+
8
+ @singular_of = {}
9
+ @plural_of = {}
10
+
11
+ @singular_rules = []
12
+ @plural_rules = []
13
+
14
+ class << self
15
+ # Defines a general inflection exception case.
16
+ #
17
+ # ==== Parameters
18
+ # singular<String>::
19
+ # singular form of the word
20
+ # plural<String>::
21
+ # plural form of the word
22
+ #
23
+ # ==== Examples
24
+ #
25
+ # Here we define erratum/errata exception case:
26
+ #
27
+ # English::Inflect.word "erratum", "errata"
28
+ #
29
+ # In case singular and plural forms are the same omit
30
+ # second argument on call:
31
+ #
32
+ # English::Inflect.word 'information'
33
+ def word(singular, plural=nil)
34
+ plural = singular unless plural
35
+ singular_word(singular, plural)
36
+ plural_word(singular, plural)
37
+ end
38
+
39
+ def clear(type = :all)
40
+ if type == :singular || type == :all
41
+ @singular_of = {}
42
+ @singular_rules = []
43
+ @singularization_rules, @singularization_regex = nil, nil
44
+ end
45
+ if type == :plural || type == :all
46
+ @singular_of = {}
47
+ @singular_rules = []
48
+ @singularization_rules, @singularization_regex = nil, nil
49
+ end
50
+ end
51
+
52
+
53
+ # Define a singularization exception.
54
+ #
55
+ # ==== Parameters
56
+ # singular<String>::
57
+ # singular form of the word
58
+ # plural<String>::
59
+ # plural form of the word
60
+ def singular_word(singular, plural)
61
+ @singular_of[plural] = singular
62
+ @singular_of[plural.capitalize] = singular.capitalize
63
+ end
64
+
65
+ # Define a pluralization exception.
66
+ #
67
+ # ==== Parameters
68
+ # singular<String>::
69
+ # singular form of the word
70
+ # plural<String>::
71
+ # plural form of the word
72
+ def plural_word(singular, plural)
73
+ @plural_of[singular] = plural
74
+ @plural_of[singular.capitalize] = plural.capitalize
75
+ end
76
+
77
+ # Define a general rule.
78
+ #
79
+ # ==== Parameters
80
+ # singular<String>::
81
+ # ending of the word in singular form
82
+ # plural<String>::
83
+ # ending of the word in plural form
84
+ # whole_word<Boolean>::
85
+ # for capitalization, since words can be
86
+ # capitalized (Man => Men) #
87
+ # ==== Examples
88
+ # Once the following rule is defined:
89
+ # English::Inflect.rule 'y', 'ies'
90
+ #
91
+ # You can see the following results:
92
+ # irb> "fly".plural
93
+ # => flies
94
+ # irb> "cry".plural
95
+ # => cries
96
+ # Define a general rule.
97
+
98
+ def rule(singular, plural, whole_word = false)
99
+ singular_rule(singular, plural)
100
+ plural_rule(singular, plural)
101
+ word(singular, plural) if whole_word
102
+ end
103
+
104
+ # Define a singularization rule.
105
+ #
106
+ # ==== Parameters
107
+ # singular<String>::
108
+ # ending of the word in singular form
109
+ # plural<String>::
110
+ # ending of the word in plural form
111
+ #
112
+ # ==== Examples
113
+ # Once the following rule is defined:
114
+ # English::Inflect.singular_rule 'o', 'oes'
115
+ #
116
+ # You can see the following results:
117
+ # irb> "heroes".singular
118
+ # => hero
119
+ def singular_rule(singular, plural)
120
+ @singular_rules << [singular, plural]
121
+ end
122
+
123
+ # Define a plurualization rule.
124
+ #
125
+ # ==== Parameters
126
+ # singular<String>::
127
+ # ending of the word in singular form
128
+ # plural<String>::
129
+ # ending of the word in plural form
130
+ #
131
+ # ==== Examples
132
+ # Once the following rule is defined:
133
+ # English::Inflect.singular_rule 'fe', 'ves'
134
+ #
135
+ # You can see the following results:
136
+ # irb> "wife".plural
137
+ # => wives
138
+ def plural_rule(singular, plural)
139
+ @plural_rules << [singular, plural]
140
+ end
141
+
142
+ # Read prepared singularization rules.
143
+ def singularization_rules
144
+ if defined?(@singularization_regex) && @singularization_regex
145
+ return [@singularization_regex, @singularization_hash]
146
+ end
147
+ # No sorting needed: Regexen match on longest string
148
+ @singularization_regex = Regexp.new("(" + @singular_rules.map {|s,p| p}.join("|") + ")$", "i")
149
+ @singularization_hash = Hash[*@singular_rules.flatten].invert
150
+ [@singularization_regex, @singularization_hash]
151
+ end
152
+
153
+ # Read prepared pluralization rules.
154
+ def pluralization_rules
155
+ if defined?(@pluralization_regex) && @pluralization_regex
156
+ return [@pluralization_regex, @pluralization_hash]
157
+ end
158
+ @pluralization_regex = Regexp.new("(" + @plural_rules.map {|s,p| s}.join("|") + ")$", "i")
159
+ @pluralization_hash = Hash[*@plural_rules.flatten]
160
+ [@pluralization_regex, @pluralization_hash]
161
+ end
162
+
163
+ attr_reader :singular_of, :plural_of
164
+
165
+ # Convert an English word from plural to singular.
166
+ #
167
+ # "boys".singular #=> boy
168
+ # "tomatoes".singular #=> tomato
169
+ #
170
+ # ==== Parameters
171
+ # word<String>:: word to singularize
172
+ #
173
+ # ==== Returns
174
+ # <String>:: singularized form of word
175
+ #
176
+ # ==== Notes
177
+ # Aliased as singularize (a Railism)
178
+ def singular(word)
179
+ if result = singular_of[word]
180
+ return result.dup
181
+ end
182
+ result = word.dup
183
+ regex, hash = singularization_rules
184
+ result.sub!(regex) {|m| hash[m]}
185
+ singular_of[word] = result
186
+ return result
187
+ end
188
+
189
+ # Alias for #singular (a Railism).
190
+ #
191
+ alias_method(:singularize, :singular)
192
+
193
+ # Convert an English word from singular to plural.
194
+ #
195
+ # "boy".plural #=> boys
196
+ # "tomato".plural #=> tomatoes
197
+ #
198
+ # ==== Parameters
199
+ # word<String>:: word to pluralize
200
+ #
201
+ # ==== Returns
202
+ # <String>:: pluralized form of word
203
+ #
204
+ # ==== Notes
205
+ # Aliased as pluralize (a Railism)
206
+ def plural(word)
207
+ # special exceptions
208
+ return "" if word == ""
209
+ if result = plural_of[word]
210
+ return result.dup
211
+ end
212
+ result = word.dup
213
+ regex, hash = pluralization_rules
214
+ result.sub!(regex) {|m| hash[m]}
215
+ plural_of[word] = result
216
+ return result
217
+ end
218
+
219
+ # Alias for #plural (a Railism).
220
+ alias_method(:pluralize, :plural)
221
+ end
222
+
223
+ # One argument means singular and plural are the same.
224
+
225
+ word 'equipment'
226
+ word 'fish'
227
+ word 'grass'
228
+ word 'hovercraft'
229
+ word 'information'
230
+ word 'milk'
231
+ word 'money'
232
+ word 'moose'
233
+ word 'plurals'
234
+ word 'postgres'
235
+ word 'rain'
236
+ word 'rice'
237
+ word 'series'
238
+ word 'sheep'
239
+ word 'species'
240
+ word 'status'
241
+ word 'pokemon'
242
+ word 'pokémon'
243
+ word 'mysql'
244
+
245
+ # Two arguments defines a singular and plural exception.
246
+ word 'alias' , 'aliases'
247
+ word 'analysis' , 'analyses'
248
+ word 'axis' , 'axes'
249
+ word 'basis' , 'bases'
250
+ word 'buffalo' , 'buffaloes'
251
+ word 'cactus' , 'cacti'
252
+ word 'crisis' , 'crises'
253
+ word 'criterion' , 'criteria'
254
+ word 'cross' , 'crosses'
255
+ word 'datum' , 'data'
256
+ word 'diagnosis' , 'diagnoses'
257
+ word 'drive' , 'drives'
258
+ word 'erratum' , 'errata'
259
+ word 'goose' , 'geese'
260
+ word 'index' , 'indices'
261
+ word 'life' , 'lives'
262
+ word 'louse' , 'lice'
263
+ word 'matrix' , 'matrices'
264
+ word 'medium' , 'media'
265
+ word 'mouse' , 'mice'
266
+ word 'movie' , 'movies'
267
+ word 'octopus' , 'octopi'
268
+ word 'ox' , 'oxen'
269
+ word 'phenomenon' , 'phenomena'
270
+ word 'plus' , 'plusses'
271
+ word 'potato' , 'potatoes'
272
+ word 'quiz' , 'quizzes'
273
+ word 'status' , 'status'
274
+ word 'status' , 'statuses'
275
+ word 'Swiss' , 'Swiss'
276
+ word 'testis' , 'testes'
277
+ word 'thesaurus' , 'thesauri'
278
+ word 'thesis' , 'theses'
279
+ word 'thief' , 'thieves'
280
+ word 'tomato' , 'tomatoes'
281
+ word 'torpedo' , 'torpedoes'
282
+ word 'vertex' , 'vertices'
283
+ word 'wife' , 'wives'
284
+ word 'tooth' , 'teeth'
285
+ word 'penis' , 'penises'
286
+ word 'stimulus' , 'stimuli'
287
+ word 'shaman' , 'shamans'
288
+ word 'rookie' , 'rookies'
289
+ word 'radius' , 'radii'
290
+ word 'talisman' , 'talismans'
291
+ word 'syllabus' , 'syllabi'
292
+ word 'move' , 'moves'
293
+ word 'human' , 'humans'
294
+ word 'hippopotamus', 'hippopotami'
295
+ word 'german' , 'germans'
296
+ word 'fungus' , 'fungi'
297
+ word 'focus' , 'foci'
298
+ word 'die' , 'dice'
299
+ word 'alumnus' , 'alumni'
300
+ word 'appendix' , 'appendices'
301
+ word 'arena' , 'arenas'
302
+
303
+ # One-way singularization exception (convert plural to singular).
304
+
305
+ # General rules.
306
+ rule 'person' , 'people', true
307
+ rule 'shoe' , 'shoes', true
308
+ rule 'hive' , 'hives', true
309
+ rule 'man' , 'men', true
310
+ rule 'child' , 'children', true
311
+ rule 'news' , 'news', true
312
+ rule 'rf' , 'rves'
313
+ rule 'af' , 'aves'
314
+ rule 'ero' , 'eroes'
315
+ rule 'man' , 'men'
316
+ rule 'ch' , 'ches'
317
+ rule 'sh' , 'shes'
318
+ rule 'ss' , 'sses'
319
+ #rule 'ta' , 'tum'
320
+ #rule 'ia' , 'ium'
321
+ #rule 'ra' , 'rum'
322
+ rule 'ay' , 'ays'
323
+ rule 'ey' , 'eys'
324
+ rule 'oy' , 'oys'
325
+ rule 'uy' , 'uys'
326
+ rule 'y' , 'ies'
327
+ rule 'x' , 'xes'
328
+ rule 'lf' , 'lves'
329
+ rule 'ffe' , 'ffes'
330
+ rule 'afe' , 'aves'
331
+ rule 'ouse' , 'ouses'
332
+ rule 'ive' , 'ives' # don't want to snag wife
333
+ # more cases of words ending in -oses not being singularized properly
334
+ # than cases of words ending in -osis
335
+ # rule 'osis' , 'oses'
336
+ rule 'ox' , 'oxes'
337
+ rule 'us' , 'uses'
338
+ rule '' , 's'
339
+
340
+ # Some latin words
341
+ rule 'a' , 'ae'
342
+ rule 'um' , 'a'
343
+
344
+ # cookie / bookie
345
+ rule 'ookie' , 'ookies'
346
+ # One-way singular rules.
347
+
348
+ singular_rule 'of' , 'ofs' # proof
349
+ singular_rule 'o' , 'oes' # hero, heroes
350
+ singular_rule 'f' , 'ves'
351
+
352
+ # One-way plural rules.
353
+
354
+ #plural_rule 'fe' , 'ves' # safe, wife
355
+ plural_rule 's' , 'ses'
356
+ plural_rule 'fe' , 'ves' # don't want to snag perspectives
357
+
358
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+ require 'extlib/inflection'
3
+
4
+ describe Extlib::Inflection do
5
+ describe "#classify" do
6
+ it 'classifies data_mapper as DataMapper' do
7
+ Extlib::Inflection.classify('data_mapper').should == 'DataMapper'
8
+ end
9
+
10
+ it "classifies enlarged_testes as EnlargedTestis" do
11
+ Extlib::Inflection.classify('enlarged_testes').should == 'EnlargedTestis'
12
+ end
13
+
14
+ it "singularizes string first: classifies data_mappers as egg_and_hams as EggAndHam" do
15
+ Extlib::Inflection.classify('egg_and_hams').should == 'EggAndHam'
16
+ end
17
+ end
18
+
19
+ describe "#camelize" do
20
+ it 'camelizes data_mapper as DataMapper' do
21
+ Extlib::Inflection.camelize('data_mapper').should == 'DataMapper'
22
+ end
23
+
24
+ it "camelizes merb as Merb" do
25
+ Extlib::Inflection.camelize('merb').should == 'Merb'
26
+ end
27
+
28
+ it "camelizes data_mapper/resource as DataMapper::Resource" do
29
+ Extlib::Inflection.camelize('data_mapper/resource').should == 'DataMapper::Resource'
30
+ end
31
+
32
+ it "camelizes data_mapper/associations/one_to_many as DataMapper::Associations::OneToMany" do
33
+ Extlib::Inflection.camelize('data_mapper/associations/one_to_many').should == 'DataMapper::Associations::OneToMany'
34
+ end
35
+ end
36
+
37
+ describe "#underscore" do
38
+ it 'underscores DataMapper as data_mapper' do
39
+ Extlib::Inflection.underscore('DataMapper').should == 'data_mapper'
40
+ end
41
+
42
+ it 'underscores Merb as merb' do
43
+ Extlib::Inflection.underscore('Merb').should == 'merb'
44
+ end
45
+
46
+ it 'underscores DataMapper::Resource as data_mapper/resource' do
47
+ Extlib::Inflection.underscore('DataMapper::Resource').should == 'data_mapper/resource'
48
+ end
49
+
50
+ it 'underscores Merb::BootLoader::Rackup as merb/boot_loader/rackup' do
51
+ Extlib::Inflection.underscore('Merb::BootLoader::Rackup').should == 'merb/boot_loader/rackup'
52
+ end
53
+ end
54
+
55
+ describe "#humanize" do
56
+ it 'replaces _ with space: humanizes employee_salary as Employee salary' do
57
+ Extlib::Inflection.humanize('employee_salary').should == 'Employee salary'
58
+ end
59
+
60
+ it "strips _id endings: humanizes author_id as Author" do
61
+ Extlib::Inflection.humanize('author_id').should == 'Author'
62
+ end
63
+ end
64
+
65
+ describe "#demodulize" do
66
+ it 'demodulizes module name: DataMapper::Inflector => Inflector' do
67
+ Extlib::Inflection.demodulize('DataMapper::Inflector').should == 'Inflector'
68
+ end
69
+
70
+ it 'demodulizes module name: A::B::C::D::E => E' do
71
+ Extlib::Inflection.demodulize('A::B::C::D::E').should == 'E'
72
+ end
73
+ end
74
+
75
+ describe "#tableize" do
76
+ it 'pluralizes last word in snake_case strings: fancy_category => fancy_categories' do
77
+ Extlib::Inflection.tableize('fancy_category').should == 'fancy_categories'
78
+ end
79
+
80
+ it 'underscores CamelCase strings before pluralization: enlarged_testis => enlarged_testes' do
81
+ Extlib::Inflection.tableize('enlarged_testis').should == 'enlarged_testes'
82
+ end
83
+
84
+ it 'underscores CamelCase strings before pluralization: FancyCategory => fancy_categories' do
85
+ Extlib::Inflection.tableize('FancyCategory').should == 'fancy_categories'
86
+ end
87
+
88
+ it 'underscores CamelCase strings before pluralization: EnlargedTestis => enlarged_testes' do
89
+ Extlib::Inflection.tableize('EnlargedTestis').should == 'enlarged_testes'
90
+ end
91
+
92
+ it 'replaces :: with underscores: Fancy::Category => fancy_categories' do
93
+ Extlib::Inflection.tableize('Fancy::Category').should == 'fancy_categories'
94
+ end
95
+
96
+ it 'underscores CamelCase strings before pluralization: Enlarged::Testis => enlarged_testes' do
97
+ Extlib::Inflection.tableize('Enlarged::Testis').should == 'enlarged_testes'
98
+ end
99
+
100
+ end
101
+
102
+ describe "#foreign_key" do
103
+ it 'adds _id to downcased string: Message => message_id' do
104
+ Extlib::Inflection.foreign_key('Message').should == 'message_id'
105
+ end
106
+
107
+ it "demodulizes string first: Admin::Post => post_id" do
108
+ Extlib::Inflection.foreign_key('Admin::Post').should == 'post_id'
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,222 @@
1
+ require 'spec_helper'
2
+ require 'extlib/string'
3
+
4
+ describe String, "#to_const_string" do
5
+ it "swaps slashes with ::" do
6
+ "foo/bar".to_const_string.should == "Foo::Bar"
7
+ end
8
+
9
+ it "replaces snake_case with CamelCase" do
10
+ "foo/bar/baz_bat".to_const_string.should == "Foo::Bar::BazBat"
11
+ end
12
+
13
+ it "leaves constant string as is" do
14
+ "Merb::Test".to_const_string.should == "Merb::Test"
15
+ end
16
+ end
17
+
18
+
19
+
20
+ describe String, "#to_const_path" do
21
+ it "swaps :: with slash" do
22
+ "Foo::Bar".to_const_path.should == "foo/bar"
23
+ end
24
+
25
+ it "snake_cases string" do
26
+ "Merb::Test::ViewHelper".to_const_path.should == "merb/test/view_helper"
27
+ end
28
+
29
+ it "leaves slash-separated snake case string as is" do
30
+ "merb/test/view_helper".to_const_path.should == "merb/test/view_helper"
31
+ end
32
+ end
33
+
34
+
35
+
36
+ describe String, "#camel_case" do
37
+ it "handles lowercase without underscore" do
38
+ "merb".camel_case.should == "Merb"
39
+ end
40
+
41
+ it "handles lowercase with 1 underscore" do
42
+ "merb_core".camel_case.should == "MerbCore"
43
+ end
44
+
45
+ it "handles lowercase with more than 1 underscore" do
46
+ "so_you_want_contribute_to_merb_core".camel_case.should == "SoYouWantContributeToMerbCore"
47
+ end
48
+
49
+ it "handles lowercase with more than 1 underscore in a row" do
50
+ "__python__is__like__this".camel_case.should == "PythonIsLikeThis"
51
+ end
52
+
53
+ it "handle first capital letter with underscores" do
54
+ "Python__Is__Like__This".camel_case.should == "PythonIsLikeThis"
55
+ end
56
+
57
+ it "leaves CamelCase as is" do
58
+ "TestController".camel_case.should == "TestController"
59
+ end
60
+ end
61
+
62
+
63
+
64
+ describe String, "#snake_case" do
65
+ it "lowercases one word CamelCase" do
66
+ "Merb".snake_case.should == "merb"
67
+ end
68
+
69
+ it "makes one underscore snake_case two word CamelCase" do
70
+ "MerbCore".snake_case.should == "merb_core"
71
+ end
72
+
73
+ it "handles CamelCase with more than 2 words" do
74
+ "SoYouWantContributeToMerbCore".snake_case.should == "so_you_want_contribute_to_merb_core"
75
+ end
76
+
77
+ it "handles CamelCase with more than 2 capital letter in a row" do
78
+ "CNN".snake_case.should == "cnn"
79
+ "CNNNews".snake_case.should == "cnn_news"
80
+ "HeadlineCNNNews".snake_case.should == "headline_cnn_news"
81
+ "NameACRONYM".snake_case.should == "name_acronym"
82
+ end
83
+
84
+ it "does NOT change one word lowercase" do
85
+ "merb".snake_case.should == "merb"
86
+ end
87
+
88
+ it "leaves snake_case as is" do
89
+ "merb_core".snake_case.should == "merb_core"
90
+ end
91
+ end
92
+
93
+
94
+
95
+ describe String, "#escape_regexp" do
96
+ it "escapes all * in a string" do
97
+ "*and*".escape_regexp.should == "\\*and\\*"
98
+ end
99
+
100
+ it "escapes all ? in a string" do
101
+ "?and?".escape_regexp.should == "\\?and\\?"
102
+ end
103
+
104
+ it "escapes all { in a string" do
105
+ "{and{".escape_regexp.should == "\\{and\\{"
106
+ end
107
+
108
+ it "escapes all } in a string" do
109
+ "}and}".escape_regexp.should == "\\}and\\}"
110
+ end
111
+
112
+ it "escapes all . in a string" do
113
+ ".and.".escape_regexp.should == "\\.and\\."
114
+ end
115
+
116
+ it "escapes all regexp special characters used in a string" do
117
+ "*?{}.".escape_regexp.should == "\\*\\?\\{\\}\\."
118
+ end
119
+ end
120
+
121
+
122
+
123
+ describe String, "#unescape_regexp" do
124
+ it "unescapes all \\* in a string" do
125
+ "\\*and\\*".unescape_regexp.should == "*and*"
126
+ end
127
+
128
+ it "unescapes all \\? in a string" do
129
+ "\\?and\\?".unescape_regexp.should == "?and?"
130
+ end
131
+
132
+ it "unescapes all \\{ in a string" do
133
+ "\\{and\\{".unescape_regexp.should == "{and{"
134
+ end
135
+
136
+ it "unescapes all \\} in a string" do
137
+ "\\}and\\}".unescape_regexp.should == "}and}"
138
+ end
139
+
140
+ it "unescapes all \\. in a string" do
141
+ "\\.and\\.".unescape_regexp.should == ".and."
142
+ end
143
+
144
+ it "unescapes all regexp special characters used in a string" do
145
+ "\\*\\?\\{\\}\\.".unescape_regexp.should == "*?{}."
146
+ end
147
+ end
148
+
149
+
150
+
151
+ describe String, "#/" do
152
+ it "concanates operands with File::SEPARATOR" do
153
+ ("merb" / "core").should == "merb#{File::SEPARATOR}core"
154
+ end
155
+ end
156
+
157
+
158
+ require 'rbconfig'
159
+ describe String, "#relative_path_from" do
160
+ it "uses other operand as base for path calculation" do
161
+ site_dir = Config::CONFIG["sitedir"]
162
+
163
+ two_levels_up = site_dir.split(File::SEPARATOR)
164
+ 2.times { two_levels_up.pop } # remove two deepest directories
165
+ two_levels_up = two_levels_up.join(File::SEPARATOR)
166
+
167
+ two_levels_up.relative_path_from(site_dir).should == "../.."
168
+ end
169
+ end
170
+
171
+
172
+ describe String, ".translate" do
173
+ before(:each) do
174
+ String.stub!(:translations).and_return({ "on snakes and rubies" => "a serpenti e rubini" })
175
+ end
176
+
177
+ it 'looks up for translation in translations dictionary' do
178
+ String.translate("on snakes and rubies").should == "a serpenti e rubini"
179
+ end
180
+
181
+ it 'returns string that has no translations as it is' do
182
+ String.translate("shapes").should == "shapes"
183
+ String.translate("kalopsia").should == "kalopsia"
184
+ String.translate("holding on to nothing").should == "holding on to nothing"
185
+ end
186
+ end
187
+
188
+ describe String, ".t" do
189
+ before(:each) do
190
+ String.stub!(:translations).and_return({ '%s must not be blank' => "%s moet ingevuld worden",
191
+ 'username' => 'gebruikersnaam',
192
+ '%s must be between %s and %s characters long' => '%s moet tussen %s en %s tekens lang zijn'})
193
+ end
194
+
195
+ it 'looks up for translation in translations dictionary and translates parameters as well' do
196
+ "%s must not be blank".t(:username).should == "gebruikersnaam moet ingevuld worden"
197
+ "%s must not be blank".t('username').should == "gebruikersnaam moet ingevuld worden"
198
+ "%s must be between %s and %s characters long".t(:password, 5, 9).should == "password moet tussen 5 en 9 tekens lang zijn"
199
+ end
200
+
201
+ it 'returns string that has no translations as it is' do
202
+ "password".t.should == "password"
203
+ end
204
+
205
+ it 'should not translate when freezed' do
206
+ "%s must not be blank".t('username'.freeze).should == "username moet ingevuld worden"
207
+ end
208
+ end
209
+
210
+ describe String, ".translations" do
211
+ before(:each) do
212
+
213
+ end
214
+
215
+ it 'returns empty hash by default' do
216
+ String.translations.should == {}
217
+ end
218
+
219
+ it 'returns @translations if set' do
220
+ pending "is it @translations on metaclass or @@translations? leaving it out for now"
221
+ end
222
+ end
data/test/setup.rb ADDED
@@ -0,0 +1,15 @@
1
+ # Add PROJECT/lib to $LOAD_PATH
2
+ $LOAD_PATH.unshift(File.expand_path("#{__FILE__}/../../lib"))
3
+
4
+ # Ensure baretest is required
5
+ require 'baretest'
6
+
7
+ # Some defaults on BareTest (see Kernel#BareTest)
8
+ BareTest do
9
+ require_baretest "0.5.0" # minimum baretest version to run these tests
10
+ require_ruby "1.8.7" # minimum ruby version to run these tests
11
+ use :support # Use :support in all suites
12
+ use :basic_verifications
13
+ end
14
+
15
+ require 'ruby-debug'
@@ -0,0 +1,189 @@
1
+ @singular | @plural
2
+ 'ability' | 'abilities'
3
+ 'account' | 'accounts'
4
+ 'address' | 'addresses'
5
+ 'agency' | 'agencies'
6
+ 'alga' | 'algae'
7
+ 'alias' | 'aliases'
8
+ 'alumna' | 'alumnae'
9
+ 'alumnus' | 'alumni'
10
+ 'analysis' | 'analyses'
11
+ 'appendix' | 'appendices'
12
+ 'archive' | 'archives'
13
+ 'arena' | 'arenas'
14
+ 'article' | 'articles'
15
+ 'asset' | 'assets'
16
+ 'athlete' | 'athletes'
17
+ 'attachment' | 'attachments'
18
+ 'axis' | 'axes'
19
+ 'basis' | 'bases'
20
+ 'book' | 'books'
21
+ 'bookie' | 'bookies'
22
+ 'box' | 'boxes'
23
+ 'branch' | 'branches'
24
+ 'buffalo' | 'buffaloes'
25
+ 'bus' | 'buses'
26
+ 'buy' | 'buys'
27
+ 'case' | 'cases'
28
+ 'cactus' | 'cacti'
29
+ 'cat' | 'cats'
30
+ 'category' | 'categories'
31
+ 'child' | 'children'
32
+ 'city' | 'cities'
33
+ 'comment' | 'comments'
34
+ 'commit' | 'commits'
35
+ 'cookie' | 'cookies'
36
+ 'cow' | 'cows'
37
+ 'crisis' | 'crises'
38
+ 'criterion' | 'criteria'
39
+ 'cross' | 'crosses'
40
+ 'crunch' | 'crunches'
41
+ 'cry' | 'cries'
42
+ 'date' | 'dates'
43
+ 'datum' | 'data'
44
+ 'day' | 'days'
45
+ 'diagnosis' | 'diagnoses'
46
+ 'die' | 'dice'
47
+ 'document' | 'documents'
48
+ 'download' | 'downloads'
49
+ 'drive' | 'drives'
50
+ 'dwarf' | 'dwarves'
51
+ 'edge' | 'edges'
52
+ 'edition' | 'editions'
53
+ 'elf' | 'elves'
54
+ 'equipment' | 'equipment'
55
+ 'erratum' | 'errata'
56
+ 'event' | 'events'
57
+ 'experience' | 'experiences'
58
+ 'fish' | 'fish'
59
+ 'fix' | 'fixes'
60
+ 'fly' | 'flies'
61
+ 'focus' | 'foci'
62
+ 'foobar' | 'foobars'
63
+ 'formula' | 'formulae'
64
+ 'forum' | 'fora'
65
+ 'fox' | 'foxes'
66
+ 'friend' | 'friends'
67
+ 'fruit' | 'fruits'
68
+ 'fungus' | 'fungi'
69
+ 'game' | 'games'
70
+ 'german' | 'germans'
71
+ 'goose' | 'geese'
72
+ 'grass' | 'grass'
73
+ 'guy' | 'guys'
74
+ 'half' | 'halves'
75
+ 'hero' | 'heroes'
76
+ 'hippopotamus' | 'hippopotami'
77
+ 'hive' | 'hives'
78
+ 'horse' | 'horses'
79
+ 'house' | 'houses'
80
+ 'hovercraft' | 'hovercraft'
81
+ 'human' | 'humans'
82
+ 'income' | 'incomes'
83
+ 'index' | 'indices'
84
+ 'information' | 'information'
85
+ 'installation' | 'installations'
86
+ 'invoice' | 'invoices'
87
+ 'job' | 'jobs'
88
+ 'joy' | 'joys'
89
+ 'life' | 'lives'
90
+ 'link' | 'links'
91
+ 'location' | 'locations'
92
+ 'louse' | 'lice'
93
+ 'man' | 'men'
94
+ 'map' | 'maps'
95
+ 'mash' | 'mashes'
96
+ 'matrix_fu' | 'matrix_fus'
97
+ 'matrix' | 'matrices'
98
+ 'medium' | 'media'
99
+ 'memorandum' | 'memoranda'
100
+ 'milk' | 'milk'
101
+ 'money' | 'money'
102
+ 'moose' | 'moose'
103
+ 'mouse' | 'mice'
104
+ 'move' | 'moves'
105
+ 'movie' | 'movies'
106
+ 'mysql' | 'mysql'
107
+ 'nebula' | 'nebulae'
108
+ 'newsletter' | 'newsletters'
109
+ 'news' | 'news'
110
+ 'node_child' | 'node_children'
111
+ 'octopus' | 'octopi'
112
+ 'old_news' | 'old_news'
113
+ 'ox' | 'oxen'
114
+ 'package' | 'packages'
115
+ 'penis' | 'penises'
116
+ 'person' | 'people'
117
+ 'perspective' 'perspectives'
118
+ 'phenomenon' | 'phenomena'
119
+ 'photo' | 'photos'
120
+ 'ping' | 'pings'
121
+ 'plus' | 'plusses'
122
+ 'pokemon' | 'pokemon'
123
+ 'pokémon' | 'pokémon'
124
+ 'portfolio' | 'portfolios'
125
+ 'postgres' | 'postgres'
126
+ 'post' | 'posts'
127
+ 'potato' | 'potatoes'
128
+ 'prey' | 'preys'
129
+ 'price' | 'prices'
130
+ 'prize' | 'prizes'
131
+ 'process' | 'processes'
132
+ 'product' | 'products'
133
+ 'project' | 'projects'
134
+ 'proof' | 'proofs'
135
+ 'query' | 'queries'
136
+ 'quiz' | 'quizzes'
137
+ 'radius' | 'radii'
138
+ 'rain' | 'rain'
139
+ 'rat' | 'rats'
140
+ 'ray' | 'rays'
141
+ 'rice' | 'rice'
142
+ 'rookie' | 'rookies'
143
+ 'rose' | 'roses'
144
+ 'safe' | 'saves'
145
+ 'salesperson' 'salespeople'
146
+ 'schedule' | 'schedules'
147
+ 'search' | 'searches'
148
+ 'series' | 'series'
149
+ 'server' | 'servers'
150
+ 'shaman' | 'shamans'
151
+ 'sheep' | 'sheep'
152
+ 'shelf' | 'shelves'
153
+ 'shoe' | 'shoes'
154
+ 'song' | 'songs'
155
+ 'spam' | 'spams'
156
+ 'species' | 'species'
157
+ 'spokesman' | 'spokesmen'
158
+ 'sportsman' | 'sportsmen'
159
+ 'spray' | 'sprays'
160
+ 'stack' | 'stacks'
161
+ 'status_code' 'status_codes'
162
+ 'status' | 'statuses'
163
+ 'stimulus' | 'stimuli'
164
+ 'Swiss' | 'Swiss'
165
+ 'switch' | 'switches'
166
+ 'syllabus' | 'syllabi'
167
+ 'talisman' | 'talismans'
168
+ 'testis' | 'testes'
169
+ 'thesaurus' | 'thesauri'
170
+ 'thesis' | 'theses'
171
+ 'thief' | 'thieves'
172
+ 'ticket' | 'tickets'
173
+ 'tomato' | 'tomatoes'
174
+ 'tooth' | 'teeth'
175
+ 'torpedo' | 'torpedoes'
176
+ 'tournament' | 'tournaments'
177
+ 'toy' | 'toys'
178
+ 'trash' | 'trashes'
179
+ 'typo' | 'typos'
180
+ 'url' | 'urls'
181
+ 'version' | 'versions'
182
+ 'vertebra' | 'vertebrae'
183
+ 'vertex' | 'vertices'
184
+ 'virus' | 'viruses'
185
+ 'vita' | 'vitae'
186
+ 'wife' | 'wives'
187
+ 'wish' | 'wishes'
188
+ 'woman' | 'women'
189
+ 'zero' | 'zeroes'
@@ -0,0 +1,40 @@
1
+ # So we can test with all provided solutions
2
+ #BareTest.new_component :inflection do
3
+ require 'inflection'
4
+ suite 'Inflection', :use => :tabular_data do
5
+ suite 'bijective' do
6
+ setup.tabular_data <<-TABLE
7
+ @from | @to
8
+ :singular | :plural
9
+ :plural | :singular
10
+ TABLE
11
+
12
+ setup.tabular_data(File.read(File.expand_path('../inflection', __FILE__)))
13
+
14
+ setup do
15
+ class << self
16
+ attr_reader :singular, :plural
17
+ end
18
+ end
19
+
20
+ exercise "converting :singular <=> :plural from :from" do
21
+ ::Inflection.send(@to, send(@from))
22
+ end
23
+ verify "returns :to" do
24
+ returns(send(@to))
25
+ end
26
+ end
27
+
28
+ suite 'injective singular -> plural' do
29
+
30
+ setup.tabular_data(File.read(File.expand_path('../injective', __FILE__)))
31
+
32
+ exercise "converting :plural" do
33
+ ::Inflection.singular(@plural)
34
+ end
35
+ verify "returns :singular" do
36
+ returns(@singular)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,4 @@
1
+ @singular | @plural
2
+ 'index' | 'indexes'
3
+ 'plus' | 'pluses'
4
+ 'forum' | 'forums'
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inflection
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Dan Kubb
12
+ - Simon Hafner
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-07 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Support library for inflections
22
+ email:
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README.rdoc
30
+ files:
31
+ - .gitignore
32
+ - LICENSE
33
+ - README.rdoc
34
+ - VERSION
35
+ - inflection.gemspec
36
+ - lib/inflection.rb
37
+ - spec/inflection_extras_spec.rb
38
+ - spec/string_spec.rb
39
+ - test/setup.rb
40
+ - test/suite/lib/inflection
41
+ - test/suite/lib/inflection.rb
42
+ - test/suite/lib/injective
43
+ has_rdoc: true
44
+ homepage: http://github.com/Tass/extlib
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.7
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Provies english inflection.
75
+ test_files: []
76
+