sequel 1.5.1 → 2.0.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.
@@ -1,59 +1,61 @@
1
1
  module Sequel
2
2
  class Model
3
- HOOKS = [
4
- :after_initialize,
5
- :before_create,
6
- :after_create,
7
- :before_update,
8
- :after_update,
9
- :before_save,
10
- :after_save,
11
- :before_destroy,
12
- :after_destroy
13
- ]
3
+ # Hooks that are safe for public use
4
+ HOOKS = [:after_initialize, :before_create, :after_create, :before_update,
5
+ :after_update, :before_save, :after_save, :before_destroy, :after_destroy,
6
+ :before_validation, :after_validation]
7
+
8
+ # Hooks that are only for internal use
9
+ PRIVATE_HOOKS = [:before_update_values, :before_delete]
14
10
 
15
- # Some fancy code generation here in order to define the hook class methods...
16
- HOOK_METHOD_STR = %Q{
17
- def self.%s(method = nil, &block)
18
- unless block
19
- (raise SequelError, 'No hook method specified') unless method
20
- block = proc {send method}
21
- end
22
- add_hook(%s, &block)
11
+ # Returns true if the model class or any of its ancestors have defined
12
+ # hooks for the given hook key. Notice that this method cannot detect
13
+ # hooks defined using overridden methods.
14
+ def self.has_hooks?(key)
15
+ has = hooks[key] && !hooks[key].empty?
16
+ has || ((self != Model) && superclass.has_hooks?(key))
17
+ end
18
+
19
+ ### Private Class Methods ###
20
+
21
+ # Add a hook block to the list of hook methods.
22
+ # If a non-nil tag is given and it already is in the list of hooks,
23
+ # replace it with the new block.
24
+ def self.add_hook(hook, tag, &block) #:nodoc:
25
+ unless block
26
+ (raise Error, 'No hook method specified') unless tag
27
+ block = proc {send tag}
23
28
  end
24
- }
25
-
26
- class << self
27
- # Returns true if the model class or any of its ancestors have defined
28
- # hooks for the given hook key. Notice that this method cannot detect
29
- # hooks defined using overridden methods.
30
- def has_hooks?(key)
31
- has = hooks[key] && !hooks[key].empty?
32
- has || ((self != Model) && superclass.has_hooks?(key))
29
+ h = hooks[hook]
30
+ if tag && (old = h.find{|x| x[0] == tag})
31
+ old[1] = block
32
+ else
33
+ h << [tag, block]
33
34
  end
34
- private
35
- def def_hook_method(m) #:nodoc:
36
- instance_eval(HOOK_METHOD_STR % [m.to_s, m.inspect])
37
- end
38
-
39
- # Returns the hooks hash for the model class.
40
- def hooks #:nodoc:
41
- @hooks ||= Hash.new {|h, k| h[k] = []}
42
- end
43
-
44
- def add_hook(hook, &block) #:nodoc:
45
- chain = hooks[hook]
46
- chain << block
47
- define_method(hook) do
48
- return false if super == false
49
- chain.each {|h| break false if instance_eval(&h) == false}
50
- end
51
- end
52
35
  end
53
36
 
54
- HOOKS.each do |h|
55
- define_method(h){}
56
- def_hook_method(h)
37
+ # Returns all hook methods for the given type of hook for this
38
+ # model class and its ancestors.
39
+ def self.all_hooks(hook) # :nodoc:
40
+ ((self == Model ? [] : superclass.send(:all_hooks, hook)) + hooks[hook].collect{|x| x[1]})
41
+ end
42
+
43
+ # Returns the hooks hash for this model class.
44
+ def self.hooks #:nodoc:
45
+ @hooks ||= Hash.new {|h, k| h[k] = []}
46
+ end
47
+
48
+ # Runs all hooks of type hook on the given object.
49
+ # Returns false if any hook returns false.
50
+ def self.run_hooks(hook, object) #:nodoc:
51
+ all_hooks(hook).each{|b| return false if object.instance_eval(&b) == false}
52
+ end
53
+
54
+ metaprivate :add_hook, :all_hooks, :hooks, :run_hooks
55
+
56
+ (HOOKS + PRIVATE_HOOKS).each do |hook|
57
+ instance_eval("def #{hook}(method = nil, &block); add_hook(:#{hook}, method, &block) end")
58
+ define_method(hook){model.send(:run_hooks, hook, self)}
57
59
  end
