roda-tags 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
- # The inflector extension adds inflection instance methods to String, which allows the easy
1
+ # frozen_string_literal: false
2
+
3
+ # The inflector extension adds inflection instance methods to String, which allows the easy
2
4
  # transformation of words from singular to plural, class names to table names, modularized class
3
- # names to ones without, and class names to foreign keys. It exists for
5
+ # names to ones without, and class names to foreign keys. It exists for
4
6
  # backwards compatibility to legacy Sequel code.
5
7
  #
6
8
  # To load the extension:
@@ -17,16 +19,21 @@ class String
17
19
  # inflect.uncountable "equipment"
18
20
  # end
19
21
  #
20
- # New rules are added at the top. So in the example above, the irregular rule for octopus will
21
- # now be the first of the pluralization and singularization rules that is runs. This guarantees
22
+ # New rules are added at the top. So in the example above, the irregular rule for octopus will
23
+ # now be the first of the pluralization and singularization rules that is runs. This guarantees
22
24
  # that your rules run before any of the rules that may already have been loaded.
25
+ #
23
26
  module Inflections
27
+ # Array to store plural inflection rules
24
28
  @plurals = []
29
+ # Array to store singular inflection rules
25
30
  @singulars = []
31
+ # Array to store words that are the same in singular and plural forms
26
32
  @uncountables = []
27
-
33
+
28
34
  # Proc that is instance evaled to create the default inflections for both the
29
35
  # model inflector and the inflector extension.
36
+ # rubocop:disable Metrics/BlockLength
30
37
  DEFAULT_INFLECTIONS_PROC = proc do
31
38
  plural(/$/, 's')
32
39
  plural(/s$/i, 's')
@@ -66,29 +73,45 @@ class String
66
73
  irregular('quiz', 'quizzes')
67
74
  irregular('testis', 'testes')
68
75
 
69
- uncountable(%w(equipment information rice money species series fish sheep news))
76
+ uncountable(%w[equipment information rice money species series fish sheep news])
70
77
  end
71
-
72
-
78
+ # rubocop:enable Metrics/BlockLength
79
+
73
80
  class << self
74
- # Array of 2 element arrays, first containing a regex, and the second containing a
75
- # substitution pattern, used for plurization.
81
+ # An Array that stores the pluralization rules.
82
+ # Each rule is a 2-element array containing:
83
+ # - A regular expression pattern for matching words to pluralize
84
+ # - A substitution pattern (e.g. '\1es') for transforming the match into plural form
85
+ # Rules are processed in reverse order, so newer rules take precedence.
76
86
  attr_reader :plurals
77
87
 
78
- # Array of 2 element arrays, first containing a regex, and the second containing a
79
- # substitution pattern, used for singularization.
88
+ # An Array that stores the singularization rules.
89
+ # Each rule is a 2-element array containing:
90
+ # - A regular expression pattern for matching plural words
91
+ # - A substitution pattern (e.g. '\1y') for transforming the match into singular form
92
+ # Rules are processed in reverse order, so newer rules take precedence.
80
93
  attr_reader :singulars
81
94
 
82
- # Array of strings for words were the singular form is the same as the plural form
95
+ # An Array of uncountable word strings that should not be inflected.
96
+ # These words have the same form in both singular and plural.
97
+ # Examples: 'fish', 'money', 'species'
83
98
  attr_reader :uncountables
84
99
  end
85
100
 
86
- # Clears the loaded inflections within a given scope (default is :all). Give the scope as a
87
- # symbol of the inflection type, the options are: :plurals, :singulars, :uncountables
101
+ # Clear inflection rules in a given scope.
102
+ # If scope is not specified, all inflection rules will be cleared.
103
+ # Passing :plurals, :singulars, or :uncountables will clear only that specific type of rule.
104
+ #
105
+ # @param scope [Symbol] The scope of rules to clear. Can be :all (default),
106
+ # :plurals, :singulars, or :uncountables
107
+ # @return [Array] An empty array
108
+ #
109
+ # @example Clear all inflection rules
110
+ # String.inflections.clear
111
+ #
112
+ # @example Clear only plural rules
113
+ # String.inflections.clear(:plurals)
88
114
  #
89
- # Examples:
90
- # clear :all
91
- # clear :plurals
92
115
  def self.clear(scope = :all)
