dry-inflector 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +16 -0
- data/LICENSE.md +22 -0
- data/README.md +109 -0
- data/dry-inflector.gemspec +32 -0
- data/lib/dry/inflector.rb +292 -0
- data/lib/dry/inflector/inflections.rb +217 -0
- data/lib/dry/inflector/inflections/defaults.rb +110 -0
- data/lib/dry/inflector/rules.rb +37 -0
- data/lib/dry/inflector/version.rb +8 -0
- metadata +114 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: c6a797f23150eb58f07e63794a61f5e2e904b6b51e7029678e2a6fd01e7413d2
         | 
| 4 | 
            +
              data.tar.gz: 338a9cf61f97e6afe9d298e70017575b89cea25dfeca4159dc97763f51efaecb
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 50f87e79a468bd3001605e7aa9598d4f0b519e88f3fa0b0b9567e88dc2ca583f7dfe56e1dfe59caf8bc77e00cb6e5f73703e2d6fc5742dd7512bbb9fdd578d12
         | 
| 7 | 
            +
              data.tar.gz: b3de9ce00c62bbe31aaeef50bd54b2fe30f0a7a37e5850ac4e44a0c6b57333d6528828735289336a4cb658c685f7a9c81e2ef1b429b2a3455bad857330894130
         | 
    
        data/CHANGELOG.md
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            # Dry::Inflector
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Inflector for Ruby
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## v0.1.0 (unreleased)
         | 
| 6 | 
            +
            ### Added
         | 
| 7 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#pluralize`
         | 
| 8 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#singularize`
         | 
| 9 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#camelize`
         | 
| 10 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#classify`
         | 
| 11 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#tableize`
         | 
| 12 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#dasherize`
         | 
| 13 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#underscore`
         | 
| 14 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#demodulize`
         | 
| 15 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#humanize`
         | 
| 16 | 
            +
            - [Luca Guidi] Introduced `Dry::Inflector#ordinalize`
         | 
    
        data/LICENSE.md
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            Copyright © The Dry, Rails, Merb, Datamapper, Inflecto, Flexus, and Hanami teams
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            MIT License
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 6 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 7 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 8 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 9 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 10 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 11 | 
            +
            the following conditions:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 14 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 17 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 18 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 19 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 20 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 21 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 22 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            [gitter]: https://gitter.im/dry-rb/chat
         | 
| 2 | 
            +
            [gem]: https://img.shields.io/gem/v/dry-inflector.svg]
         | 
| 3 | 
            +
            [travis]: https://travis-ci.org/dry-rb/dry-inflector
         | 
| 4 | 
            +
            [gemnasium]: https://gemnasium.com/dry-rb/dry-inflector
         | 
| 5 | 
            +
            [codeclimate]: https://codeclimate.com/github/dry-rb/dry-inflector
         | 
| 6 | 
            +
            [coveralls]: https://coveralls.io/r/dry-rb/dry-inflector
         | 
| 7 | 
            +
            [inchpages]: http://inch-ci.org/github/dry-rb/dry-inflector
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # dry-inflector [](https://gitter.im/dry-rb/chat)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            [][gem]
         | 
| 12 | 
            +
            [][travis]
         | 
| 13 | 
            +
            [][gemnasium]
         | 
| 14 | 
            +
            [][codeclimate]
         | 
| 15 | 
            +
            [][codeclimate]
         | 
| 16 | 
            +
            [][inchpages]
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            dry-inflector is an inflector gem for Ruby.
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## Installation
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            Add this line to your application's `Gemfile`:
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ```ruby
         | 
| 25 | 
            +
            gem 'dry-inflector'
         | 
| 26 | 
            +
            ```
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            And then execute:
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            ```shell
         | 
| 31 | 
            +
            $ bundle
         | 
| 32 | 
            +
            ```
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Or install it yourself as:
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            ```shell
         | 
| 37 | 
            +
            $ gem install dry-inflector
         | 
| 38 | 
            +
            ```
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            ## Usage
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            ### Basic usage
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            ```ruby
         | 
| 45 | 
            +
            require "dry/inflector"
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            inflector = Dry::Inflector.new
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            inflector.pluralize("book")    # => "books"
         | 
| 50 | 
            +
            inflector.singularize("books") # => "book"
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            inflector.camelize("dry/inflector") # => "Dry::Inflector"
         | 
| 53 | 
            +
            inflector.classify("books")         # => "Book"
         | 
| 54 | 
            +
            inflector.tableize("Book")          # => "books"
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            inflector.dasherize("dry_inflector")  # => "dry-inflector"
         | 
| 57 | 
            +
            inflector.underscore("dry-inflector") # => "dry_inflector"
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            inflector.demodulize("Dry::Inflector") # => "Inflector"
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            inflector.humanize("dry_inflector")    # => "Dry inflector"
         | 
| 62 | 
            +
            inflector.humanize("author_id")        # => "Author"
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            inflector.ordinalize(1)  # => "1st"
         | 
| 65 | 
            +
            inflector.ordinalize(2)  # => "2nd"
         | 
| 66 | 
            +
            inflector.ordinalize(3)  # => "3rd"
         | 
| 67 | 
            +
            inflector.ordinalize(10) # => "10th"
         | 
| 68 | 
            +
            inflector.ordinalize(23) # => "23rd"
         | 
| 69 | 
            +
            ```
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            ### Custom inflection rules
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            ```ruby
         | 
| 74 | 
            +
            require "dry/inflector"
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            inflector = Dry::Inflector.new do |inflections|
         | 
| 77 | 
            +
              inflections.plural      "virus",   "viruses" # specify a rule for #pluralize
         | 
| 78 | 
            +
              inflections.singular    "thieves", "thief"   # specify a rule for #singularize
         | 
| 79 | 
            +
              inflections.uncountable "dry-inflector"      # add an exception for an uncountable word
         | 
| 80 | 
            +
            end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            inflector.pluralize("virus")     # => "viruses"
         | 
| 83 | 
            +
            inflector.singularize("thieves") # => "thief"
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            inflector.pluralize("dry-inflector") # => "dry-inflector"
         | 
| 86 | 
            +
            ```
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            ## Credits
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            This gem is the cumulative effort of the Ruby community.
         | 