58
60
  end
59
61
  end
@@ -1,13 +1,12 @@
1
- require 'singleton'
1
+ # Add inflection methods to String, which allows the easy transformation of
2
+ # words from singular to plural,class names to table names, modularized class
3
+ # names to ones without, and class names to foreign keys.
2
4
 
3
- # The Inflector transforms words from singular to plural, class names to table names, modularized class names to ones without,
4
- # and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
5
- # in inflections.rb.
6
- module Inflector
7
- # A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
8
- # inflection rules. Examples:
5
+ class String
6
+ # This module acts as a singleton returned/yielded by String.inflections,
7
+ # which is used to override or specify additional inflection rules. Examples:
9
8
  #
10
- # Inflector.inflections do |inflect|
9
+ # String.inflections do |inflect|
11
10
  # inflect.plural /^(ox)$/i, '\1\2en'
12
11
  # inflect.singular /^(ox)en/i, '\1'
13
12
  #
@@ -19,25 +18,24 @@ module Inflector
19
18
  # New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
20
19
  # pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
21
20
  # already have been loaded.
22
- class Inflections
23
- include Singleton
21
+ module Inflections
22
+ @plurals, @singulars, @uncountables = [], [], []
24
23
 
25
- attr_reader :plurals, :singulars, :uncountables
24
+ metaattr_reader :plurals, :singulars, :uncountables
26
25
 
27
- def initialize
28
- @plurals, @singulars, @uncountables = [], [], []
29
- end
30
-
31
- # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
32
- # The replacement should always be a string that may include references to the matched data from the rule.
33
- def plural(rule, replacement)
34
- @plurals.insert(0, [rule, replacement])
35
- end
36
-
37
- # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
38
- # The replacement should always be a string that may include references to the matched data from the rule.
39
- def singular(rule, replacement)
40
- @singulars.insert(0, [rule, replacement])
26
+ # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
27
+ # the options are: :plurals, :singulars, :uncountables
28
+ #
29
+ # Examples:
30
+ # clear :all
31
+ # clear :plurals
32
+ def self.clear(scope = :all)
33
+ case scope
34
+ when :all
35
+ @plurals, @singulars, @uncountables = [], [], []
36
+ else
37
+ instance_variable_set("@#{scope}", [])
38
+ end
41
39
  end
42
40
 
43
41
  # Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
@@ -46,89 +44,101 @@ module Inflector
46
44
  # Examples:
47
45
  # irregular 'octopus', 'octopi'
48
46
  # irregular 'person', 'people'
49
- def irregular(singular, plural)
47
+ def self.irregular(singular, plural)
50
48
  plural(Regexp.new("(#{singular[0,1]})#{singular[1..-1]}$", "i"), '\1' + plural[1..-1])
51
49
  singular(Regexp.new("(#{plural[0,1]})#{plural[1..-1]}$", "i"), '\1' + singular[1..-1])
52
50
  end
53
51
 
52
+ # Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
53
+ # The replacement should always be a string that may include references to the matched data from the rule.
54
+ #
55
+ # Example:
56
+ # plural(/(x|ch|ss|sh)$/i, '\1es')
57
+ def self.plural(rule, replacement)
58
+ @plurals.insert(0, [rule, replacement])
59
+ end
60
+
61
+ # Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
62
+ # The replacement should always be a string that may include references to the matched data from the rule.
63
+ #
64
+ # Example:
65
+ # singular(/([^aeiouy]|qu)ies$/i, '\1y')
66
+ def self.singular(rule, replacement)
67
+ @singulars.insert(0, [rule, replacement])
68
+ end
69
+
54
70
  # Add uncountable words that shouldn't be attempted inflected.