93
116
  case scope
94
117
  when :all
@@ -96,219 +119,370 @@ class String
96
119
  @singulars = []
97
120
  @uncountables = []
98
121
  else
99
- instance_variable_set("@#{scope}", [])
122
+ instance_variable_set(:"@#{scope}", [])
100
123
  end
101
124
  end
102
125
 
103
- # Specifies a new irregular that applies to both pluralization and singularization at the same
104
- # time. This can only be used for strings, not regular expressions. You simply pass the
105
- # irregular in singular and plural form.
126
+ # Specifies a new irregular inflection rule that transforms between singular and plural forms.
127
+ # This method creates rules for both pluralization and singularization simultaneously.
128
+ # Unlike regular inflection rules, this only works with literal strings, not regexp.
129
+ #
130
+ # @param singular [String] The singular form of the word
131
+ # @param plural [String] The plural form of the word
132
+ #
133
+ # @example
134
+ # irregular('person', 'people') # Creates rules to transform person <-> people
135
+ # irregular('child', 'children') # Creates rules to transform child <-> children
106
136
  #
107
- # Examples:
108
- # irregular 'octopus', 'octopi'
109
- # irregular 'person', 'people'
110
137
  def self.irregular(singular, plural)
111
- plural(Regexp.new("(#{singular[0, 1]})#{singular[1..-1]}$", 'i'), '\1' + plural[1..-1])
112
- singular(Regexp.new("(#{plural[0, 1]})#{plural[1..-1]}$", 'i'), '\1' + singular[1..-1])
138
+ plural(Regexp.new("(#{singular[0, 1]})#{singular[1..]}$", 'i'), "\\1#{plural[1..]}")
139
+ singular(Regexp.new("(#{plural[0, 1]})#{plural[1..]}$", 'i'), "\\1#{singular[1..]}")
113
140
  end
114
141
 
115
- # Specifies a new pluralization rule and its replacement. The rule can either be a string or a
116
- # regular expression. The replacement should always be a string that may include references to
117
- # the matched data from the rule.
142
+ # Specifies a new pluralization rule to transform singular words into plural forms.
143
+ # Adds the rule to the beginning of the rules array so it takes precedence over existing rules.
144
+ #
145
+ # @param rule [Regexp, String] Pattern to match words that should be pluralized
146
+ # @param replacement [String] Template for constructing the plural form, can reference
147
+ # captured groups from the rule pattern using \1, \2 etc.
148
+ # @return [Array] The updated array of plural rules
149
+ #
150
+ # @example Add rule to pluralize words ending in 'y'
151
+ # plural(/([^aeiou])y$/i, '\1ies') # changes 'fly' to 'flies'
118
152
  #
119
- # Example:
120
- # plural(/(x|ch|ss|sh)$/i, '\1es')
121
153
  def self.plural(rule, replacement)
122
154
  @plurals.insert(0, [rule, replacement])
123
155
  end
124
156
 
125
- # Specifies a new singularization rule and its replacement. The rule can either be a string or
126
- # a regular expression. The replacement should always be a string that may include references
127
- # to the matched data from the rule.
157
+ # Specifies a new singularization rule to transform plural words into singular forms.
158
+ # Adds the rule to the beginning of the rules array so it takes precedence over existing rules.
159
+ #
160
+ # @param rule [Regexp, String] Pattern to match words that should be singularized
161
+ # @param replacement [String] Template for constructing the singular form, can reference
162
+ # captured groups from the rule pattern using \1, \2 etc.
163
+ #
164
+ # @return [Array] The updated array of singular rules
165
+ #
166
+ # @example Add rule to singularize words ending in 'ies'
167
+ # singular(/([^aeiou])ies$/i, '\1y') # changes 'flies' to 'fly'
128
168
  #
129
- # Example:
130
- # singular(/([^aeiouy]|qu)ies$/i, '\1y')
131
169
  def self.singular(rule, replacement)
132
170
  @singulars.insert(0, [rule, replacement])
133
171
  end
134
172
 