| 91 | 
            +
            It started with the extlib inflecto originated from [active_support](https://github.com/rails/rails), then dm-core inflector originated from [extlib](https://github.com/datamapper/extlib).
         | 
| 92 | 
            +
            Later, [`inflecto`](https://github.com/mbj/inflecto) was extracted from [dm-core](https://github.com/datamapper/dm-core) as a standalone inflector.
         | 
| 93 | 
            +
            Now, we resurrect `inflecto` and merged [`flexus`](https://github.com/Ptico/flexus), with some inflection rules from [`hanami-utils`](https://github.com/hanami/utils).
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            This is `dry-inflector`.
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            ## Development
         | 
| 98 | 
            +
             | 
| 99 | 
            +
            After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            ## Contributing
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/dry-rb/dry-inflector.
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            ## Copyright
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            Copyright © The Dry, Rails, Merb, Datamapper, Inflecto, Flexus, and Hanami teams - Released under the MIT License
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            lib = File.expand_path("../lib", __FILE__)
         | 
| 5 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 6 | 
            +
            require "dry/inflector/version"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Gem::Specification.new do |spec|
         | 
| 9 | 
            +
              spec.name          = "dry-inflector"
         | 
| 10 | 
            +
              spec.version       = Dry::Inflector::VERSION
         | 
| 11 | 
            +
              spec.authors       = ["Luca Guidi", "Andrii Savchenko", "Abinoam P. Marques Jr."]
         | 
| 12 | 
            +
              spec.email         = ["me@lucaguidi.com", "andrey@aejis.eu", "abinoam@gmail.com"]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              spec.summary       = "DRY Inflector"
         | 
| 15 | 
            +
              spec.description   = "String inflections for dry-rb"
         | 
| 16 | 
            +
              spec.homepage      = "http://dry-rb.org"
         | 
| 17 | 
            +
              spec.license       = "MIT"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              spec.metadata["allowed_push_host"] = "https://rubygems.org"
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              spec.bindir        = "exe"
         | 
| 22 | 
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 23 | 
            +
              spec.require_paths = ["lib"]
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              spec.files         = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md dry-inflector.gemspec`.split($INPUT_RECORD_SEPARATOR)
         | 
| 26 | 
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              spec.add_development_dependency "bundler", "~> 1.15"
         | 
| 29 | 
            +
              spec.add_development_dependency "rake",    "~> 12.0"
         | 
| 30 | 
            +
              spec.add_development_dependency "rspec",   "~> 3.6"
         | 
| 31 | 
            +
              spec.add_development_dependency "rubocop", "~> 0.50.0"
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,292 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "set"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Dry
         | 
| 6 | 
            +
              # dry-inflector
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # @since 0.1.0
         | 
| 9 | 
            +
              class Inflector
         | 
| 10 | 
            +
                require "dry/inflector/version"
         | 
| 11 | 
            +
                require "dry/inflector/inflections"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                # Instantiate the inflector
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # @param blk [Proc] an optional block to specify custom inflection rules
         | 
| 16 | 
            +
                # @yieldparam [Dry::Inflector::Inflections] the inflection rules
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # @return [Dry::Inflector] the inflector
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                # @since 0.1.0
         | 
| 21 | 
            +
                #
         | 
| 22 | 
            +
                # @example Basic usage
         | 
| 23 | 
            +
                #   require "dry/inflector"
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 26 | 
            +
                #
         | 
| 27 | 
            +
                # @example Custom inflection rules
         | 
| 28 | 
            +
                #   require "dry/inflector"
         | 
| 29 | 
            +
                #
         | 
| 30 | 
            +
                #   inflector = Dry::Inflector.new do |inflections|
         | 
| 31 | 
            +
                #     inflections.plural      "virus",   "viruses" # specify a rule for #pluralize
         | 
| 32 | 
            +
                #     inflections.singular    "thieves", "thief"   # specify a rule for #singularize
         | 
| 33 | 
            +
                #     inflections.uncountable "dry-inflector"      # add an exception for an uncountable word
         | 
| 34 | 
            +
                #   end
         | 
| 35 | 
            +
                def initialize(&blk)
         | 
| 36 | 
            +
                  @inflections = Inflections.build(&blk)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # Camelize a string
         | 
| 40 | 
            +
                #
         | 
| 41 | 
            +
                # @param input [String,Symbol] the input
         | 
| 42 | 
            +
                # @return [String] the camelized string
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                # @since 0.1.0
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                # @example
         | 
| 47 | 
            +
                #   require "dry/inflector"
         | 
| 48 | 
            +
                #
         | 
| 49 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 50 | 
            +
                #   inflector.camelize("dry/inflector") # => "Dry::Inflector"
         | 
| 51 | 
            +
                def camelize(input)
         | 
| 52 | 
            +
                  input.to_s.gsub(/\/(.?)/) { "::#{Regexp.last_match(1).upcase}" }.gsub(/(?:\A|_)(.)/) { Regexp.last_match(1).upcase }
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                # Find a constant with the name specified in the argument string
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                # The name is assumed to be the one of a top-level constant,
         | 
| 58 | 
            +
                # constant scope of caller is ignored
         | 
| 59 | 
            +
                #
         | 
| 60 | 
            +
                # @param input [String,Symbol] the input
         | 
| 61 | 
            +
                # @return [Class, Module] the class or module
         | 
| 62 | 
            +
                #
         | 
| 63 | 
            +
                # @since 0.1.0
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                # @example
         | 
| 66 | 
            +
                #   require "dry/inflector"
         | 
| 67 | 
            +
                #
         | 
| 68 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 69 | 
            +
                #   inflector.constantize("Module")         # => Module
         | 
| 70 | 
            +
                #   inflector.constantize("Dry::Inflector") # => Dry::Inflector
         | 
| 71 | 
            +
                def constantize(input)
         | 
| 72 | 
            +
                  Object.const_get(input)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                # Classify a string
         | 
| 76 | 
            +
                #
         | 
| 77 | 
            +
                # @param input [String,Symbol] the input
         | 
| 78 | 
            +
                # @return [String] the classified string
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                # @since 0.1.0
         | 
| 81 | 
            +
                #
         | 
| 82 | 
            +
                # @example
         | 
| 83 | 
            +
                #   require "dry/inflector"
         | 
| 84 | 
            +
                #
         | 
| 85 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 86 | 
            +
                #   inflector.classify("books") # => "Book"
         | 
| 87 | 
            +
                def classify(input)
         | 
| 88 | 
            +
                  camelize(singularize(input.to_s.sub(/.*\./, "")))
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                # Dasherize a string
         | 
| 92 | 
            +
                #
         | 
| 93 | 
            +
                # @param input [String,Symbol] the input
         | 
| 94 | 
            +
                # @return [String] the dasherized string
         | 
| 95 | 
            +
                #
         | 
| 96 | 
            +
                # @since 0.1.0
         | 
| 97 | 
            +
                #
         | 
| 98 | 
            +
                # @example
         | 
| 99 | 
            +
                #   require "dry/inflector"
         | 
| 100 | 
            +
                #
         | 
| 101 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 102 | 
            +
                #   inflector.dasherize("dry_inflector") # => "dry-inflector"
         | 
| 103 | 
            +
                def dasherize(input)
         | 
| 104 | 
            +
                  input.to_s.tr("_", "-")
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                # Demodulize a string
         | 
| 108 | 
            +
                #
         | 
| 109 | 
            +
                # @param input [String,Symbol] the input
         | 
| 110 | 
            +
                # @return [String] the demodulized string
         | 
| 111 | 
            +
                #
         | 
| 112 | 
            +
                # @since 0.1.0
         | 
| 113 | 
            +
                #
         | 
| 114 | 
            +
                # @example
         | 
| 115 | 
            +
                #   require "dry/inflector"
         | 
| 116 | 
            +
                #
         | 
| 117 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 118 | 
            +
                #   inflector.demodulize("Dry::Inflector") # => "Inflector"
         | 
| 119 | 
            +
                def demodulize(input)
         | 
| 120 | 
            +
                  input.to_s.split("::").last
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                # Humanize a string
         | 
| 124 | 
            +
                #
         | 
| 125 | 
            +
                # @param input [String,Symbol] the input
         | 
| 126 | 
            +
                # @return [String] the humanized string
         | 
| 127 | 
            +
                #
         | 
| 128 | 
            +
                # @since 0.1.0
         | 
| 129 | 
            +
                #
         | 
| 130 | 
            +
                # @example
         | 
| 131 | 
            +
                #   require "dry/inflector"
         | 
| 132 | 
            +
                #
         | 
| 133 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 134 | 
            +
                #   inflector.humanize("dry_inflector") # => "Dry inflector"
         | 
| 135 | 
            +
                #   inflector.humanize("author_id")     # => "Author"
         | 
| 136 | 
            +
                def humanize(input)
         | 
| 137 | 
            +
                  input = input.to_s
         | 
| 138 | 
            +
                  result = inflections.humans.apply_to(input)
         | 
| 139 | 
            +
                  result.gsub!(/_id\z/, "")
         | 
| 140 | 
            +
                  result.tr!("_", " ")
         | 
| 141 | 
            +
                  result.capitalize!
         | 
| 142 | 
            +
                  result
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                # Creates a foreign key name
         | 
| 146 | 
            +
                #
         | 
| 147 | 
            +
                # @param input [String, Symbol] the input
         | 
| 148 | 
            +
                # @return [String] foreign key
         | 
| 149 | 
            +
                #
         | 
| 150 | 
            +
                # @example
         | 
| 151 | 
            +
                #   require "dry/inflector"
         | 
| 152 | 
            +
                #
         | 
| 153 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 154 | 
            +
                #   inflector.foreign_key("Message") => "message_id"
         | 
| 155 | 
            +
                def foreign_key(input)
         | 
| 156 | 
            +
                  "#{underscorize(demodulize(input))}_id"
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                # Ordinalize a number
         | 
| 160 | 
            +
                #
         | 
| 161 | 
            +
                # @param number [Integer] the input
         | 
| 162 | 
            +
                # @return [String] the ordinalized number
         | 
| 163 | 
            +
                #
         | 
| 164 | 
            +
                # @since 0.1.0
         | 
| 165 | 
            +
                #
         | 
| 166 | 
            +
                # @example
         | 
| 167 | 
            +
                #   require "dry/inflector"
         | 
| 168 | 
            +
                #
         | 
| 169 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 170 | 
            +
                #   inflector.ordinalize(1)  # => "1st"
         | 
| 171 | 
            +
                #   inflector.ordinalize(2)  # => "2nd"
         | 
| 172 | 
            +
                #   inflector.ordinalize(3)  # => "3rd"
         | 
| 173 | 
            +
                #   inflector.ordinalize(10) # => "10th"
         | 
| 174 | 
            +
                #   inflector.ordinalize(23) # => "23rd"
         | 
| 175 | 
            +
                def ordinalize(number)
         | 
| 176 | 
            +
                  abs_value = number.abs
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                  if ORDINALIZE_TH.include?(abs_value % 100)
         | 
| 179 | 
            +
                    "#{number}th"
         | 
| 180 | 
            +
                  else
         | 
| 181 | 
            +
                    case abs_value % 10
         | 
| 182 | 
            +
                    when 1 then "#{number}st"
         | 
| 183 | 
            +
                    when 2 then "#{number}nd"
         | 
| 184 | 
            +
                    when 3 then "#{number}rd"
         | 
| 185 | 
            +
                    end
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                # Pluralize a string
         | 
| 190 | 
            +
                #
         | 
| 191 | 
            +
                # @param input [String,Symbol] the input
         | 
| 192 | 
            +
                # @return [String] the pluralized string
         | 
| 193 | 
            +
                #
         | 
| 194 | 
            +
                # @since 0.1.0
         | 
| 195 | 
            +
                #
         | 
| 196 | 
            +
                # @example
         | 
| 197 | 
            +
                #   require "dry/inflector"
         | 
| 198 | 
            +
                #
         | 
| 199 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 200 | 
            +
                #   inflector.pluralize("book")  # => "books"
         | 
| 201 | 
            +
                #   inflector.pluralize("money") # => "money"
         | 
| 202 | 
            +
                def pluralize(input)
         | 
| 203 | 
            +
                  input = input.to_s
         | 
| 204 | 
            +
                  return input if uncountable?(input)
         | 
| 205 | 
            +
                  inflections.plurals.apply_to(input)
         | 
| 206 | 
            +
                end
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                # Singularize a string
         | 
| 209 | 
            +
                #
         | 
| 210 | 
            +
                # @param input [String] the input
         | 
| 211 | 
            +
                # @return [String] the singularized string
         | 
| 212 | 
            +
                #
         | 
| 213 | 
            +
                # @since 0.1.0
         | 
| 214 | 
            +
                #
         | 
| 215 | 
            +
                # @example
         | 
| 216 | 
            +
                #   require "dry/inflector"
         | 
| 217 | 
            +
                #
         | 
| 218 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 219 | 
            +
                #   inflector.singularize("books") # => "book"
         | 
| 220 | 
            +
                #   inflector.singularize("money") # => "money"
         | 
| 221 | 
            +
                def singularize(input)
         | 
| 222 | 
            +
                  input = input.to_s
         | 
| 223 | 
            +
                  return input if uncountable?(input)
         | 
| 224 | 
            +
                  inflections.singulars.apply_to(input)
         | 
| 225 | 
            +
                end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                # Tableize a string
         | 
| 228 | 
            +
                #
         | 
| 229 | 
            +
                # @param input [String,Symbol] the input
         | 
| 230 | 
            +
                # @return [String] the tableized string
         | 
| 231 | 
            +
                #
         | 
| 232 | 
            +
                # @since 0.1.0
         | 
| 233 | 
            +
                #
         | 
| 234 | 
            +
                # @example
         | 
| 235 | 
            +
                #   require "dry/inflector"
         | 
| 236 | 
            +
                #
         | 
| 237 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 238 | 
            +
                #   inflector.tableize("Book") # => "books"
         | 
| 239 | 
            +
                def tableize(input)
         | 
| 240 | 
            +
                  input = input.to_s.gsub(/::/, "_")
         | 
| 241 | 
            +
                  pluralize(underscorize(input))
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                # Underscore a string
         | 
| 245 | 
            +
                #
         | 
| 246 | 
            +
                # @param input [String,Symbol] the input
         | 
| 247 | 
            +
                # @return [String] the underscored string
         | 
| 248 | 
            +
                #
         | 
| 249 | 
            +
                # @since 0.1.0
         | 
| 250 | 
            +
                #
         | 
| 251 | 
            +
                # @example
         | 
| 252 | 
            +
                #   require "dry/inflector"
         | 
| 253 | 
            +
                #
         | 
| 254 | 
            +
                #   inflector = Dry::Inflector.new
         | 
| 255 | 
            +
                #   inflector.underscore("dry-inflector") # => "dry_inflector"
         | 
| 256 | 
            +
                def underscore(input)
         | 
| 257 | 
            +
                  input = input.to_s.gsub(/::/, "/")
         | 
| 258 | 
            +
                  underscorize(input)
         | 
| 259 | 
            +
                end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                # Check if the input is an uncountable word
         | 
| 262 | 
            +
                #
         | 
| 263 | 
            +
                # @param input [String] the input
         | 
| 264 | 
            +
                # @return [TrueClass,FalseClass] the result of the check
         | 
| 265 | 
            +
                #
         | 
| 266 | 
            +
                # @since 0.1.0
         | 
| 267 | 
            +
                # @api private
         | 
| 268 | 
            +
                def uncountable?(input)
         | 
| 269 | 
            +
                  !(input =~ /\A[[:space:]]*\z/).nil? || inflections.uncountables.include?(input.downcase)
         | 
| 270 | 
            +
                end
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                private
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                # @since 0.1.0
         | 
| 275 | 
            +
                # @api private
         | 
| 276 | 
            +
                ORDINALIZE_TH = (4..16).to_set.freeze
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                # @since 0.1.0
         | 
| 279 | 
            +
                # @api private
         | 
| 280 | 
            +
                attr_reader :inflections
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                # @since 0.1.0
         | 
| 283 | 
            +
                # @api private
         | 
| 284 | 
            +
                def underscorize(input)
         | 
| 285 | 
            +
                  input.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
         | 
| 286 | 
            +
                  input.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
         | 
| 287 | 
            +
                  input.tr!("-", "_")
         | 
| 288 | 
            +
                  input.downcase!
         | 
| 289 | 
            +
                  input
         | 
| 290 | 
            +
                end
         | 
| 291 | 
            +
              end
         | 
| 292 | 
            +
            end
         | 
| @@ -0,0 +1,217 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "set"
         | 
| 4 | 
            +
            require "dry/inflector/rules"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Dry
         | 
| 7 | 
            +
              class Inflector
         | 
| 8 | 
            +
                # Inflections
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # @since 0.1.0
         | 
| 11 | 
            +
                class Inflections
         | 
| 12 | 
            +
                  require "dry/inflector/inflections/defaults"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  # Instantiate a set of inflection rules.
         | 
| 15 | 
            +
                  # It adds the default rules and the optional customizations, passed as a block.
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  # @param blk [Proc] the optional, custom rules
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  # @since 0.1.0
         | 
| 20 | 
            +
                  # @api private
         | 
| 21 | 
            +
                  def self.build(&blk)
         | 
| 22 | 
            +
                    new do |inflect|
         | 
| 23 | 
            +
                      Defaults.call(inflect)
         | 
| 24 | 
            +
                      blk.call(inflect) if block_given?
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # Pluralization rules
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  # @return [Dry::Inflector::Rules]
         | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  # @since 0.1.0
         | 
| 33 | 
            +
                  # @api private
         | 
| 34 | 
            +
                  attr_reader :plurals
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  # Singularization rules
         | 
| 37 | 
            +
                  #
         | 
| 38 | 
            +
                  # @return [Dry::Inflector::Rules]
         | 
| 39 | 
            +
                  #
         | 
| 40 | 
            +
                  # @since 0.1.0
         | 
| 41 | 
            +
                  # @api private
         | 
| 42 | 
            +
                  attr_reader :singulars
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # Uncountable rules
         | 
| 45 | 
            +
                  #
         | 
| 46 | 
            +
                  # @return [Set]
         | 
| 47 | 
            +
                  #
         | 
| 48 | 
            +
                  # @since 0.1.0
         | 
| 49 | 
            +
                  # @api private
         | 
| 50 | 
            +
                  attr_reader :uncountables
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  # Human rules
         | 
| 53 | 
            +
                  #
         | 
| 54 | 
            +
                  # @return [Dry::Inflector::Rules]
         | 
| 55 | 
            +
                  #
         | 
| 56 | 
            +
                  # @since 0.1.0
         | 
| 57 | 
            +
                  # @api private
         | 
| 58 | 
            +
                  attr_reader :humans
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  # Instantiate the rules
         | 
| 61 | 
            +
                  #
         | 
| 62 | 
            +
                  # @return [Dry::Inflector::Inflections]
         | 
| 63 | 
            +
                  # @yieldparam [self]
         | 
| 64 | 
            +
                  #
         | 
| 65 | 
            +
                  # @since 0.1.0
         | 
| 66 | 
            +
                  # @api private
         | 
| 67 | 
            +
                  def initialize
         | 
| 68 | 
            +
                    @plurals      = Rules.new
         | 
| 69 | 
            +
                    @singulars    = Rules.new
         | 
| 70 | 
            +
                    @humans       = Rules.new
         | 
| 71 | 
            +
                    @uncountables = Set[]
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    yield(self) if block_given?
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  # Add a custom pluralization rule
         | 
| 77 | 
            +
                  #
         | 
| 78 | 
            +
                  # Specifies a new pluralization rule and its replacement.
         | 
| 79 | 
            +
                  # The rule can either be a string or a regular expression.
         | 
| 80 | 
            +
                  # The replacement should always be a string that may include references to the matched data from the rule.
         | 
| 81 | 
            +
                  #
         | 
| 82 | 
            +
                  # @param rule [String, Regexp] the rule
         | 
| 83 | 
            +
                  # @param replacement [String] the replacement
         | 
| 84 | 
            +
                  #
         | 
| 85 | 
            +
                  # @since 0.1.0
         | 
| 86 | 
            +
                  #
         | 
| 87 | 
            +
                  # @example
         | 
| 88 | 
            +
                  #   require "dry/inflector"
         | 
| 89 | 
            +
                  #
         | 
| 90 | 
            +
                  #   inflector = Dry::Inflector.new do |inflections|
         | 
| 91 | 
            +
                  #     inflections.plural "virus", "viruses"
         | 
| 92 | 
            +
                  #   end
         | 
| 93 | 
            +
                  def plural(rule, replacement)
         | 
| 94 | 
            +
                    rule(rule, replacement, plurals)
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  # Add a custom singularization rule
         | 
| 98 | 
            +
                  #
         | 
| 99 | 
            +
                  # Specifies a new singularization rule and its replacement.
         | 
| 100 | 
            +
                  # The rule can either be a string or a regular expression.
         | 
| 101 | 
            +
                  # The replacement should always be a string that may include references to the matched data from the rule.
         | 
| 102 | 
            +
                  #
         | 
| 103 | 
            +
                  # @param rule [String, Regexp] the rule
         | 
| 104 | 
            +
                  # @param replacement [String] the replacement
         | 
| 105 | 
            +
                  #
         | 
| 106 | 
            +
                  # @since 0.1.0
         | 
| 107 | 
            +
                  #
         | 
| 108 | 
            +
                  # @example
         | 
| 109 | 
            +
                  #   require "dry/inflector"
         | 
| 110 | 
            +
                  #
         | 
| 111 | 
            +
                  #   inflector = Dry::Inflector.new do |inflections|
         | 
| 112 | 
            +
                  #     inflections.singular "thieves", "thief"
         | 
| 113 | 
            +
                  #   end
         | 
| 114 | 
            +
                  def singular(rule, replacement)
         | 
| 115 | 
            +
                    rule(rule, replacement, singulars)
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  # Add a custom pluralization rule
         | 
| 119 | 
            +
                  #
         | 
| 120 | 
            +
                  # Specifies a new irregular that applies to both pluralization and singularization at the same time.
         | 
| 121 | 
            +
                  # This can only be used for strings, not regular expressions.
         | 
| 122 | 
            +
                  # You simply pass the irregular in singular and plural form.
         | 
| 123 | 
            +
                  #
         | 
| 124 | 
            +
                  # @param singular [String] the singular
         | 
| 125 | 
            +
                  # @param plural [String] the plural
         | 
| 126 | 
            +
                  #
         | 
| 127 | 
            +
                  # @since 0.1.0
         | 
| 128 | 
            +
                  #
         | 
| 129 | 
            +
                  # @example
         | 
| 130 | 
            +
                  #   require "dry/inflector"
         | 
| 131 | 
            +
                  #
         | 
| 132 | 
            +
                  #   inflector = Dry::Inflector.new do |inflections|
         | 
| 133 | 
            +
                  #     inflections.singular "octopus", "octopi"
         | 
| 134 | 
            +
                  #   end
         | 
| 135 | 
            +
                  def irregular(singular, plural)
         | 
| 136 | 
            +
                    uncountables.delete(singular)
         | 
| 137 | 
            +
                    uncountables.delete(plural)
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    add_irregular(singular, plural, plurals)
         | 
| 140 | 
            +
                    add_irregular(plural, singular, singulars)
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  # Add a custom rule for uncountable words
         | 
| 144 | 
            +
                  #
         | 
| 145 | 
            +
                  # Uncountable will not be inflected
         | 
| 146 | 
            +
                  #
         | 
| 147 | 
            +
                  # @param [Enumerable<String>] words
         | 
| 148 | 
            +
                  #
         | 
| 149 | 
            +
                  # @since 0.1.0
         | 
| 150 | 
            +
                  #
         | 
| 151 | 
            +
                  # @example
         | 
| 152 | 
            +
                  #   require "dry/inflector"
         | 
| 153 | 
            +
                  #
         | 
| 154 | 
            +
                  #   inflector = Dry::Inflector.new do |inflections|
         | 
| 155 | 
            +
                  #     inflections.uncountable "money"
         | 
| 156 | 
            +
                  #     inflections.uncountable "money", "information"
         | 
| 157 | 
            +
                  #     inflections.uncountable %w(money information rice)
         | 
| 158 | 
            +
                  #   end
         | 
| 159 | 
            +
                  def uncountable(*words)
         | 
| 160 | 
            +
                    uncountables.merge(words.flatten)
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  # Add a custom humanize rule
         | 
| 164 | 
            +
                  #
         | 
| 165 | 
            +
                  # Specifies a humanized form of a string by a regular expression rule or by a string mapping.
         | 
| 166 | 
            +
                  # When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
         | 
| 167 | 
            +
                  # When a string is used, the human form should be specified as desired (example: `"The name"`, not `"the_name"`)
         | 
| 168 | 
            +
                  #
         | 
| 169 | 
            +
                  # @param rule [String, Regexp] the rule
         | 
| 170 | 
            +
                  # @param replacement [String] the replacement
         | 
| 171 | 
            +
                  #
         | 
| 172 | 
            +
                  # @since 0.1.0
         | 
| 173 | 
            +
                  #
         | 
| 174 | 
            +
                  # @example
         | 
| 175 | 
            +
                  #   require "dry/inflector"
         | 
| 176 | 
            +
                  #
         | 
| 177 | 
            +
                  #   inflector = Dry::Inflector.new do |inflections|
         | 
| 178 | 
            +
                  #     inflections.human(/_cnt$/i, '\1_count')
         | 
| 179 | 
            +
                  #     inflections.human("legacy_col_person_name", "Name")
         | 
| 180 | 
            +
                  #   end
         | 
| 181 | 
            +
                  def human(rule, replacement)
         | 
| 182 | 
            +
                    humans.insert(0, [rule, replacement])
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                  private
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                  # Add irregular inflection
         | 
| 188 | 
            +
                  #
         | 
| 189 | 
            +
                  # @param rule [String] the rule
         | 
| 190 | 
            +
                  # @param replacement [String] the replacement
         | 
| 191 | 
            +
                  #
         | 
| 192 | 
            +
                  # @return [undefined]
         | 
| 193 | 
            +
                  #
         | 
| 194 | 
            +
                  # @since 0.1.0
         | 
| 195 | 
            +
                  # @api private
         | 
| 196 | 
            +
                  def add_irregular(rule, replacement, target)
         | 
| 197 | 
            +
                    head, *tail = rule.chars.to_a
         | 
| 198 | 
            +
                    rule(/(#{head})#{tail.join}\z/i, '\1' + replacement[1..-1], target)
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                  # Add a new rule
         | 
| 202 | 
            +
                  #
         | 
| 203 | 
            +
                  # @param rule [String, Regexp] the rule
         | 
| 204 | 
            +
                  # @param replacement [String, Regexp] the replacement
         | 
| 205 | 
            +
                  # @param target [Dry::Inflector::Rules] the target
         | 
| 206 | 
            +
                  #
         | 
| 207 | 
            +
                  # @since 0.1.0
         | 
| 208 | 
            +
                  # @api private
         | 
| 209 | 
            +
                  def rule(rule, replacement, target)
         | 
| 210 | 
            +
                    uncountables.delete(rule)
         | 
| 211 | 
            +
                    uncountables.delete(replacement)
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                    target.insert(0, [rule, replacement])
         | 
| 214 | 
            +
                  end
         | 
| 215 | 
            +
                end
         | 
| 216 | 
            +
              end
         | 
| 217 | 
            +
            end
         | 
| @@ -0,0 +1,110 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Dry
         | 
| 4 | 
            +
              class Inflector
         | 
| 5 | 
            +
                class Inflections
         | 
| 6 | 
            +
                  # Default inflections
         | 
| 7 | 
            +
                  #
         | 
| 8 | 
            +
                  # @since 0.1.0
         | 
| 9 | 
            +
                  # @api private
         | 
| 10 | 
            +
                  #
         | 
| 11 | 
            +
                  # rubocop:disable Metrics/AbcSize
         | 
| 12 | 
            +
                  # rubocop:disable Metrics/MethodLength
         | 
| 13 | 
            +
                  module Defaults
         | 
| 14 | 
            +
                    # @since 0.1.0
         | 
| 15 | 
            +
                    # @api private
         | 
| 16 | 
            +
                    def self.call(inflect)
         | 
| 17 | 
            +
                      plural(inflect)
         | 
| 18 | 
            +
                      singular(inflect)
         | 
| 19 | 
            +
                      irregular(inflect)
         | 
| 20 | 
            +
                      uncountable(inflect)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    # @since 0.1.0
         | 
| 24 | 
            +
                    # @api private
         | 
| 25 | 
            +
                    def self.plural(inflect)
         | 
| 26 | 
            +
                      inflect.plural(/\z/, "s")
         | 
| 27 | 
            +
                      inflect.plural(/s\z/i, "s")
         | 
| 28 | 
            +
                      inflect.plural(/(ax|test)is\z/i, '\1es')
         | 
| 29 | 
            +
                      inflect.plural(/(.*)us\z/i, '\1uses')
         | 
| 30 | 
            +
                      inflect.plural(/(octop|vir|cact)us\z/i, '\1i')
         | 
| 31 | 
            +
                      inflect.plural(/(octop|vir)i\z/i, '\1i')
         | 
| 32 | 
            +
                      inflect.plural(/(alias|status)\z/i, '\1es')
         | 
| 33 | 
            +
                      inflect.plural(/(buffal|domin|ech|embarg|her|mosquit|potat|tomat)o\z/i, '\1oes')
         | 
| 34 | 
            +
                      inflect.plural(/(?<!b)um\z/i, '\1a')
         | 
| 35 | 
            +
                      inflect.plural(/([ti])a\z/i, '\1a')
         | 
| 36 | 
            +
                      inflect.plural(/sis\z/i, "ses")
         | 
| 37 | 
            +
                      inflect.plural(/(.*)(?:([^f]))f[e]*\z/i, '\1\2ves')
         | 
| 38 | 
            +
                      inflect.plural(/(hive|proof)\z/i, '\1s') # TODO: proof can be moved in the above regexp
         | 
| 39 | 
            +
                      inflect.plural(/([^aeiouy]|qu)y\z/i, '\1ies')
         | 
| 40 | 
            +
                      inflect.plural(/(x|ch|ss|sh)\z/i, '\1es')
         | 
| 41 | 
            +
                      inflect.plural(/(stoma|epo)ch\z/i, '\1chs')
         | 
| 42 | 
            +
                      inflect.plural(/(matr|vert|ind)(?:ix|ex)\z/i, '\1ices')
         | 
| 43 | 
            +
                      inflect.plural(/([m|l])ouse\z/i, '\1ice')
         | 
| 44 | 
            +
                      inflect.plural(/([m|l])ice\z/i, '\1ice')
         | 
| 45 | 
            +
                      inflect.plural(/^(ox)\z/i, '\1en')
         | 
| 46 | 
            +
                      inflect.plural(/^(oxen)\z/i, '\1')
         | 
| 47 | 
            +
                      inflect.plural(/(quiz)\z/i, '\1zes')
         | 
| 48 | 
            +
                      inflect.plural(/(.*)non\z/i, '\1na')
         | 
| 49 | 
            +
                      inflect.plural(/(.*)ma\z/i, '\1mata')
         | 
| 50 | 
            +
                      inflect.plural(/(.*)(eau|eaux)\z/, '\1eaux')
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    # @since 0.1.0
         | 
| 54 | 
            +
                    # @api private
         | 
| 55 | 
            +
                    def self.singular(inflect)
         | 
| 56 | 
            +
                      inflect.singular(/s\z/i, "")
         | 
| 57 | 
            +
                      inflect.singular(/(n)ews\z/i, '\1ews')
         | 
| 58 | 
            +
                      inflect.singular(/([ti])a\z/i, '\1um')
         | 
| 59 | 
            +
                      inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses\z/i, '\1\2sis')
         | 
| 60 | 
            +
                      inflect.singular(/(^analy)ses\z/i, '\1sis')
         | 
| 61 | 
            +
                      inflect.singular(/([^f])ves\z/i, '\1fe')
         | 
| 62 | 
            +
                      inflect.singular(/(hive)s\z/i, '\1')
         | 
| 63 | 
            +
                      inflect.singular(/(tive)s\z/i, '\1')
         | 
| 64 | 
            +
                      inflect.singular(/([lr])ves\z/i, '\1f')
         | 
| 65 | 
            +
                      inflect.singular(/([^aeiouy]|qu)ies\z/i, '\1y')
         | 
| 66 | 
            +
                      inflect.singular(/(s)eries\z/i, '\1eries')
         | 
| 67 | 
            +
                      inflect.singular(/(m)ovies\z/i, '\1ovie')
         | 
| 68 | 
            +
                      inflect.singular(/(ss)\z/i, '\1')
         | 
| 69 | 
            +
                      inflect.singular(/(x|ch|ss|sh)es\z/i, '\1')
         | 
| 70 | 
            +
                      inflect.singular(/([m|l])ice\z/i, '\1ouse')
         | 
| 71 | 
            +
                      inflect.singular(/(bus)es\z/i, '\1')
         | 
| 72 | 
            +
                      inflect.singular(/(o)es\z/i, '\1')
         | 
| 73 | 
            +
                      inflect.singular(/(shoe)s\z/i, '\1')
         | 
| 74 | 
            +
                      inflect.singular(/(cris|ax|test)es\z/i, '\1is')
         | 
| 75 | 
            +
                      inflect.singular(/(octop|vir)i\z/i, '\1us')
         | 
| 76 | 
            +
                      inflect.singular(/(alias|status)es\z/i, '\1')
         | 
| 77 | 
            +
                      inflect.singular(/^(ox)en/i, '\1')
         | 
| 78 | 
            +
                      inflect.singular(/(vert|ind)ices\z/i, '\1ex')
         | 
| 79 | 
            +
                      inflect.singular(/(matr)ices\z/i, '\1ix')
         | 
| 80 | 
            +
                      inflect.singular(/(quiz)zes\z/i, '\1')
         | 
| 81 | 
            +
                      inflect.singular(/(database)s\z/i, '\1')
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    # @since 0.1.0
         | 
| 85 | 
            +
                    # @api private
         | 
| 86 | 
            +
                    def self.irregular(inflect)
         | 
| 87 | 
            +
                      inflect.irregular("person", "people")
         | 
| 88 | 
            +
                      inflect.irregular("man", "men")
         | 
| 89 | 
            +
                      inflect.irregular("human", "humans") # NOTE: this is here only to override the previous rule
         | 
| 90 | 
            +
                      inflect.irregular("child", "children")
         | 
| 91 | 
            +
                      inflect.irregular("sex", "sexes")
         | 
| 92 | 
            +
                      inflect.irregular("foot", "feet")
         | 
| 93 | 
            +
                      inflect.irregular("tooth", "teeth")
         | 
| 94 | 
            +
                      inflect.irregular("goose", "geese")
         | 
| 95 | 
            +
                      inflect.irregular("forum", "forums") # FIXME: this is here because I need to fix the "um" regexp
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    # @since 0.1.0
         | 
| 99 | 
            +
                    # @api private
         | 
| 100 | 
            +
                    def self.uncountable(inflect)
         | 
| 101 | 
            +
                      inflect.uncountable(%w[hovercraft moose deer milk rain Swiss grass equipment information rice money species series fish sheep jeans])
         | 
| 102 | 
            +
                    end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                    private_class_method :plural, :singular, :irregular, :uncountable
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                  # rubocop:enable Metrics/MethodLength
         | 
| 107 | 
            +
                  # rubocop:enable Metrics/AbcSize
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Dry
         | 
| 4 | 
            +
              class Inflector
         | 
| 5 | 
            +
                # A set of inflection rules
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                # @since 0.1.0
         | 
| 8 | 
            +
                # @api private
         | 
| 9 | 
            +
                class Rules
         | 
| 10 | 
            +
                  # @since 0.1.0
         | 
| 11 | 
            +
                  # @api private
         | 
| 12 | 
            +
                  def initialize
         | 
| 13 | 
            +
                    @rules = []
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # @since 0.1.0
         | 
| 17 | 
            +
                  # @api private
         | 
| 18 | 
            +
                  def apply_to(word)
         | 
| 19 | 
            +
                    result = word.dup
         | 
| 20 | 
            +
                    each { |rule, replacement| break if result.gsub!(rule, replacement) }
         | 
| 21 | 
            +
                    result
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # @since 0.1.0
         | 
| 25 | 
            +
                  # @api private
         | 
| 26 | 
            +
                  def insert(index, array)
         | 
| 27 | 
            +
                    @rules.insert(index, array)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # @since 0.1.0
         | 
| 31 | 
            +
                  # @api private
         | 
| 32 | 
            +
                  def each(&blk)
         | 
| 33 | 
            +
                    @rules.each(&blk)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,114 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: dry-inflector
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Luca Guidi
         | 
| 8 | 
            +
            - Andrii Savchenko
         | 
| 9 | 
            +
            - Abinoam P. Marques Jr.
         | 
| 10 | 
            +
            autorequire: 
         | 
| 11 | 
            +
            bindir: exe
         | 
| 12 | 
            +
            cert_chain: []
         | 
| 13 | 
            +
            date: 2017-11-17 00:00:00.000000000 Z
         | 
| 14 | 
            +
            dependencies:
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 16 | 
            +
              name: bundler
         | 
| 17 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 18 | 
            +
                requirements:
         | 
| 19 | 
            +
                - - "~>"
         | 
| 20 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            +
                    version: '1.15'
         | 
| 22 | 
            +
              type: :development
         | 
| 23 | 
            +
              prerelease: false
         | 
| 24 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            +
                requirements:
         | 
| 26 | 
            +
                - - "~>"
         | 
| 27 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 28 | 
            +
                    version: '1.15'
         | 
| 29 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 30 | 
            +
              name: rake
         | 
| 31 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 32 | 
            +
                requirements:
         | 
| 33 | 
            +
                - - "~>"
         | 
| 34 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 35 | 
            +
                    version: '12.0'
         | 
| 36 | 
            +
              type: :development
         | 
| 37 | 
            +
              prerelease: false
         | 
| 38 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 39 | 
            +
                requirements:
         | 
| 40 | 
            +
                - - "~>"
         | 
| 41 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 42 | 
            +
                    version: '12.0'
         | 
| 43 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 44 | 
            +
              name: rspec
         | 
| 45 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 46 | 
            +
                requirements:
         | 
| 47 | 
            +
                - - "~>"
         | 
| 48 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 49 | 
            +
                    version: '3.6'
         | 
| 50 | 
            +
              type: :development
         | 
| 51 | 
            +
              prerelease: false
         | 
| 52 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 53 | 
            +
                requirements:
         | 
| 54 | 
            +
                - - "~>"
         | 
| 55 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 56 | 
            +
                    version: '3.6'
         | 
| 57 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 58 | 
            +
              name: rubocop
         | 
| 59 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 60 | 
            +
                requirements:
         | 
| 61 | 
            +
                - - "~>"
         | 
| 62 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 63 | 
            +
                    version: 0.50.0
         | 
| 64 | 
            +
              type: :development
         | 
| 65 | 
            +
              prerelease: false
         | 
| 66 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 67 | 
            +
                requirements:
         | 
| 68 | 
            +
                - - "~>"
         | 
| 69 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 70 | 
            +
                    version: 0.50.0
         | 
| 71 | 
            +
            description: String inflections for dry-rb
         | 
| 72 | 
            +
            email:
         | 
| 73 | 
            +
            - me@lucaguidi.com
         | 
| 74 | 
            +
            - andrey@aejis.eu
         | 
| 75 | 
            +
            - abinoam@gmail.com
         | 
| 76 | 
            +
            executables: []
         | 
| 77 | 
            +
            extensions: []
         | 
| 78 | 
            +
            extra_rdoc_files: []
         | 
| 79 | 
            +
            files:
         | 
| 80 | 
            +
            - CHANGELOG.md
         | 
| 81 | 
            +
            - LICENSE.md
         | 
| 82 | 
            +
            - README.md
         | 
| 83 | 
            +
            - dry-inflector.gemspec
         | 
| 84 | 
            +
            - lib/dry/inflector.rb
         | 
| 85 | 
            +
            - lib/dry/inflector/inflections.rb
         | 
| 86 | 
            +
            - lib/dry/inflector/inflections/defaults.rb
         | 
| 87 | 
            +
            - lib/dry/inflector/rules.rb
         | 
| 88 | 
            +
            - lib/dry/inflector/version.rb
         | 
| 89 | 
            +
            homepage: http://dry-rb.org
         | 
| 90 | 
            +
            licenses:
         | 
| 91 | 
            +
            - MIT
         | 
| 92 | 
            +
            metadata:
         | 
| 93 | 
            +
              allowed_push_host: https://rubygems.org
         | 
| 94 | 
            +
            post_install_message: 
         | 
| 95 | 
            +
            rdoc_options: []
         | 
| 96 | 
            +
            require_paths:
         | 
| 97 | 
            +
            - lib
         | 
| 98 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 99 | 
            +
              requirements:
         | 
| 100 | 
            +
              - - ">="
         | 
| 101 | 
            +
                - !ruby/object:Gem::Version
         | 
| 102 | 
            +
                  version: '0'
         | 
| 103 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 104 | 
            +
              requirements:
         | 
| 105 | 
            +
              - - ">="
         | 
| 106 | 
            +
                - !ruby/object:Gem::Version
         | 
| 107 | 
            +
                  version: '0'
         | 
| 108 | 
            +
            requirements: []
         | 
| 109 | 
            +
            rubyforge_project: 
         | 
| 110 | 
            +
            rubygems_version: 2.7.1
         | 
| 111 | 
            +
            signing_key: 
         | 
| 112 | 
            +
            specification_version: 4
         | 
| 113 | 
            +
            summary: DRY Inflector
         | 
| 114 | 
            +
            test_files: []
         |