55
71
  #
56
72
  # Examples:
57
73
  # uncountable "money"
58
74
  # uncountable "money", "information"
59
75
  # uncountable %w( money information rice )
60
- def uncountable(*words)
76
+ def self.uncountable(*words)
61
77
  (@uncountables << words).flatten!
62
78
  end
63
79
 
64
- # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
65
- # the options are: :plurals, :singulars, :uncountables
66
- #
67
- # Examples:
68
- # clear :all
69
- # clear :plurals
70
- def clear(scope = :all)
71
- case scope
72
- when :all
73
- @plurals, @singulars, @uncountables = [], [], []
74
- else
75
- instance_variable_set "@#{scope}", []
76
- end
77
- end
78
- end
80
+ # Setup the default inflections
81
+ plural(/$/, 's')
82
+ plural(/s$/i, 's')
83
+ plural(/(ax|test)is$/i, '\1es')
84
+ plural(/(octop|vir)us$/i, '\1i')
85
+ plural(/(alias|status)$/i, '\1es')
86
+ plural(/(bu)s$/i, '\1ses')
87
+ plural(/(buffal|tomat)o$/i, '\1oes')
88
+ plural(/([ti])um$/i, '\1a')
89
+ plural(/sis$/i, 'ses')
90
+ plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
91
+ plural(/(hive)$/i, '\1s')
92
+ plural(/([^aeiouy]|qu)y$/i, '\1ies')
93
+ plural(/(x|ch|ss|sh)$/i, '\1es')
94
+ plural(/(matr|vert|ind)ix|ex$/i, '\1ices')
95
+ plural(/([m|l])ouse$/i, '\1ice')
96
+ plural(/^(ox)$/i, '\1en')
97
+ plural(/(quiz)$/i, '\1zes')
79
98
 
80
- extend self
99
+ singular(/s$/i, '')
100
+ singular(/(n)ews$/i, '\1ews')
101
+ singular(/([ti])a$/i, '\1um')
102
+ singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1\2sis')
103
+ singular(/(^analy)ses$/i, '\1sis')
104
+ singular(/([^f])ves$/i, '\1fe')
105
+ singular(/(hive)s$/i, '\1')
106
+ singular(/(tive)s$/i, '\1')
107
+ singular(/([lr])ves$/i, '\1f')
108
+ singular(/([^aeiouy]|qu)ies$/i, '\1y')
109
+ singular(/(s)eries$/i, '\1eries')
110
+ singular(/(m)ovies$/i, '\1ovie')
111
+ singular(/(x|ch|ss|sh)es$/i, '\1')
112
+ singular(/([m|l])ice$/i, '\1ouse')
113
+ singular(/(bus)es$/i, '\1')
114
+ singular(/(o)es$/i, '\1')
115
+ singular(/(shoe)s$/i, '\1')
116
+ singular(/(cris|ax|test)es$/i, '\1is')
117
+ singular(/(octop|vir)i$/i, '\1us')
118
+ singular(/(alias|status)es$/i, '\1')
119
+ singular(/^(ox)en/i, '\1')
120
+ singular(/(vert|ind)ices$/i, '\1ex')
121
+ singular(/(matr)ices$/i, '\1ix')
122
+ singular(/(quiz)zes$/i, '\1')
81
123
 