135
- # Add uncountable words that shouldn't be attempted inflected.
173
+ # Adds words that have the same singular and plural form to the uncountables list.
174
+ # These words will be skipped by the inflector and returned unchanged.
175
+ #
176
+ # @param words [Array<String>] One or more words to mark as uncountable
177
+ # @return [Array] The flattened array of all uncountable words
178
+ #
179
+ # @example Add a single uncountable word
180
+ # uncountable "fish"
181
+ #
182
+ # @example Add multiple uncountable words
183
+ # uncountable "rice", "equipment"
184
+ #
185
+ # @example Add an array of uncountable words
186
+ # uncountable %w(sheep species)
136
187
  #
137
- # Examples:
138
- # uncountable "money"
139
- # uncountable "money", "information"
140
- # uncountable %w( money information rice )
141
188
  def self.uncountable(*words)
142
189
  (@uncountables << words).flatten!
143
190
  end
144
191
 
145
- # Sequel.require('default_inflections', 'model')
146
- # instance_eval(&Sequel::DEFAULT_INFLECTIONS_PROC)
147
- # Sequel.require('default_inflections', 'model')
148
- instance_eval(&DEFAULT_INFLECTIONS_PROC)
192
+ # Execute the default inflection rules defined in DEFAULT_INFLECTIONS_PROC
193
+ # This sets up the basic plural/singular transformations and irregular/uncountable words
194
+ # that the inflector will use by default
195
+ instance_exec(&DEFAULT_INFLECTIONS_PROC)
149
196
  end
150
197
 
151
- # Yield the Inflections module if a block is given, and return
152
- # the Inflections module.
198
+ # Provides access to the Inflections module for defining custom inflection rules.
199
+ # If a block is given, yields the Inflections module to the block.
200
+ # Always returns the Inflections module.
201
+ #
202
+ # @yield [Inflections] The Inflections module if a block is given
203
+ #
204
+ # @return [Inflections] The Inflections module
205
+ #
206
+ # @example Define custom inflection rules
207
+ # String.inflections do |inflect|
208
+ # inflect.plural /^(ox)$/i, '\1\2en'
209
+ # inflect.singular /^(ox)en/i, '\1'
210
+ # end
211
+ #
153
212
  def self.inflections
154
- yield Inflections if block_given?
213
+ yield Inflections if defined?(yield)
155
214
  Inflections
156
215
  end
157
216
 
158
- # By default, camelize converts the string to UpperCamelCase. If the argument to camelize
159
- # is set to :lower then camelize produces lowerCamelCase.
217
+ # Converts the string to CamelCase format.
218
+ # - Replaces forward slashes with double colons (e.g. 'foo/bar' -> 'Foo::Bar')
219
+ # - Converts underscores to camelized format (e.g. 'foo_bar' -> 'FooBar')
160
220
  #
161
- # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
221
+ # @param first_letter_in_uppercase [Symbol] Whether first letter should be
222
+ # uppercase (:upper) or lowercase (:lower)
162
223
  #
163
- # Examples
224
+ # @return [String] The camelized string
225
+ #
226
+ # @example Convert to UpperCamelCase
164
227
  # "active_record".camelize #=> "ActiveRecord"
228
+ #
229
+ # @example Convert to lowerCamelCase
165
230
  # "active_record".camelize(:lower) #=> "activeRecord"
231
+ #
232
+ # @example Convert path to namespace
166
233
  # "active_record/errors".camelize #=> "ActiveRecord::Errors"
167
- # "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
234
+ #
168
235
  def camelize(first_letter_in_uppercase = :upper)
169
- s = gsub(%r{/(.?)}) { |x| "::#{x[-1..-1].upcase unless x == '/'}" }
170
- .gsub(/(^|_)(.)/) { |x| x[-1..-1].upcase }
236
+ s = gsub(%r{/(.?)}) { |x| "::#{x[-1..].upcase unless x == "/"}" }
237
+ .gsub(/(^|_)(.)/) { |x| x[-1..].upcase }
171
238
  s[0...1] = s[0...1].downcase unless first_letter_in_uppercase == :upper
172
239
  s
173
240
  end
174
- alias_method :camelcase, :camelize
241
+ alias camelcase camelize
175
242
 
176
- # Singularizes and camelizes the string. Also strips out all characters preceding
177
- # and including a period (".").
243
+ # Converts a string into a class name by removing any non-final period and subsequent characters,
244
+ # converting to singular form, and camelizing.
245
+ # Commonly used to obtain class name from table or file names.
246
+ #
247
+ # @return [String] A camelized singular form suitable for a class name
178
248
  #
