Inflecto is dead, long live dry-inflector
This commit is contained in:
parent
a39d9a57b1
commit
cae1230594
|
@ -1,37 +0,0 @@
|
|||
## MAC OS
|
||||
.DS_Store
|
||||
|
||||
## TEXTMATE
|
||||
*.tmproj
|
||||
tmtags
|
||||
|
||||
## EMACS
|
||||
*~
|
||||
\#*
|
||||
.\#*
|
||||
|
||||
## VIM
|
||||
*.swp
|
||||
|
||||
## Rubinius
|
||||
*.rbc
|
||||
.rbx
|
||||
|
||||
## PROJECT::GENERAL
|
||||
*.gem
|
||||
coverage
|
||||
profiling
|
||||
turbulence
|
||||
rdoc
|
||||
pkg
|
||||
tmp
|
||||
doc
|
||||
log
|
||||
.yardoc
|
||||
measurements
|
||||
|
||||
## BUNDLER
|
||||
.bundle
|
||||
Gemfile.lock
|
||||
|
||||
## PROJECT::SPECIFIC
|
25
.travis.yml
25
.travis.yml
|
@ -1,25 +0,0 @@
|
|||
language: ruby
|
||||
before_install: gem install bundler
|
||||
bundler_args: --without yard guard benchmarks
|
||||
script: "bundle exec rake ci"
|
||||
rvm:
|
||||
- 1.9.3
|
||||
- 2.0.0
|
||||
- 2.1.3
|
||||
- ruby-head
|
||||
- rbx-19mode
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#rom-rb"
|
||||
on_success: never
|
||||
on_failure: change
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: change
|
||||
matrix:
|
||||
include:
|
||||
- rvm: jruby-19mode
|
||||
env: JRUBY_OPTS="$JRUBY_OPTS --debug"
|
||||
- rvm: jruby-head
|
||||
env: JRUBY_OPTS="$JRUBY_OPTS --debug"
|
|
@ -1,7 +0,0 @@
|
|||
# v0.0.2 2013-01-20
|
||||
|
||||
[change] Do not depend on backports
|
||||
|
||||
# v0.0.1 2012-12-12
|
||||
|
||||
First public release!
|
7
Gemfile
7
Gemfile
|
@ -1,7 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
|
||||
group :development, :test do
|
||||
gem 'devtools', '~> 0.1.x'
|
||||
end
|
18
Guardfile
18
Guardfile
|
@ -1,18 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
guard :bundler do
|
||||
watch('Gemfile')
|
||||
end
|
||||
|
||||
guard :rspec do
|
||||
# run all specs if the spec_helper or supporting files files are modified
|
||||
watch('spec/spec_helper.rb') { 'spec' }
|
||||
watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
|
||||
|
||||
# run unit specs if associated lib code is modified
|
||||
watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
|
||||
watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
|
||||
|
||||
# run a spec if it is modified
|
||||
watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
|
||||
end
|
20
LICENSE
20
LICENSE
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) The rails, merb & datamapper team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
52
README.md
52
README.md
|
@ -1,52 +1,4 @@
|
|||
inflecto
|
||||
Discontinued
|
||||
========
|
||||
|
||||
[![Gem Version](https://badge.fury.io/rb/inflecto.png)][gem]
|
||||
[![Build Status](https://secure.travis-ci.org/mbj/inflecto.png?branch=master)][travis]
|
||||
[![Dependency Status](https://gemnasium.com/mbj/inflecto.png)][gemnasium]
|
||||
[![Code Climate](https://codeclimate.com/github/mbj/inflecto.png)][codeclimate]
|
||||
[![Coverage Status](https://coveralls.io/repos/mbj/inflecto/badge.png?branch=master)][coveralls]
|
||||
|
||||
[gem]: https://rubygems.org/gems/inflecto
|
||||
[travis]: https://travis-ci.org/mbj/inflecto
|
||||
[gemnasium]: https://gemnasium.com/mbj/inflecto
|
||||
[codeclimate]: https://codeclimate.com/github/mbj/inflecto
|
||||
[coveralls]: https://coveralls.io/r/mbj/inflecto
|
||||
|
||||
This is a standalone inflector ripped out from [dm-core](https://github.com/datamapper/dm-core)
|
||||
The dm-core inflector originated from [extlib](https://github.com/datamapper/extlib)
|
||||
The extlib inflecto originated from [active_support](https://github.com/rails/rails)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Install the gem ```inflecto``` via your preferred method.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Soon.
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
The rails, merb & datamapper team
|
||||
|
||||
The current maintainer is Markus Schirp ([mbj](https://github.com/mbj)) with help from [indrekj](https://github.com/indrekj).
|
||||
|
||||
Contributing
|
||||
-------------
|
||||
|
||||
* If you want your code merged into the mainline, please discuss the proposed changes with me before doing any work on it. This library is still in early development, and the direction it is going may not always be clear. Some features may not be appropriate yet, may need to be deferred until later when the foundation for them is laid, or may be more applicable in a plugin.
|
||||
* Fork the project.
|
||||
* Make your feature addition or bug fix.
|
||||
* Follow this [style guide](https://github.com/dkubb/styleguide).
|
||||
* Add specs for it. This is important so I don't break it in a future version unintentionally. Tests must cover all branches within the code, and code must be fully covered.
|
||||
* Commit, do not mess with Rakefile, version, or history. (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)
|
||||
* Run "rake ci". This must pass and not show any regressions in the metrics for the code to be merged.
|
||||
* Send me a pull request. Bonus points for topic branches.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
See LICENSE for details
|
||||
This gem has been discontinued in favor of [dry-inflector](https://github.com/dry-rb/dry-inflector)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
threshold: 12
|
||||
total_score: 73
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
threshold: 11.3
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
name: inflecto
|
||||
namespace: Inflecto
|
||||
expect_coverage: '331/332'
|
111
config/reek.yml
111
config/reek.yml
|
@ -1,111 +0,0 @@
|
|||
---
|
||||
Attribute:
|
||||
enabled: true
|
||||
exclude:
|
||||
- Inflecto::Inflections
|
||||
BooleanParameter:
|
||||
enabled: true
|
||||
exclude: []
|
||||
ClassVariable:
|
||||
enabled: true
|
||||
exclude: []
|
||||
ControlParameter:
|
||||
enabled: true
|
||||
exclude: []
|
||||
DataClump:
|
||||
enabled: true
|
||||
exclude:
|
||||
- Inflecto::Inflections
|
||||
max_copies: 2
|
||||
min_clump_size: 2
|
||||
DuplicateMethodCall:
|
||||
enabled: true
|
||||
exclude:
|
||||
- Inflecto#self.camelize
|
||||
max_calls: 1
|
||||
allow_calls: []
|
||||
FeatureEnvy:
|
||||
enabled: true
|
||||
exclude: []
|
||||
IrresponsibleModule:
|
||||
enabled: true
|
||||
exclude: []
|
||||
LongParameterList:
|
||||
enabled: true
|
||||
exclude:
|
||||
- Inflecto::Inflections#add_irregular
|
||||
- Inflecto::Inflections#rule
|
||||
max_params: 2
|
||||
overrides:
|
||||
initialize:
|
||||
max_params: 3
|
||||
LongYieldList:
|
||||
enabled: true
|
||||
exclude: []
|
||||
max_params: 2
|
||||
NestedIterators:
|
||||
enabled: true
|
||||
exclude: []
|
||||
max_allowed_nesting: 1
|
||||
ignore_iterators: []
|
||||
NilCheck:
|
||||
enabled: true
|
||||
exclude: []
|
||||
RepeatedConditional:
|
||||
enabled: true
|
||||
exclude: []
|
||||
max_ifs: 1
|
||||
TooManyInstanceVariables:
|
||||
enabled: true
|
||||
exclude:
|
||||
- Inflecto::Inflections
|
||||
max_instance_variables: 3
|
||||
TooManyMethods:
|
||||
enabled: true
|
||||
exclude: []
|
||||
max_methods: 10
|
||||
TooManyStatements:
|
||||
enabled: true
|
||||
exclude:
|
||||
- each
|
||||
- 'Inflecto#self.underscore'
|
||||
- 'Inflecto#self.ordinalize'
|
||||
max_statements: 5
|
||||
UncommunicativeMethodName:
|
||||
enabled: true
|
||||
exclude: []
|
||||
reject:
|
||||
- !ruby/regexp /^[a-z]$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
- !ruby/regexp /[A-Z]/
|
||||
accept: []
|
||||
UncommunicativeModuleName:
|
||||
enabled: true
|
||||
exclude: []
|
||||
reject:
|
||||
- !ruby/regexp /^.$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
accept: []
|
||||
UncommunicativeParameterName:
|
||||
enabled: true
|
||||
exclude: []
|
||||
reject:
|
||||
- !ruby/regexp /^.$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
- !ruby/regexp /[A-Z]/
|
||||
accept: []
|
||||
UncommunicativeVariableName:
|
||||
enabled: true
|
||||
exclude: []
|
||||
reject:
|
||||
- !ruby/regexp /^.$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
- !ruby/regexp /[A-Z]/
|
||||
accept: []
|
||||
UnusedParameters:
|
||||
enabled: true
|
||||
exclude: []
|
||||
UtilityFunction:
|
||||
enabled: true
|
||||
exclude: []
|
||||
max_helper_calls: 0
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
AbcMetricMethodCheck: { score: 70 }
|
||||
AssignmentInConditionalCheck: { }
|
||||
CaseMissingElseCheck: { }
|
||||
ClassLineCountCheck: { line_count: 325 }
|
||||
ClassNameCheck:
|
||||
pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
|
||||
ClassVariableCheck: { }
|
||||
CyclomaticComplexityBlockCheck: { complexity: 4 }
|
||||
CyclomaticComplexityMethodCheck: { complexity: 4 }
|
||||
EmptyRescueBodyCheck: { }
|
||||
ForLoopCheck: { }
|
||||
MethodLineCountCheck: { line_count: 16 }
|
||||
MethodNameCheck:
|
||||
pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/
|
||||
ModuleLineCountCheck: { line_count: 331 }
|
||||
ModuleNameCheck:
|
||||
pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
|
||||
# TODO: decrease parameter_count to 2 or less
|
||||
ParameterNumberCheck: { parameter_count: 3 }
|
|
@ -1,7 +0,0 @@
|
|||
AllCops:
|
||||
Exclude:
|
||||
- 'lib/**/*'
|
||||
- 'spec/**/*'
|
||||
- 'Gemfile'
|
||||
- 'Guardfile'
|
||||
- 'inflecto.gemspec'
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
threshold: 100.0
|
|
@ -1,19 +0,0 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = 'inflecto'
|
||||
gem.version = '0.1.0'
|
||||
gem.authors = ['The rails, merb & datamapper team', 'Markus Schirp']
|
||||
gem.email = ['mbj@seonic.net']
|
||||
gem.description = 'Inflector for strings'
|
||||
gem.summary = gem.description
|
||||
gem.homepage = 'https://github.com/mbj/inflecto'
|
||||
gem.license = 'MIT'
|
||||
|
||||
gem.require_paths = %w[lib]
|
||||
gem.files = `git ls-files`.split($/)
|
||||
gem.test_files = `git ls-files spec/{unit,integration}`.split($/)
|
||||
gem.extra_rdoc_files = %w[LICENSE README.md TODO]
|
||||
|
||||
gem.required_ruby_version = '>= 1.9.3'
|
||||
end
|
331
lib/inflecto.rb
331
lib/inflecto.rb
|
@ -1,331 +0,0 @@
|
|||
require 'set'
|
||||
|
||||
# The Inflecto transforms words from singular to plural, class names to table names, modularized class names to ones without,
|
||||
# and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept
|
||||
# in inflections.rb.
|
||||
#
|
||||
# The Rails core team has stated patches for the inflections library will not be accepted
|
||||
# in order to avoid breaking legacy applications which may be relying on errant inflections.
|
||||
# If you discover an incorrect inflection and require it for your application, you'll need
|
||||
# to correct it yourself (explained below).
|
||||
module Inflecto
|
||||
|
||||
# Convert input to UpperCamelCase
|
||||
#
|
||||
# Will also convert '/' to '::' which is useful for converting paths to namespaces.
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
# Inflecto.camelize("data_mapper") # => "DataMapper"
|
||||
# Inflecto.camelize("data_mapper/errors") # => "DataMapper::Errors"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.camelize(input)
|
||||
input.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:\A|_)(.)/) { $1.upcase }
|
||||
end
|
||||
|
||||
# Convert input to underscored, lowercase string
|
||||
#
|
||||
# Changes '::' to '/' to convert namespaces to paths.
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
# Inflecto.underscore("DataMapper") # => "data_mapper"
|
||||
# Inflecto.underscore("DataMapper::Errors") # => "data_mapper/errors"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.underscore(input)
|
||||
word = input.gsub(/::/, '/')
|
||||
underscorize(word)
|
||||
end
|
||||
|
||||
# Convert input underscores to dashes
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
# Inflecto.dasherize("foo_bar") # => "foo-bar"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.dasherize(input)
|
||||
input.tr('_', '-')
|
||||
end
|
||||
|
||||
# Return unscoped constant name
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.demodulize("DataMapper::Error") # => "Error"
|
||||
# Inflecto.demodulize("DataMapper") # => "DataMapper"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.demodulize(input)
|
||||
input.split('::').last
|
||||
end
|
||||
|
||||
# Creates a foreign key name
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.foreign_key("Message") => "message_id"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.foreign_key(input)
|
||||
"#{underscorize(demodulize(input))}_id"
|
||||
end
|
||||
|
||||
# Find a constant with the name specified in the argument string
|
||||
#
|
||||
# The name is assumed to be the one of a top-level constant, constant scope of caller is ignored
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.constantize("Module") # => Module
|
||||
# Inflecto.constantize("DataMapper::Error") # => DataMapper::Error
|
||||
#
|
||||
# @return [Class, Module]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.constantize(input)
|
||||
names = input.split('::')
|
||||
names.shift if names.first.empty?
|
||||
|
||||
names.inject(Object) do |constant, name|
|
||||
if constant.const_defined?(name, false)
|
||||
constant.const_get(name)
|
||||
else
|
||||
constant.const_missing(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ORDINALIZE_TH = (4..16).to_set.freeze
|
||||
|
||||
# Convert a number into an ordinal string
|
||||
#
|
||||
# @param [Fixnum] number
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# ordinalize(1) # => "1st"
|
||||
# ordinalize(2) # => "2nd"
|
||||
# ordinalize(1002) # => "1002nd"
|
||||
# ordinalize(1003) # => "1003rd"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.ordinalize(number)
|
||||
abs_value = number.abs
|
||||
|
||||
if ORDINALIZE_TH.include?(abs_value % 100)
|
||||
"#{number}th"
|
||||
else
|
||||
case abs_value % 10
|
||||
when 1; "#{number}st"
|
||||
when 2; "#{number}nd"
|
||||
when 3; "#{number}rd"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Yields a singleton instance of Inflecto::Inflections
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.inflections do |inflect|
|
||||
# inflect.uncountable "rails"
|
||||
# end
|
||||
#
|
||||
# @return [Inflecto::Inflections]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.inflections
|
||||
instance = Inflections.instance
|
||||
block_given? ? yield(instance) : instance
|
||||
end
|
||||
|
||||
# Convert input word string to plural
|
||||
#
|
||||
# @param [String] word
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.pluralize("post") # => "posts"
|
||||
# Inflecto.pluralize("octopus") # => "octopi"
|
||||
# Inflecto.pluralize("sheep") # => "sheep"
|
||||
# Inflecto.pluralize("words") # => "words"
|
||||
# Inflecto.pluralize("CamelOctopus") # => "CamelOctopi"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.pluralize(word)
|
||||
return word if uncountable?(word)
|
||||
inflections.plurals.apply_to(word)
|
||||
end
|
||||
|
||||
# Convert word to singular
|
||||
#
|
||||
# @param [String] word
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.singularize("posts") # => "post"
|
||||
# Inflecto.singularize("octopi") # => "octopus"
|
||||
# Inflecto.singularize("sheep") # => "sheep"
|
||||
# Inflecto.singularize("word") # => "word"
|
||||
# Inflecto.singularize("CamelOctopi") # => "CamelOctopus"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.singularize(word)
|
||||
return word if uncountable?(word)
|
||||
inflections.singulars.apply_to(word)
|
||||
end
|
||||
|
||||
# Humanize string
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# capitalizes the first word and turns underscores into spaces and strips a # trailing "_id", if any.
|
||||
# Like +titleize+, this is meant for creating pretty output.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.humanize("employee_salary") # => "Employee salary"
|
||||
# Inflecto.humanize("author_id") # => "Author"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.humanize(input)
|
||||
result = inflections.humans.apply_to(input)
|
||||
result.gsub!(/_id\z/, "")
|
||||
result.tr!('_', " ")
|
||||
result.capitalize!
|
||||
result
|
||||
end
|
||||
|
||||
# Tabelize input string
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# Create the name of a table like Rails does for models to table names.
|
||||
# This method # uses the +pluralize+ method on the last word in the string.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.tableize("RawScaledScorer") # => "raw_scaled_scorers"
|
||||
# Inflecto.tableize("egg_and_ham") # => "egg_and_hams"
|
||||
# Inflecto.tableize("fancyCategory") # => "fancy_categories"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.tableize(input)
|
||||
word = input.gsub(/::/, '_')
|
||||
pluralize(underscorize(word))
|
||||
end
|
||||
|
||||
# Classify input
|
||||
#
|
||||
# Create a class name from a plural table name like Rails does for table names to models.
|
||||
# Note that this returns a string and not a Class.
|
||||
#
|
||||
# To convert to an actual class # follow +classify+ with +constantize+.
|
||||
#
|
||||
# @examples:
|
||||
#
|
||||
# Inflecto.classify("egg_and_hams") # => "EggAndHam"
|
||||
# Inflecto.classify("posts") # => "Post"
|
||||
#
|
||||
# # Singular names are not handled correctly:
|
||||
# Inflecto.classify("business") # => "Busines"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.classify(table_name)
|
||||
# strip out any leading schema name
|
||||
camelize(singularize(table_name.sub(/.*\./, '')))
|
||||
end
|
||||
|
||||
# Test if word is uncountable
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.uncountable?('rice') #=> true
|
||||
# Inflecto.uncountable?('apple') #=> false
|
||||
#
|
||||
# @param [String] word
|
||||
#
|
||||
# @return [Boolean]
|
||||
# true, if word is uncountable
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
def self.uncountable?(word)
|
||||
word.empty? || inflections.uncountables.include?(word.downcase)
|
||||
end
|
||||
|
||||
# Convert input to underscored, lowercase string
|
||||
#
|
||||
# Contains main logic for .underscore and .tableize
|
||||
# Does nothing with '::' divider
|
||||
#
|
||||
# @param [String] input
|
||||
#
|
||||
# @example
|
||||
# Inflecto.underscorize("DataMapper") # => "data_mapper"
|
||||
# Inflecto.underscorize("DataMapper::Errors") # => "data_mapper::errors"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def self.underscorize(word)
|
||||
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
||||
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
||||
word.tr!('-', '_')
|
||||
word.downcase!
|
||||
word
|
||||
end
|
||||
private_class_method :underscorize
|
||||
end
|
||||
|
||||
require 'inflecto/rules_collection'
|
||||
require 'inflecto/inflections'
|
||||
require 'inflecto/defaults'
|
|
@ -1,58 +0,0 @@
|
|||
Inflecto.inflections do |inflect|
|
||||
inflect.plural(/\z/, 's')
|
||||
inflect.plural(/s\z/i, 's')
|
||||
inflect.plural(/(ax|test)is\z/i, '\1es')
|
||||
inflect.plural(/(octop|vir)us\z/i, '\1i')
|
||||
inflect.plural(/(octop|vir)i\z/i, '\1i')
|
||||
inflect.plural(/(alias|status)\z/i, '\1es')
|
||||
inflect.plural(/(bu)s\z/i, '\1ses')
|
||||
inflect.plural(/(buffal|tomat)o\z/i, '\1oes')
|
||||
inflect.plural(/([ti])um\z/i, '\1a')
|
||||
inflect.plural(/([ti])a\z/i, '\1a')
|
||||
inflect.plural(/sis\z/i, 'ses')
|
||||
inflect.plural(/(?:([^f])fe|([lr])f)\z/i, '\1\2ves')
|
||||
inflect.plural(/(hive)\z/i, '\1s')
|
||||
inflect.plural(/([^aeiouy]|qu)y\z/i, '\1ies')
|
||||
inflect.plural(/(x|ch|ss|sh)\z/i, '\1es')
|
||||
inflect.plural(/(matr|vert|ind)(?:ix|ex)\z/i, '\1ices')
|
||||
inflect.plural(/([m|l])ouse\z/i, '\1ice')
|
||||
inflect.plural(/([m|l])ice\z/i, '\1ice')
|
||||
inflect.plural(/^(ox)\z/i, '\1en')
|
||||
inflect.plural(/^(oxen)\z/i, '\1')
|
||||
inflect.plural(/(quiz)\z/i, '\1zes')
|
||||
|
||||
inflect.singular(/s\z/i, '')
|
||||
inflect.singular(/(n)ews\z/i, '\1ews')
|
||||
inflect.singular(/([ti])a\z/i, '\1um')
|
||||
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses\z/i, '\1\2sis')
|
||||
inflect.singular(/(^analy)ses\z/i, '\1sis')
|
||||
inflect.singular(/([^f])ves\z/i, '\1fe')
|
||||
inflect.singular(/(hive)s\z/i, '\1')
|
||||
inflect.singular(/(tive)s\z/i, '\1')
|
||||
inflect.singular(/([lr])ves\z/i, '\1f')
|
||||
inflect.singular(/([^aeiouy]|qu)ies\z/i, '\1y')
|
||||
inflect.singular(/(s)eries\z/i, '\1eries')
|
||||
inflect.singular(/(m)ovies\z/i, '\1ovie')
|
||||
inflect.singular(/(x|ch|ss|sh)es\z/i, '\1')
|
||||
inflect.singular(/([m|l])ice\z/i, '\1ouse')
|
||||
inflect.singular(/(bus)es\z/i, '\1')
|
||||
inflect.singular(/(o)es\z/i, '\1')
|
||||
inflect.singular(/(shoe)s\z/i, '\1')
|
||||
inflect.singular(/(cris|ax|test)es\z/i, '\1is')
|
||||
inflect.singular(/(octop|vir)i\z/i, '\1us')
|
||||
inflect.singular(/(alias|status)es\z/i, '\1')
|
||||
inflect.singular(/^(ox)en/i, '\1')
|
||||
inflect.singular(/(vert|ind)ices\z/i, '\1ex')
|
||||
inflect.singular(/(matr)ices\z/i, '\1ix')
|
||||
inflect.singular(/(quiz)zes\z/i, '\1')
|
||||
inflect.singular(/(database)s\z/i, '\1')
|
||||
|
||||
inflect.irregular('person', 'people')
|
||||
inflect.irregular('man', 'men')
|
||||
inflect.irregular('child', 'children')
|
||||
inflect.irregular('sex', 'sexes')
|
||||
inflect.irregular('move', 'moves')
|
||||
inflect.irregular('cow', 'cows')
|
||||
|
||||
inflect.uncountable(%w(hovercraft moose milk rain Swiss grass equipment information rice money species series fish sheep jeans))
|
||||
end
|
|
@ -1,232 +0,0 @@
|
|||
module Inflecto
|
||||
# A singleton instance of this class is yielded by Inflecto.inflections, which can then be used to specify additional
|
||||
# inflection rules. Examples:
|
||||
#
|
||||
# Inflecto.inflections do |inflect|
|
||||
# inflect.plural /^(ox)$/i, '\1\2en'
|
||||
# inflect.singular /^(ox)en/i, '\1'
|
||||
#
|
||||
# inflect.irregular 'octopus', 'octopi'
|
||||
#
|
||||
# inflect.uncountable "equipment"
|
||||
# end
|
||||
#
|
||||
# New rules are added at the top. So in the example above, the irregular rule for octopus will now be the first of the
|
||||
# pluralization and singularization rules that is runs. This guarantees that your rules run before any of the rules that may
|
||||
# already have been loaded.
|
||||
#
|
||||
class Inflections
|
||||
|
||||
# Return instance
|
||||
#
|
||||
# @return [Inflections]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def self.instance
|
||||
@__instance__ ||= new
|
||||
end
|
||||
|
||||
# Return plurals
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
attr_reader :plurals
|
||||
|
||||
# Return singulars
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
attr_reader :singulars
|
||||
|
||||
# Return uncountables
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
attr_reader :uncountables
|
||||
|
||||
# Return humans
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
#
|
||||
attr_reader :humans
|
||||
|
||||
# Initialize object
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def initialize
|
||||
@plurals = RulesCollection.new
|
||||
@singulars = RulesCollection.new
|
||||
@humans = RulesCollection.new
|
||||
@uncountables = Set[]
|
||||
end
|
||||
|
||||
# Add a new plural role
|
||||
#
|
||||
# Specifies a new pluralization rule and its replacement. The rule can either be a string or a regular expression.
|
||||
# The replacement should always be a string that may include references to the matched data from the rule.
|
||||
#
|
||||
# @param [String, Regexp] rule
|
||||
# @param [String, Regexp] replacement
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def plural(rule, replacement)
|
||||
rule(rule, replacement, plurals)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Add a new singular rule
|
||||
#
|
||||
# Specifies a new singularization rule and its replacement. The rule can either be a string or a regular expression.
|
||||
# The replacement should always be a string that may include references to the matched data from the rule.
|
||||
#
|
||||
# @param [String, Regexp] rule
|
||||
# @param [String, Regexp] replacement
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def singular(rule, replacement)
|
||||
rule(rule, replacement, singulars)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Add a new irregular pluralization
|
||||
#
|
||||
# Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
|
||||
# for strings, not regular expressions. You simply pass the irregular in singular and plural form.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.irregular('octopus', 'octopi')
|
||||
# Inflecto.irregular('person', 'people')
|
||||
#
|
||||
# @param [String] singular
|
||||
# @param [String] plural
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def irregular(singular, plural)
|
||||
uncountables.delete(singular)
|
||||
uncountables.delete(plural)
|
||||
|
||||
add_irregular(singular, plural, plurals)
|
||||
add_irregular(plural, singular, singulars)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Add uncountable words
|
||||
#
|
||||
# Uncountable will not be inflected
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.uncountable "money"
|
||||
# Inflecto.uncountable "money", "information"
|
||||
# Inflecto.uncountable %w( money information rice )
|
||||
#
|
||||
# @param [Enumerable<String>] words
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def uncountable(*words)
|
||||
uncountables.merge(words.flatten)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Add humanize rule
|
||||
#
|
||||
# Specifies a humanized form of a string by a regular expression rule or by a string mapping.
|
||||
# When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
|
||||
# When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
|
||||
#
|
||||
# @example
|
||||
# Inflecto.human(/_cnt$/i, '\1_count')
|
||||
# Inflecto.human("legacy_col_person_name", "Name")
|
||||
#
|
||||
# @param [String, Regexp] rule
|
||||
# @param [String, Regexp] replacement
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
def human(rule, replacement)
|
||||
humans.insert(0, [rule, replacement])
|
||||
self
|
||||
end
|
||||
|
||||
# Clear all inflection rules
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# Inflecto.clear
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def clear
|
||||
initialize
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Add irregular inflection
|
||||
#
|
||||
# @param [String] rule
|
||||
# @param [String] replacement
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def add_irregular(rule, replacement, target)
|
||||
head, *tail = rule.chars.to_a
|
||||
rule(/(#{head})#{tail.join}\z/i, '\1' + replacement[1..-1], target)
|
||||
end
|
||||
|
||||
# Add a new rule
|
||||
#
|
||||
# @param [String, Regexp] rule
|
||||
# @param [String, Regexp] replacement
|
||||
# @param [Array] target
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def rule(rule, replacement, target)
|
||||
uncountables.delete(rule)
|
||||
uncountables.delete(replacement)
|
||||
|
||||
target.insert(0, [rule, replacement])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
module Inflecto
|
||||
# Wraps inflections array
|
||||
#
|
||||
class RulesCollection < Array
|
||||
# Applies first found rule to given word
|
||||
#
|
||||
# @param [String] word
|
||||
#
|
||||
# @return [String]
|
||||
# modified word
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def apply_to(word)
|
||||
result = word.dup
|
||||
each { |rule, replacement| break if result.gsub!(rule, replacement) }
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, 'underscore' do
|
||||
specify 'allows to create snake_case from CamelCase' do
|
||||
expect(Inflecto.underscore('CamelCase')).to eql('camel_case')
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
--exclude-only "spec/,^/"
|
||||
--sort coverage
|
||||
--callsites
|
||||
--xrefs
|
||||
--profile
|
||||
--text-summary
|
||||
--failure-threshold 100
|
|
@ -1,41 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'devtools/spec_helper'
|
||||
|
||||
if ENV['COVERAGE'] == 'true'
|
||||
require 'simplecov'
|
||||
|
||||
SimpleCov.start do
|
||||
command_name 'spec:unit'
|
||||
add_filter 'config'
|
||||
add_filter 'spec'
|
||||
minimum_coverage 100
|
||||
end
|
||||
end
|
||||
|
||||
require 'inflecto'
|
||||
|
||||
# require spec support files and shared behavior
|
||||
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each do |file|
|
||||
require file
|
||||
end
|
||||
|
||||
# Mutant is already using inflecto. If it mutates inflecto methods then our
|
||||
# tests start to fail. Instead, we force mutant to use unmutated version of
|
||||
# inflecto.
|
||||
if defined?(Mutant)
|
||||
module Mutant
|
||||
module Inflecto
|
||||
::Inflecto.singleton_methods.each do |name|
|
||||
define_singleton_method name, ::Inflecto.method(name).to_proc
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
# Helps to ensure that inflecto does not modify original input
|
||||
def i(object)
|
||||
object.freeze
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.camelize' do
|
||||
it 'camelizes data_mapper as DataMapper' do
|
||||
Inflecto.camelize(i('data_mapper')).should == 'DataMapper'
|
||||
end
|
||||
|
||||
it 'camelizes merb as Merb' do
|
||||
Inflecto.camelize(i('merb')).should == 'Merb'
|
||||
end
|
||||
|
||||
it 'camelizes data_mapper/resource as DataMapper::Resource' do
|
||||
Inflecto.camelize(i('data_mapper/resource')).should == 'DataMapper::Resource'
|
||||
end
|
||||
|
||||
it 'camelizes data_mapper/associations/one_to_many as DataMapper::Associations::OneToMany' do
|
||||
Inflecto.camelize(i('data_mapper/associations/one_to_many')).should == 'DataMapper::Associations::OneToMany'
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.classify' do
|
||||
it 'classifies data_mapper as DataMapper' do
|
||||
Inflecto.classify(i('data_mapper')).should == 'DataMapper'
|
||||
end
|
||||
|
||||
it 'classifies data.mapper as Mapper' do
|
||||
Inflecto.classify(i('data.mapper')).should == 'Mapper'
|
||||
end
|
||||
|
||||
it 'classifies enlarged_testes as EnlargedTestis' do
|
||||
Inflecto.classify(i('enlarged_testes')).should == 'EnlargedTestis'
|
||||
end
|
||||
|
||||
it 'singularizes string first: classifies data_mappers as egg_and_hams as EggAndHam' do
|
||||
Inflecto.classify(i('egg_and_hams')).should == 'EggAndHam'
|
||||
end
|
||||
end
|
|
@ -1,60 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.constantize' do
|
||||
it 'constantizes Module' do
|
||||
Inflecto.constantize(i('Module')).should == Module
|
||||
end
|
||||
|
||||
it 'constantizes ::Module' do
|
||||
Inflecto.constantize(i('::Module')).should == Module
|
||||
end
|
||||
|
||||
it 'constantizes nested constant Inflecto::Inflections' do
|
||||
Inflecto.constantize(i('Inflecto::Inflections')).should == Inflecto::Inflections
|
||||
end
|
||||
|
||||
it 'does not search ancestors' do
|
||||
module Foo
|
||||
class Bar
|
||||
VAL = 10
|
||||
end
|
||||
|
||||
class Baz < Bar; end
|
||||
end
|
||||
|
||||
expect {
|
||||
Inflecto.constantize(i('Foo::Baz::VAL'))
|
||||
}.to raise_error(NameError)
|
||||
end
|
||||
|
||||
it 'searches in const_missing' do
|
||||
module Foo
|
||||
class Bar
|
||||
def self.const_missing(name)
|
||||
name.to_s == 'Const' ? Baz : super
|
||||
end
|
||||
end
|
||||
|
||||
class Baz < Bar; end
|
||||
|
||||
def self.const_missing(name)
|
||||
name.to_s == 'Autoloaded' ? Bar : super
|
||||
end
|
||||
end
|
||||
|
||||
Inflecto.constantize(i('Foo::Autoloaded::Const')).should == Foo::Baz
|
||||
Inflecto.constantize(i('Foo::Bar::Const')).should == Foo::Baz
|
||||
end
|
||||
|
||||
it 'raises exception when empty string given' do
|
||||
expect {
|
||||
Inflecto.constantize(i(''))
|
||||
}.to raise_error(NameError)
|
||||
end
|
||||
|
||||
it 'raises exception when constant not found' do
|
||||
expect {
|
||||
Inflecto.constantize(i('Qwerty'))
|
||||
}.to raise_error(NameError)
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.dasherize' do
|
||||
it 'dasherizes data_mapper_rspec as data-mapper-rspec' do
|
||||
Inflecto.dasherize(i('data_mapper_rspec')).should == 'data-mapper-rspec'
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.demodulize' do
|
||||
it 'demodulizes module name: DataMapper::Inflecto => Inflecto' do
|
||||
Inflecto.demodulize(i('DataMapper::Inflecto')).should == 'Inflecto'
|
||||
end
|
||||
|
||||
it 'demodulizes module name: A::B::C::D::E => E' do
|
||||
Inflecto.demodulize(i('A::B::C::D::E')).should == 'E'
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.foreign_key' do
|
||||
it 'adds _id to downcased string: Message => message_id' do
|
||||
Inflecto.foreign_key(i('Message')).should == 'message_id'
|
||||
end
|
||||
|
||||
it 'demodulizes string first: Admin::Post => post_id' do
|
||||
Inflecto.foreign_key(i('Admin::Post')).should == 'post_id'
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.humanize' do
|
||||
it 'replaces _ with space: humanizes employee_salary as Employee salary' do
|
||||
Inflecto.humanize(i('employee_salary')).should == 'Employee salary'
|
||||
end
|
||||
|
||||
it 'strips _id endings: humanizes author_id as Author' do
|
||||
Inflecto.humanize(i('author_id')).should == 'Author'
|
||||
end
|
||||
|
||||
it 'uses user added rules when possible' do
|
||||
Inflecto.inflections do |inflect|
|
||||
inflect.human('Question', 'Fancy question')
|
||||
inflect.human('questionary', 'Questionnaire')
|
||||
end
|
||||
|
||||
Inflecto.humanize(i('questionary')).should == 'Questionnaire'
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.inflections' do
|
||||
context 'when block given' do
|
||||
it 'yields inflections instance' do
|
||||
yielded = nil
|
||||
|
||||
described_class.inflections do |inflect|
|
||||
yielded = inflect
|
||||
end
|
||||
|
||||
yielded.should be(Inflecto::Inflections.instance)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when without block' do
|
||||
subject { described_class.inflections }
|
||||
|
||||
it { should be(Inflecto::Inflections.instance) }
|
||||
end
|
||||
end
|
|
@ -1,51 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.ordinalize' do
|
||||
context 'when number ends with digit 1' do
|
||||
it 'adds -th suffix when number ends with 11' do
|
||||
[-1011, -111, -11, 11, 111, 1011].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}th")
|
||||
end
|
||||
end
|
||||
|
||||
it 'adds -st suffix when number does not end with 11' do
|
||||
[-1001, -101, -21, -1, 1, 21, 101, 1001].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}st")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when number ends with digit 2' do
|
||||
it 'adds -th suffix when number ends with 12' do
|
||||
[-1012, -112, -12, 12, 112, 1012].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}th")
|
||||
end
|
||||
end
|
||||
|
||||
it 'adds -nd suffix when number does not end with 12' do
|
||||
[-1002, -102, -22, -2, 2, 22, 102, 1002].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}nd")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when number ends with digit 3' do
|
||||
it 'adds -th suffix when number ends with 13' do
|
||||
[-1013, -113, -13, 13, 113, 1013].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}th")
|
||||
end
|
||||
end
|
||||
|
||||
it 'adds -rd suffix when number does not end with 13' do
|
||||
[-1003, -103, -23, -3, 3, 23, 103, 1003].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}rd")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'ordinalizes other numbers with -th suffix' do
|
||||
[-4, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16].each do |number|
|
||||
Inflecto.ordinalize(number).should eq("#{number}th")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,193 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.pluralize' do
|
||||
|
||||
SINGULAR_TO_PLURAL = {
|
||||
'equipment' => 'equipment',
|
||||
'information' => 'information',
|
||||
'money' => 'money',
|
||||
'species' => 'species',
|
||||
'series' => 'series',
|
||||
'fish' => 'fish',
|
||||
'sheep' => 'sheep',
|
||||
'news' => 'news',
|
||||
'matrix' => 'matrices',
|
||||
'life' => 'lives',
|
||||
'wife' => 'wives',
|
||||
'alias' => 'aliases',
|
||||
'status' => 'statuses',
|
||||
'axis' => 'axes',
|
||||
'crisis' => 'crises',
|
||||
'testis' => 'testes',
|
||||
'child' => 'children',
|
||||
'person' => 'people',
|
||||
'tomato' => 'tomatoes',
|
||||
'buffalo' => 'buffaloes',
|
||||
'quiz' => 'quizzes',
|
||||
'vertex' => 'vertices',
|
||||
'index' => 'indices',
|
||||
'ox' => 'oxen',
|
||||
'mouse' => 'mice',
|
||||
'louse' => 'lice',
|
||||
'thesis' => 'theses',
|
||||
'analysis' => 'analyses',
|
||||
'octopus' => 'octopi',
|
||||
'grass' => 'grass',
|
||||
'drive' => 'drives',
|
||||
# ==== bugs, typos and reported issues
|
||||
|
||||
# ==== rules and most common cases
|
||||
|
||||
'forum' => 'forums',
|
||||
'hive' => 'hives',
|
||||
'athlete' => 'athletes',
|
||||
'dwarf' => 'dwarves',
|
||||
'man' => 'men',
|
||||
'woman' => 'women',
|
||||
'sportsman' => 'sportsmen',
|
||||
'branch' => 'branches',
|
||||
'crunch' => 'crunches',
|
||||
'trash' => 'trashes',
|
||||
'mash' => 'mashes',
|
||||
'cross' => 'crosses',
|
||||
'erratum' => 'errata',
|
||||
# FIXME: add -ia => -ium cases
|
||||
# FIXME: add -ra => -rum cases
|
||||
'ray' => 'rays',
|
||||
'spray' => 'sprays',
|
||||
# Merriam-Webster dictionary says
|
||||
# preys is correct, too.
|
||||
'prey' => 'preys',
|
||||
'toy' => 'toys',
|
||||
'joy' => 'joys',
|
||||
'buy' => 'buys',
|
||||
'guy' => 'guys',
|
||||
'cry' => 'cries',
|
||||
'fly' => 'flies',
|
||||
'fox' => 'foxes',
|
||||
'elf' => 'elves',
|
||||
'shelf' => 'shelves',
|
||||
'cat' => 'cats',
|
||||
'rat' => 'rats',
|
||||
'rose' => 'roses',
|
||||
'project' => 'projects',
|
||||
'post' => 'posts',
|
||||
'article' => 'articles',
|
||||
'location' => 'locations',
|
||||
'friend' => 'friends',
|
||||
'link' => 'links',
|
||||
'url' => 'urls',
|
||||
'account' => 'accounts',
|
||||
'server' => 'servers',
|
||||
'fruit' => 'fruits',
|
||||
'map' => 'maps',
|
||||
'income' => 'incomes',
|
||||
'ping' => 'pings',
|
||||
'event' => 'events',
|
||||
'proof' => 'proofs',
|
||||
'typo' => 'typos',
|
||||
'attachment' => 'attachments',
|
||||
'download' => 'downloads',
|
||||
'asset' => 'assets',
|
||||
'job' => 'jobs',
|
||||
'city' => 'cities',
|
||||
'package' => 'packages',
|
||||
'commit' => 'commits',
|
||||
'version' => 'versions',
|
||||
'document' => 'documents',
|
||||
'edition' => 'editions',
|
||||
'movie' => 'movies',
|
||||
'song' => 'songs',
|
||||
'invoice' => 'invoices',
|
||||
'product' => 'products',
|
||||
'book' => 'books',
|
||||
'ticket' => 'tickets',
|
||||
'game' => 'games',
|
||||
'tournament' => 'tournaments',
|
||||
'prize' => 'prizes',
|
||||
'price' => 'prices',
|
||||
'installation' => 'installations',
|
||||
'date' => 'dates',
|
||||
'schedule' => 'schedules',
|
||||
'arena' => 'arenas',
|
||||
'spam' => 'spams',
|
||||
'bus' => 'buses',
|
||||
'rice' => 'rice',
|
||||
|
||||
# Some specs from Rails
|
||||
'search' => 'searches',
|
||||
'switch' => 'switches',
|
||||
'fix' => 'fixes',
|
||||
'box' => 'boxes',
|
||||
'process' => 'processes',
|
||||
'address' => 'addresses',
|
||||
'case' => 'cases',
|
||||
'stack' => 'stacks',
|
||||
'wish' => 'wishes',
|
||||
'category' => 'categories',
|
||||
'query' => 'queries',
|
||||
'ability' => 'abilities',
|
||||
'agency' => 'agencies',
|
||||
'archive' => 'archives',
|
||||
'safe' => 'saves',
|
||||
'half' => 'halves',
|
||||
'move' => 'moves',
|
||||
'salesperson' => 'salespeople',
|
||||
'spokesman' => 'spokesmen',
|
||||
'basis' => 'bases',
|
||||
'diagnosis' => 'diagnoses',
|
||||
'diagnosis_a' => 'diagnosis_as',
|
||||
'datum' => 'data',
|
||||
'medium' => 'media',
|
||||
'node_child' => 'node_children',
|
||||
'experience' => 'experiences',
|
||||
'day' => 'days',
|
||||
'comment' => 'comments',
|
||||
'foobar' => 'foobars',
|
||||
'newsletter' => 'newsletters',
|
||||
'old_news' => 'old_news',
|
||||
'perspective' => 'perspectives',
|
||||
'photo' => 'photos',
|
||||
'status_code' => 'status_codes',
|
||||
'house' => 'houses',
|
||||
'portfolio' => 'portfolios',
|
||||
'matrix_fu' => 'matrix_fus',
|
||||
'axis' => 'axes',
|
||||
'shoe' => 'shoes',
|
||||
'horse' => 'horses',
|
||||
'edge' => 'edges',
|
||||
'cow' => 'cows',
|
||||
}
|
||||
|
||||
# Missing rule or exception?
|
||||
PENDING = {
|
||||
'virus' => 'viruses',
|
||||
'torpedo' => 'torpedoes',
|
||||
'Swiss' => 'Swiss',
|
||||
'goose' => 'geese',
|
||||
'milk' => 'milk',
|
||||
'plus' => 'plusses',
|
||||
'thesaurus' => 'thesauri',
|
||||
'thief' => 'thieves',
|
||||
'hovercraft' => 'hovercraft',
|
||||
'zero' => 'zeroes',
|
||||
'rain' => 'rain',
|
||||
'cactus' => 'cacti',
|
||||
'moose' => 'moose',
|
||||
'criterion' => 'criteria',
|
||||
'potato' => 'potatoes',
|
||||
'phenomenon' => 'phenomena',
|
||||
'hero' => 'heroes',
|
||||
}
|
||||
|
||||
PENDING.each do |singular, plural|
|
||||
pending "missing exception or rule for #{singular} => #{plural}"
|
||||
end
|
||||
|
||||
SINGULAR_TO_PLURAL.each do |singular, plural|
|
||||
it "pluralizes #{singular} => #{plural}" do
|
||||
Inflecto.pluralize(i(singular)).should eql(plural)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,153 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.singularize' do
|
||||
# ==== exceptional cases
|
||||
|
||||
PLURAL_TO_SINGULAR = {
|
||||
'equipment' => 'equipment',
|
||||
'mysql' => 'mysql',
|
||||
'information' => 'information',
|
||||
'money' => 'money',
|
||||
'species' => 'species',
|
||||
'series' => 'series',
|
||||
'fish' => 'fish',
|
||||
'sheep' => 'sheep',
|
||||
'news' => 'news',
|
||||
'rain' => 'rain',
|
||||
'milk' => 'milk',
|
||||
'moose' => 'moose',
|
||||
'hovercraft' => 'hovercraft',
|
||||
'matrices' => 'matrix',
|
||||
'lives' => 'life',
|
||||
'wives' => 'wife',
|
||||
'aliases' => 'alias',
|
||||
'statuses' => 'status',
|
||||
'axes' => 'axis',
|
||||
'crises' => 'crisis',
|
||||
'testes' => 'testis',
|
||||
'children' => 'child',
|
||||
'people' => 'person',
|
||||
'potatoes' => 'potato',
|
||||
'tomatoes' => 'tomato',
|
||||
'buffaloes' => 'buffalo',
|
||||
'torpedoes' => 'torpedo',
|
||||
'quizzes' => 'quiz',
|
||||
'vertices' => 'vertex',
|
||||
'indices' => 'index',
|
||||
'indexes' => 'index',
|
||||
'oxen' => 'ox',
|
||||
'mice' => 'mouse',
|
||||
'lice' => 'louse',
|
||||
'theses' => 'thesis',
|
||||
'analyses' => 'analysis',
|
||||
'octopi' => 'octopus',
|
||||
'grass' => 'grass',
|
||||
# ==== bugs, typos and reported issues
|
||||
|
||||
# ==== rules
|
||||
|
||||
'forums' => 'forum',
|
||||
'hives' => 'hive',
|
||||
'athletes' => 'athlete',
|
||||
'dwarves' => 'dwarf',
|
||||
'heroes' => 'hero',
|
||||
'zeroes' => 'zero',
|
||||
'men' => 'man',
|
||||
'women' => 'woman',
|
||||
'sportsmen' => 'sportsman',
|
||||
'branches' => 'branch',
|
||||
'crunches' => 'crunch',
|
||||
'trashes' => 'trash',
|
||||
'mashes' => 'mash',
|
||||
'crosses' => 'cross',
|
||||
'errata' => 'erratum',
|
||||
# FIXME: add -ia => -ium cases
|
||||
|
||||
# FIXME: add -ra => -rum cases
|
||||
|
||||
'rays' => 'ray',
|
||||
'sprays' => 'spray',
|
||||
# Merriam-Webster dictionary says
|
||||
# preys is correct, too.
|
||||
'preys' => 'prey',
|
||||
'toys' => 'toy',
|
||||
'joys' => 'joy',
|
||||
'buys' => 'buy',
|
||||
'guys' => 'guy',
|
||||
'cries' => 'cry',
|
||||
'flies' => 'fly',
|
||||
'foxes' => 'fox',
|
||||
'elves' => 'elf',
|
||||
'shelves' => 'shelf',
|
||||
'cats' => 'cat',
|
||||
'rats' => 'rat',
|
||||
'roses' => 'rose',
|
||||
'projects' => 'project',
|
||||
'posts' => 'post',
|
||||
'articles' => 'article',
|
||||
'locations' => 'location',
|
||||
'friends' => 'friend',
|
||||
'links' => 'link',
|
||||
'urls' => 'url',
|
||||
'accounts' => 'account',
|
||||
'servers' => 'server',
|
||||
'fruits' => 'fruit',
|
||||
'maps' => 'map',
|
||||
'incomes' => 'income',
|
||||
'pings' => 'ping',
|
||||
'events' => 'event',
|
||||
'proofs' => 'proof',
|
||||
'typos' => 'typo',
|
||||
'attachments' => 'attachment',
|
||||
'downloads' => 'download',
|
||||
'assets' => 'asset',
|
||||
'jobs' => 'job',
|
||||
'cities' => 'city',
|
||||
'packages' => 'package',
|
||||
'commits' => 'commit',
|
||||
'versions' => 'version',
|
||||
'documents' => 'document',
|
||||
'editions' => 'edition',
|
||||
'movies' => 'movie',
|
||||
'songs' => 'song',
|
||||
'invoices' => 'invoice',
|
||||
'products' => 'product',
|
||||
'books' => 'book',
|
||||
'tickets' => 'ticket',
|
||||
'games' => 'game',
|
||||
'tournaments' => 'tournament',
|
||||
'prizes' => 'prize',
|
||||
'prices' => 'price',
|
||||
'installations' => 'installation',
|
||||
'dates' => 'date',
|
||||
'schedules' => 'schedule',
|
||||
'arenas' => 'arena',
|
||||
'spams' => 'spam',
|
||||
'rice' => 'rice'
|
||||
}
|
||||
|
||||
# Missing exceptions or missing rules?
|
||||
PENDING = {
|
||||
'cacti' => 'cactus',
|
||||
'cactuses' => 'cactus',
|
||||
'thesauri' => 'thesaurus',
|
||||
'geese' => 'goose',
|
||||
'phenomena' => 'phenomenon',
|
||||
'Swiss' => 'Swiss',
|
||||
'drives' => 'drive',
|
||||
'pluses' => 'plus',
|
||||
'thieves' => 'thief',
|
||||
'criteria' => 'criterion',
|
||||
'postgres' => 'postgres'
|
||||
}
|
||||
|
||||
PENDING.each do |plural, singular|
|
||||
pending "missing rule or exception for #{plural} => #{singular}"
|
||||
end
|
||||
|
||||
PLURAL_TO_SINGULAR.each do |plural, singular|
|
||||
it "should signularize #{plural} => #{singular}" do
|
||||
Inflecto.singularize(i(plural)).should eql(singular)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.tableize' do
|
||||
it 'pluralizes last word in snake_case strings: fancy_category => fancy_categories' do
|
||||
Inflecto.tableize(i('fancy_category')).should == 'fancy_categories'
|
||||
end
|
||||
|
||||
it 'underscores CamelCase strings before pluralization: enlarged_testis => enlarged_testes' do
|
||||
Inflecto.tableize(i('enlarged_testis')).should == 'enlarged_testes'
|
||||
end
|
||||
|
||||
it 'underscores CamelCase strings before pluralization: FancyCategory => fancy_categories' do
|
||||
Inflecto.tableize(i('FancyCategory')).should == 'fancy_categories'
|
||||
end
|
||||
|
||||
it 'underscores CamelCase strings before pluralization: EnlargedTestis => enlarged_testes' do
|
||||
Inflecto.tableize(i('EnlargedTestis')).should == 'enlarged_testes'
|
||||
end
|
||||
|
||||
it 'replaces :: with underscores: My::Fancy::Category => my_fancy_categories' do
|
||||
Inflecto.tableize(i('My::Fancy::Category')).should == 'my_fancy_categories'
|
||||
end
|
||||
|
||||
it 'underscores CamelCase strings before pluralization: Enlarged::Testis => enlarged_testes' do
|
||||
Inflecto.tableize(i('Enlarged::Testis')).should == 'enlarged_testes'
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.uncountable?' do
|
||||
it 'truthy when empty string' do
|
||||
Inflecto.uncountable?('').should be(true)
|
||||
end
|
||||
|
||||
it 'truthy when word is present in list' do
|
||||
Inflecto.uncountable?('grass').should be(true)
|
||||
end
|
||||
|
||||
it 'falsy when word is not present in list' do
|
||||
Inflecto.uncountable?('user').should be(false)
|
||||
end
|
||||
|
||||
it 'truthy when word is present in list but in different case' do
|
||||
Inflecto.uncountable?('FiSH').should be(true)
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto, '.underscore' do
|
||||
it 'underscores DataMapper as data_mapper' do
|
||||
Inflecto.underscore(i('DataMapper')).should == 'data_mapper'
|
||||
end
|
||||
|
||||
it 'underscores Merb as merb' do
|
||||
Inflecto.underscore(i('Merb')).should == 'merb'
|
||||
end
|
||||
|
||||
it 'underscores DataMapper::Resource as data_mapper/resource' do
|
||||
Inflecto.underscore(i('DataMapper::Resource')).should == 'data_mapper/resource'
|
||||
end
|
||||
|
||||
it 'underscores Merb::BootLoader::Rackup as merb/boot_loader/rackup' do
|
||||
Inflecto.underscore(i('Merb::BootLoader::Rackup')).should == 'merb/boot_loader/rackup'
|
||||
end
|
||||
|
||||
it 'underscores data-mapper as data_mapper' do
|
||||
Inflecto.underscore(i('data-mapper')).should == 'data_mapper'
|
||||
end
|
||||
|
||||
it 'underscores CLI as cli' do
|
||||
Inflecto.underscore(i('CLI')).should == 'cli'
|
||||
end
|
||||
|
||||
it 'underscores castleKing as castle_king' do
|
||||
Inflecto.underscore(i('castleKing')).should == 'castle_king'
|
||||
end
|
||||
|
||||
it 'underscores CLIRunner as cli_runner' do
|
||||
Inflecto.underscore(i('CLIRunner')).should == 'cli_runner'
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '.instance' do
|
||||
subject { described_class.instance }
|
||||
|
||||
it { should be_instance_of(described_class) }
|
||||
|
||||
it 'returns always same instance' do
|
||||
subject.should equal(described_class.instance)
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '#clear' do
|
||||
subject { object.clear }
|
||||
|
||||
let(:object) { described_class.new }
|
||||
|
||||
before do
|
||||
object.uncountable('apple')
|
||||
object.plural('people', 'person')
|
||||
object.singular('apple', 'apples')
|
||||
object.human('person_name', 'Name')
|
||||
end
|
||||
|
||||
it { should be(object) }
|
||||
|
||||
its(:plurals) { should be_empty }
|
||||
its(:singulars) { should be_empty }
|
||||
its(:uncountables) { should be_empty }
|
||||
its(:humans) { should be_empty }
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '#human' do
|
||||
subject { object.human(rule, replacement) }
|
||||
|
||||
let(:object) { described_class.new }
|
||||
let(:rule) { double(:rule) }
|
||||
let(:replacement) { double(:replacement) }
|
||||
|
||||
it { should be(object) }
|
||||
|
||||
its(:humans) { should eq([[rule, replacement]]) }
|
||||
|
||||
it 'adds rule as a first item' do
|
||||
subject
|
||||
object.human(double, double)
|
||||
|
||||
humans = object.humans
|
||||
humans.size.should be(2)
|
||||
humans.last.should eq([rule, replacement])
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '#irregular' do
|
||||
subject { object.irregular(singular, plural) }
|
||||
|
||||
let(:object) { described_class.new }
|
||||
let(:singular) { 'person' }
|
||||
let(:plural) { 'people' }
|
||||
|
||||
it { should be(object) }
|
||||
|
||||
its(:plurals) { should include([/(p)erson\z/i, "\\1eople"]) }
|
||||
its(:singulars) { should include([/(p)eople\z/i, "\\1erson"]) }
|
||||
|
||||
context 'when singular form is in uncountables' do
|
||||
before { object.uncountable('person') }
|
||||
|
||||
it 'removes it from uncountables' do
|
||||
subject.uncountables.should_not include('person')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when plural form is in uncountables' do
|
||||
before { object.uncountable('people') }
|
||||
|
||||
it 'removes it from uncountables' do
|
||||
subject.uncountables.should_not include('people')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,38 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '#plural' do
|
||||
subject { object.plural(rule, replacement) }
|
||||
|
||||
let(:object) { described_class.new }
|
||||
let(:rule) { double(:rule) }
|
||||
let(:replacement) { double(:replacement) }
|
||||
|
||||
it { should be(object) }
|
||||
|
||||
its(:plurals) { should eq([[rule, replacement]]) }
|
||||
|
||||
it 'adds rule as a first item' do
|
||||
subject
|
||||
object.plural(double, double)
|
||||
|
||||
plurals = object.plurals
|
||||
plurals.size.should be(2)
|
||||
plurals.last.should eq([rule, replacement])
|
||||
end
|
||||
|
||||
context 'when rule is in the uncountables' do
|
||||
before { object.uncountable(rule) }
|
||||
|
||||
it 'removes it from uncountables' do
|
||||
subject.uncountables.should eql(Set[])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when replacement is in the uncountables' do
|
||||
before { object.uncountable(replacement) }
|
||||
|
||||
it 'removes it from uncountables' do
|
||||
subject.uncountables.should eql(Set[])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,38 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '#singular' do
|
||||
subject { object.singular(rule, replacement) }
|
||||
|
||||
let(:object) { described_class.new }
|
||||
let(:rule) { double(:rule) }
|
||||
let(:replacement) { double(:replacement) }
|
||||
|
||||
it { should be(object) }
|
||||
|
||||
its(:singulars) { should eq([[rule, replacement]]) }
|
||||
|
||||
it 'adds rule as a first item' do
|
||||
subject
|
||||
object.singular(double, double)
|
||||
|
||||
singulars = object.singulars
|
||||
singulars.size.should be(2)
|
||||
singulars.last.should eq([rule, replacement])
|
||||
end
|
||||
|
||||
context 'when rule is in the uncountables' do
|
||||
before { object.uncountable(rule) }
|
||||
|
||||
it 'removes it from uncountables' do
|
||||
subject.uncountables.should eql(Set[])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when replacement is in the uncountables' do
|
||||
before { object.uncountable(replacement) }
|
||||
|
||||
it 'removes it from uncountables' do
|
||||
subject.uncountables.should eql(Set[])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::Inflections, '#uncountable' do
|
||||
let(:object) { described_class.new }
|
||||
|
||||
context 'when word given' do
|
||||
subject { object.uncountable('water') }
|
||||
its(:uncountables) { should eql(Set['water']) }
|
||||
end
|
||||
|
||||
context 'when array of words given' do
|
||||
subject { object.uncountable(['water', 'sugar']) }
|
||||
its(:uncountables) { should eql(Set['water', 'sugar']) }
|
||||
end
|
||||
|
||||
context 'when multiple words given' do
|
||||
subject { object.uncountable('water', 'sugar') }
|
||||
its(:uncountables) { should eql(Set['water', 'sugar']) }
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Inflecto::RulesCollection, '#apply_to' do
|
||||
subject { described_class.new(rules).apply_to(input) }
|
||||
|
||||
let(:rules) do
|
||||
[
|
||||
['question', 'questions'],
|
||||
['quest', 'quests']
|
||||
]
|
||||
end
|
||||
let(:input) { 'question' }
|
||||
|
||||
it { should eq('questions') }
|
||||
|
||||
it { should_not equal(input) }
|
||||
end
|
Loading…
Reference in New Issue