82
- def inflections
83
- if block_given?
84
- yield Inflections.instance
85
- else
86
- Inflections.instance
87
- end
88
- end
89
-
90
- # Returns the plural form of the word in the string.
91
- #
92
- # Examples
93
- # "post".pluralize #=> "posts"
94
- # "octopus".pluralize #=> "octopi"
95
- # "sheep".pluralize #=> "sheep"
96
- # "words".pluralize #=> "words"
97
- # "the blue mailman".pluralize #=> "the blue mailmen"
98
- # "CamelOctopus".pluralize #=> "CamelOctopi"
99
- def pluralize(word)
100
- result = word.to_s.dup
124
+ irregular('person', 'people')
125
+ irregular('man', 'men')
126
+ irregular('child', 'children')
127
+ irregular('sex', 'sexes')
128
+ irregular('move', 'moves')
101
129
 
102
- if inflections.uncountables.include?(result.downcase)
103
- result
104
- else
105
- inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
106
- result
107
- end
130
+ uncountable(%w(equipment information rice money species series fish sheep))
108
131
  end
109
132
 
110
- # The reverse of pluralize, returns the singular form of a word in a string.
111
- #
112
- # Examples
113
- # "posts".singularize #=> "post"
114
- # "octopi".singularize #=> "octopus"
115
- # "sheep".singluarize #=> "sheep"
116
- # "word".singluarize #=> "word"
117
- # "the blue mailmen".singularize #=> "the blue mailman"
118
- # "CamelOctopi".singularize #=> "CamelOctopus"
119
- def singularize(word)
120
- result = word.to_s.dup
121
-
122
- if inflections.uncountables.include?(result.downcase)
123
- result
124
- else
125
- inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
126
- result
127
- end
133
+ # Yield the Inflections module if a block is given, and return
134
+ # the Inflections module.
135
+ def self.inflections
136
+ yield Inflections if block_given?
137
+ Inflections
128
138
  end
129
139
 
130
- # By default, camelize converts strings to UpperCamelCase. If the argument to camelize
131
- # is set to ":lower" then camelize produces lowerCamelCase.
140
+ # By default, camelize converts the string to UpperCamelCase. If the argument to camelize
141
+ # is set to :lower then camelize produces lowerCamelCase.
132
142
  #
133
143
  # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
134
144
  #
@@ -137,143 +147,137 @@ module Inflector
137
147
  # "active_record".camelize(:lower) #=> "activeRecord"
138
148
  # "active_record/errors".camelize #=> "ActiveRecord::Errors"
139
149
  # "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
140
- def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
141
- if first_letter_in_uppercase
142
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
150
+ def camelize(first_letter_in_uppercase = :upper)
151
+ if first_letter_in_uppercase == :upper
152
+ gsub(/\/(.?)/){|x| "::#{x[-1..-1].upcase unless x == '/'}"}.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
143
153
  else
144
- lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
154
+ "#{first}#{camelize[1..-1]}"
145
155
  end
146
156
  end
157
+ alias_method :camelcase, :camelize
147
158
 
148
- # Capitalizes all the words and replaces some characters in the string to create
149
- # a nicer looking title. Titleize is meant for creating pretty output. It is not
150
- # used in the Rails internals.
151
- #
152
- # titleize is also aliased as as titlecase
159
+ # Singularizes and camelizes the string. Also strips out all characters preceding
160
+ # and including a period (".").
153
161
  #
154
162
  # Examples
155
- # "man from the boondocks".titleize #=> "Man From The Boondocks"
156
- # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
157
- def titleize(word)
158
- humanize(underscore(word)).gsub(/\b([a-z])/) { $1.capitalize }
163
+ # "egg_and_hams".classify #=> "EggAndHam"
164
+ # "post".classify #=> "Post"
165
+ # "schema.post".classify #=> "Post"
166
+ def classify
167
+ sub(/.*\./, '').singularize.camelize
159
168
  end
160
169
 
161
- # The reverse of +camelize+. Makes an underscored form from the expression in the string.
162
- #
163
- # Changes '::' to '/' to convert namespaces to paths.
170
+ # Constantize tries to find a declared constant with the name specified
171
+ # in the string. It raises a NameError when the name is not in CamelCase
172
+ # or is not initialized.
164
173
  #
165
174
  # Examples