179
- # Examples
249
+ # @example Convert database table name to class name
180
250
  # "egg_and_hams".classify #=> "EggAndHam"
181
- # "post".classify #=> "Post"
251
+ #
252
+ # @example Remove schema prefix
182
253
  # "schema.post".classify #=> "Post"
254
+ #
255
+ # @example Basic conversion
256
+ # "post".classify #=> "Post"
257
+ #
183
258
  def classify
184
259
  sub(/.*\./, '').singularize.camelize
185
260
  end
186
261
 
187
- # Constantize tries to find a declared constant with the name specified
188
- # in the string. It raises a NameError when the name is not in CamelCase
189
- # or is not initialized.
262
+ # Finds and returns a Ruby constant from a string name.
263
+ # The string must be a valid constant name in CamelCase format.
264
+ # Can handle namespaced constants using double colons (::).
265
+ # Raises NameError if the constant name is invalid or not defined.
190
266
  #
191
- # Examples
267
+ # @return [Object] The Ruby constant corresponding to the string name
268
+ #
269
+ # @raise [NameError] If string is not a valid constant name or constant is not defined
270
+ #
271
+ # @example Get Module class
192
272
  # "Module".constantize #=> Module
193
- # "Class".constantize #=> Class
273
+ #
274
+ # @example Get namespaced constant
275
+ # "ActiveRecord::Base".constantize #=> ActiveRecord::Base
276
+ #
277
+ # @example Invalid constant name
278
+ # "invalid_name".constantize #=> NameError: invalid_name is not a valid constant name!
279
+ #
194
280
  def constantize
195
- unless m = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.match(self)
196
- raise(NameError, "#{inspect} is not a valid constant name!")
281
+ unless (m = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.match(self))
282
+ raise(NameError, "#{inspect} is not a valid constant name!")
197
283
  end
198
- Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
284
+
285
+ # rubcop:disable Style/DocumentDynamicEvalDefinition
286
+ Object.module_eval("::#{m[1]}", __FILE__, __LINE__) # ::Post
287
+ # rubcop:enable Style/DocumentDynamicEvalDefinition
199
288
  end
200
289
 
201
- # Replaces underscores with dashes in the string.
290
+ # Replaces underscores (_) in a string with dashes (-).
291
+ # A helper method commonly used for URL slugs and CSS class names.
292
+ #
293
+ # @return [String] The string with underscores replaced by dashes
294
+ #
295
+ # @example
296
+ # "hello_world".dasherize #=> "hello-world"
297
+ # "foo_bar_baz".dasherize #=> "foo-bar-baz"
202
298
  #
203
- # Example
204
- # "puni_puni".dasherize #=> "puni-puni"
205
299
  def dasherize
206
300
  tr('_', '-')
207
301
  end
208
302
 
209
- # Removes the module part from the expression in the string
303
+ # Removes the module part from a fully-qualified Ruby constant name,
304
+ # returning just the rightmost portion after the last double colon (::).
305
+ #
306
+ # @return [String] The final constant name without any module namespacing
307
+ #
308
+ # @example Remove module namespace from fully-qualified name
309
+ # "ActiveRecord::Base::Table".demodulize #=> "Table"
310
+ #
311
+ # @example No change when no modules present
312
+ # "String".demodulize #=> "String"
210
313
  #
211
- # Examples
212
- # "ActiveRecord::CoreExtensions::String::Inflections".demodulize #=> "Inflections"
213
- # "Inflections".demodulize #=> "Inflections"
214
314
  def demodulize
215
315
  gsub(/^.*::/, '')
216
316
  end
217
317
 
218
- # Creates a foreign key name from a class name.
219
- # +use_underscore+ sets whether the method should put '_' between the name and 'id'.
318
+ # Creates a foreign key name from a class name by removing any module namespacing,
319
+ # underscoring the remaining name, and appending 'id'. The underscore before 'id'
320
+ # is optional.
321
+ #
322
+ # @param use_underscore [Boolean] Whether to include an underscore before 'id'
323
+ #
324
+ # @return [String] The foreign key name
220
325
  #
