inflection 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,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
+