166
- # "ActiveRecord".underscore #=> "active_record"
167
- # "ActiveRecord::Errors".underscore #=> active_record/errors
168
- def underscore(camel_cased_word)
169
- camel_cased_word.to_s.gsub(/::/, '/').
170
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
171
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
172
- tr("-", "_").
173
- downcase
175
+ # "Module".constantize #=> Module
176
+ # "Class".constantize #=> Class
177
+ def constantize
178
+ raise(NameError, "#{inspect} is not a valid constant name!") unless m = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.match(self)
179
+ Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
174
180
  end
175
181
 
176
182
  # Replaces underscores with dashes in the string.
177
183
  #
178
184
  # Example
179
- # "puni_puni" #=> "puni-puni"
180
- def dasherize(underscored_word)
181
- underscored_word.gsub(/_/, '-')
185
+ # "puni_puni".dasherize #=> "puni-puni"
186
+ def dasherize
187
+ gsub(/_/, '-')
182
188
  end
183
189
 
184
- # Capitalizes the first word and turns underscores into spaces and strips _id.
185
- # Like titleize, this is meant for creating pretty output.
190
+ # Removes the module part from the expression in the string
186
191
  #
187
192
  # Examples
188
- # "employee_salary" #=> "Employee salary"
189
- # "author_id" #=> "Author"
190
- def humanize(lower_case_and_underscored_word)
191
- lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
193
+ # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
194
+ # "Inflections".demodulize #=> "Inflections"
195
+ def demodulize
196
+ gsub(/^.*::/, '')
192
197
  end
193
198
 
194
- # Removes the module part from the expression in the string
199
+ # Creates a foreign key name from a class name.
200
+ # +use_underscore+ sets whether the method should put '_' between the name and 'id'.
195
201
  #
196
202
  # Examples
197
- # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
198
- # "Inflections".demodulize #=> "Inflections"
199
- def demodulize(class_name_in_module)
200
- class_name_in_module.to_s.gsub(/^.*::/, '')
203
+ # "Message".foreign_key #=> "message_id"
204
+ # "Message".foreign_key(false) #=> "messageid"
205
+ # "Admin::Post".foreign_key #=> "post_id"
206
+ def foreign_key(use_underscore = true)
207
+ "#{demodulize.underscore}#{'_' if use_underscore}id"
201
208
  end
202
209
 
203
- # Create the name of a table like Rails does for models to table names. This method
204
- # uses the pluralize method on the last word in the string.
210
+ # Capitalizes the first word and turns underscores into spaces and strips _id.
211
+ # Like titleize, this is meant for creating pretty output.
205
212
  #
206
213
  # Examples
207
- # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
208
- # "egg_and_ham".tableize #=> "egg_and_hams"
209
- # "fancyCategory".tableize #=> "fancy_categories"
210
- def tableize(class_name)
211
- pluralize(underscore(class_name))
214
+ # "employee_salary" #=> "Employee salary"
215
+ # "author_id" #=> "Author"
216
+ def humanize
217
+ gsub(/_id$/, "").gsub(/_/, " ").capitalize
212
218
  end
213
219
 
214
- # Create a class name from a table name like Rails does for table names to models.
215
- # Note that this returns a string and not a Class. (To convert to an actual class
216
- # follow classify with constantize.)
220
+ # Returns the plural form of the word in the string.
217
221
  #
218
222
  # Examples
219
- # "egg_and_hams".classify #=> "EggAndHam"
220
- # "post".classify #=> "Post"
221
- def classify(table_name)
222
- # strip out any leading schema name
223
- camelize(singularize(table_name.to_s.sub(/.*\./, '')))
223
+ # "post".pluralize #=> "posts"
224
+ # "octopus".pluralize #=> "octopi"
225
+ # "sheep".pluralize #=> "sheep"
226
+ # "words".pluralize #=> "words"
227
+ # "the blue mailman".pluralize #=> "the blue mailmen"
228
+ # "CamelOctopus".pluralize #=> "CamelOctopi"
229
+ def pluralize
230
+ result = dup
231
+ Inflections.plurals.each{|(rule, replacement)| break if result.gsub!(rule, replacement)} unless Inflections.uncountables.include?(downcase)
232
+ result
224
233
  end