221
- # Examples
326
+ # @example Basic usage
222
327
  # "Message".foreign_key #=> "message_id"
223
- # "Message".foreign_key(false) #=> "messageid"
328
+ #
329
+ # @example Without underscore
330
+ # "Message".foreign_key(use_underscore: false) #=> "messageid"
331
+ #
332
+ # @example With namespaced class
224
333
  # "Admin::Post".foreign_key #=> "post_id"
225
- def foreign_key(use_underscore = true)
226
- "#{demodulize.underscore}#{'_' if use_underscore}id"
334
+ #
335
+ def foreign_key(use_underscore: true)
336
+ "#{demodulize.underscore}#{"_" if use_underscore}id"
227
337
  end
228
338
 
229
- # Capitalizes the first word and turns underscores into spaces and strips _id.
230
- # Like titleize, this is meant for creating pretty output.
339
+ # Converts a string into a more human-readable format by:
340
+ # - Removing any trailing '_id'
341
+ # - Converting underscores to spaces
342
+ # - Capitalizing the first letter
343
+ #
344
+ # @return [String] A human-friendly version of the string
345
+ #
346
+ # @example Convert a database column name
347
+ # "employee_salary".humanize #=> "Employee salary"
348
+ #
349
+ # @example Remove ID suffix
350
+ # "user_id".humanize #=> "User"
351
+ #
352
+ # @example Basic conversion
353
+ # "hello_world".humanize #=> "Hello world"
231
354
  #
232
- # Examples
233
- # "employee_salary" #=> "Employee salary"
234
- # "author_id" #=> "Author"
235
355
  def humanize
236
356
  gsub(/_id$/, '').tr('_', ' ').capitalize
237
357
  end
238
358
 
239
- # Returns the plural form of the word in the string.
359
+ # Transforms a word into its plural form according to standard English language rules
360
+ # and any custom rules defined through String.inflections.
240
361
  #
241
- # Examples
362
+ # If the word is in the uncountable list (e.g. "sheep", "fish"), returns it unchanged.
363
+ # Otherwise applies plural transformation rules in order until one matches.
364
+ #
365
+ # @return [String] The plural form of the word
366
+ #
367
+ # @example Basic pluralization
242
368
  # "post".pluralize #=> "posts"
243
369
  # "octopus".pluralize #=> "octopi"
244
- # "sheep".pluralize #=> "sheep"
245
- # "words".pluralize #=> "words"
370
+ #
371
+ # @example Uncountable words
372
+ # "fish".pluralize #=> "fish"
373
+ #
374
+ # @example Complex phrases
246
375
  # "the blue mailman".pluralize #=> "the blue mailmen"
247
376
  # "CamelOctopus".pluralize #=> "CamelOctopi"
377
+ #
248
378
  def pluralize
249
379
  result = dup
250
380
  unless Inflections.uncountables.include?(downcase)
251
- Inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
381
+ Inflections.plurals.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
252
382
  end
253
383
  result
254
384
  end
255
385
 
256
- # The reverse of pluralize, returns the singular form of a word in a string.
386
+ # Transforms a word into its singular form according to standard English language rules
387
+ # and any custom rules defined through String.inflections.
257
388
  #
258
- # Examples
389
+ # If the word is in the uncountable list (e.g. "sheep", "fish"), returns it unchanged.
390
+ # Otherwise applies singular transformation rules in order until one matches.
391
+ #
392
+ # @return [String] The singular form of the word
393
+ #
394
+ # @example Basic singularization
259
395
  # "posts".singularize #=> "post"
260
- # "octopi".singularize #=> "octopus"
261
- # "sheep".singluarize #=> "sheep"
262
- # "word".singluarize #=> "word"
396
+ # "matrices".singularize #=> "matrix"
397
+ #
398
+ # @example Uncountable words
399
+ # "fish".singularize #=> "fish"
400
+ #
401
+ # @example Complex phrases
263
402
  # "the blue mailmen".singularize #=> "the blue mailman"
264
403
  # "CamelOctopi".singularize #=> "CamelOctopus"
404
+ #
265
405
  def singularize
266
406
  result = dup
267
407
  unless Inflections.uncountables.include?(downcase)
268
- Inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
408
+ Inflections.singulars.each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
269
409
  end
270
410
  result