225
234
 
226
- # Creates a foreign key name from a class name.
227
- # +separate_class_name_and_id_with_underscore+ sets whether
228
- # the method should put '_' between the name and 'id'.
235
+ # The reverse of pluralize, returns the singular form of a word in a string.
229
236
  #
230
237
  # Examples
231
- # "Message".foreign_key #=> "message_id"
232
- # "Message".foreign_key(false) #=> "messageid"
233
- # "Admin::Post".foreign_key #=> "post_id"
234
- def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
235
- underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
238
+ # "posts".singularize #=> "post"
239
+ # "octopi".singularize #=> "octopus"
240
+ # "sheep".singluarize #=> "sheep"
241
+ # "word".singluarize #=> "word"
242
+ # "the blue mailmen".singularize #=> "the blue mailman"
243
+ # "CamelOctopi".singularize #=> "CamelOctopus"
244
+ def singularize
245
+ result = dup
246
+ Inflections.singulars.each{|(rule, replacement)| break if result.gsub!(rule, replacement)} unless Inflections.uncountables.include?(downcase)
247
+ result
236
248
  end
237
249
 
238
- # Constantize tries to find a declared constant with the name specified
239
- # in the string. It raises a NameError when the name is not in CamelCase
240
- # or is not initialized.
250
+ # Underscores and pluralizes the string.
241
251
  #
242
252
  # Examples
243
- # "Module".constantize #=> Module
244
- # "Class".constantize #=> Class
245
- def constantize(camel_cased_word)
246
- unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
247
- raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
248
- end
253
+ # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
254
+ # "egg_and_ham".tableize #=> "egg_and_hams"
255
+ # "fancyCategory".tableize #=> "fancy_categories"
256
+ def tableize
257
+ underscore.pluralize
258
+ end
249
259
 
250
- Object.module_eval("::#{$1}", __FILE__, __LINE__)
260
+ # Capitalizes all the words and replaces some characters in the string to create
261
+ # a nicer looking title. Titleize is meant for creating pretty output.
262
+ #
263
+ # titleize is also aliased as as titlecase
264
+ #
265
+ # Examples
266
+ # "man from the boondocks".titleize #=> "Man From The Boondocks"
267
+ # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
268
+ def titleize
269
+ underscore.humanize.gsub(/\b([a-z])/){|x| x[-1..-1].upcase}
251
270
  end
271
+ alias_method :titlecase, :titleize
252
272
 
253
- # Ordinalize turns a number into an ordinal string used to denote the
254
- # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
273
+ # The reverse of camelize. Makes an underscored form from the expression in the string.
274
+ # Also changes '::' to '/' to convert namespaces to paths.
255
275
  #
256
276
  # Examples
257
- # ordinalize(1) # => "1st"
258
- # ordinalize(2) # => "2nd"
259
- # ordinalize(1002) # => "1002nd"
260
- # ordinalize(1003) # => "1003rd"
261
- def ordinalize(number)
262
- if (11..13).include?(number.to_i % 100)
263
- "#{number}th"
264
- else
265
- case number.to_i % 10
266
- when 1
267
- "#{number}st"
268
- when 2
269
- "#{number}nd"
270
- when 3
271
- "#{number}rd"
272
- else
273
- "#{number}th"
274
- end
275
- end
277
+ # "ActiveRecord".underscore #=> "active_record"
278
+ # "ActiveRecord::Errors".underscore #=> active_record/errors
279
+ def underscore
280
+ gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
281
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
276
282
  end
277
283
  end
278
-
279
- require File.dirname(__FILE__) + '/inflections'