271
411
  end
272
412
 
273
- # Underscores and pluralizes the string.
413
+ # Converts a class name or CamelCase word to a suitable database table name
414
+ # by underscoring and pluralizing it. Namespaces are converted to paths.
415
+ # Used to derive table names from model class names.
274
416
  #
275
- # Examples
417
+ # @return [String] The table name (underscored, pluralized form)
418
+ #
419
+ # @example Convert class name to table name
276
420
  # "RawScaledScorer".tableize #=> "raw_scaled_scorers"
277
- # "egg_and_ham".tableize #=> "egg_and_hams"
421
+ #
422
+ # @example Handle namespaces
423
+ # "Admin::Post".tableize #=> "admin/posts"
424
+ #
425
+ # @example Basic conversion
278
426
  # "fancyCategory".tableize #=> "fancy_categories"
427
+ #
279
428
  def tableize
280
429
  underscore.pluralize
281
430
  end
282
431
 
283
- # Capitalizes all the words and replaces some characters in the string to create
284
- # a nicer looking title. Titleize is meant for creating pretty output.
432
+ # Converts a string into a more human-readable title format by:
433
+ # - Converting underscores and dashes to spaces
434
+ # - Capitalizing each word
435
+ # - Applying human-friendly formatting
285
436
  #
286
437
  # titleize is also aliased as as titlecase
287
438
  #
288
- # Examples
289
- # "man from the boondocks".titleize #=> "Man From The Boondocks"
439
+ # @return [String] A titleized version of the string
440
+ #
441
+ # @example Convert basic string to title
442
+ # "hello_world".titleize #=> "Hello World"
443
+ #
444
+ # @example Convert with special characters
290
445
  # "x-men: the last stand".titleize #=> "X Men: The Last Stand"
446
+ #
447
+ # @example Convert camelCase to title
448
+ # "camelCase".titleize #=> "Camel Case"
449
+ #
291
450
  def titleize
292
- underscore.humanize.gsub(/\b([a-z])/) { |x| x[-1..-1].upcase }
451
+ underscore.humanize.gsub(/\b([a-z])/) { |x| x[-1..].upcase }
293
452
  end
294
- alias_method :titlecase, :titleize
453
+ alias titlecase titleize
295
454
 
296
- # The reverse of camelize. Makes an underscored form from the expression in the string.
297
- # Also changes '::' to '/' to convert namespaces to paths.
455
+ # Converts a CamelCase or camelCase string into an underscored format.
456
+ # - Replaces '::' with '/' for namespace/path conversion
457
+ # - Adds underscores between words including:
458
+ # - Between runs of capital letters: 'ABC' -> 'a_b_c'
459
+ # - Before first lowercase letter after capitals: 'HTMLParser' -> 'html_parser'
460
+ # - Before capitals after lowercase/numbers: 'fooBar' -> 'foo_bar'
461
+ # - Converts all dashes to underscores
462
+ # - Converts everything to lowercase
298
463
  #
299
- # Examples
464
+ # @return [String] The underscored version of the string
465
+ #
466
+ # @example Convert camelCase
467
+ # "camelCase".underscore #=> "camel_case"
300
468
  # "ActiveRecord".underscore #=> "active_record"
301
- # "ActiveRecord::Errors".underscore #=> active_record/errors
469
+ #
470
+ # @example Convert namespace
471
+ # "ActiveRecord::Errors".underscore #=> 'active_record/errors'
472
+ #
473
+ # @example Convert complex CamelCase
474
+ # "HTMLParser".underscore #=> "html_parser"
475
+ #
302
476
  def underscore
303
- gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
304
- .gsub(/([a-z\d])([A-Z])/, '\1_\2').tr('-', '_').downcase
477
+ gsub('::', '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
478
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2').tr('-', '_').downcase
305
479
  end
306
480
  end
307
481
 
308
-
309
482
  # Ripped from the Sequel gem by Jeremy Evans
310
- #
311
- #
483
+ # https://github.com/jeremyevans/sequel/blob/master/lib/sequel/extensions/inflector.rb
484
+ #
485
+ #
312
486
  # Copyright (c) 2007-2008 Sharon Rosner
313
487
  # Copyright (c) 2008-2015 Jeremy Evans
314
488
  #