tickle 1.2.0 → 2.0.0.rc1
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 +4 -4
 - data/.gitignore +2 -1
 - data/.travis.yml +6 -4
 - data/CHANGES.md +6 -24
 - data/Gemfile +13 -4
 - data/LICENCE +1 -1
 - data/README.md +2 -2
 - data/Rakefile +4 -7
 - data/benchmarks/main.rb +71 -0
 - data/lib/ext/array.rb +6 -0
 - data/lib/ext/date_and_time.rb +64 -0
 - data/lib/ext/string.rb +39 -0
 - data/lib/tickle.rb +24 -117
 - data/lib/tickle/filters.rb +58 -0
 - data/lib/tickle/handler.rb +223 -80
 - data/lib/tickle/helpers.rb +51 -0
 - data/lib/tickle/patterns.rb +115 -0
 - data/lib/tickle/repeater.rb +232 -116
 - data/lib/tickle/tickle.rb +98 -220
 - data/lib/tickle/tickled.rb +174 -0
 - data/lib/tickle/token.rb +94 -0
 - data/lib/tickle/version.rb +1 -1
 - data/spec/helpers_spec.rb +36 -0
 - data/spec/patterns_spec.rb +240 -0
 - data/spec/spec_helper.rb +41 -0
 - data/spec/tickle_spec.rb +543 -0
 - data/spec/token_spec.rb +82 -0
 - data/test/helper.rb +0 -2
 - data/test/test_parsing.rb +14 -23
 - data/tickle.gemspec +2 -9
 - metadata +32 -113
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1d8b35a7f362cfb13d80ef3236f7f1f036cd7ebc
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: cec9f257100839052b8ea4e7b7a64fa560eebd01
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: d3d2636db14e75ce64453d3bf42bfdb4f22fde65af54a01b5113a58447ab46e9530a39f16771265a28e345a16b22417ae6dca699c8828cd9d4825d756db38af0
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e972f8974b427bcb5ad3be4333b4ac0951a82ada15f9cc8def342ff7414dd636e4169f757f579a3f17baa9c1578a265bc33865ee596f1e1aee2f2a4123be052b
         
     | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/.travis.yml
    CHANGED
    
    | 
         @@ -1,12 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            language: ruby
         
     | 
| 
       2 
2 
     | 
    
         
             
            rvm:
         
     | 
| 
       3 
     | 
    
         
            -
              -  
     | 
| 
       4 
     | 
    
         
            -
              -  
     | 
| 
       5 
     | 
    
         
            -
              -  
     | 
| 
      
 3 
     | 
    
         
            +
              - 1.9.3
         
     | 
| 
      
 4 
     | 
    
         
            +
              - 2.0.0
         
     | 
| 
      
 5 
     | 
    
         
            +
              - 2.1.1
         
     | 
| 
      
 6 
     | 
    
         
            +
              - ruby-head
         
     | 
| 
      
 7 
     | 
    
         
            +
              - jruby-19mode
         
     | 
| 
      
 8 
     | 
    
         
            +
            #  - rbx-2.1.1  # not working right now, will look at later
         
     | 
| 
       6 
9 
     | 
    
         | 
| 
       7 
10 
     | 
    
         
             
            # whitelist
         
     | 
| 
       8 
11 
     | 
    
         
             
            branches:
         
     | 
| 
       9 
12 
     | 
    
         
             
              only:
         
     | 
| 
       10 
13 
     | 
    
         
             
                - master
         
     | 
| 
       11 
14 
     | 
    
         
             
                - develop
         
     | 
| 
       12 
     | 
    
         
            -
                - v1-branch
         
     | 
    
        data/CHANGES.md
    CHANGED
    
    | 
         @@ -1,39 +1,21 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # CH CH CH CH CHANGES! #
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            ##  
     | 
| 
      
 3 
     | 
    
         
            +
            ## Saturday the 7th of November 2015, 2.0.0.rc1 ##
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            -  
     | 
| 
       6 
     | 
    
         
            -
            -  
     | 
| 
       7 
     | 
    
         
            -
            -  
     | 
| 
       8 
     | 
    
         
            -
            - Fixed bug with "today and" in the tests
         
     | 
| 
       9 
     | 
    
         
            -
            - Fixed a bug previously fixed on the v2 branch in 2f2a32ce9 with @start
         
     | 
| 
       10 
     | 
    
         
            -
            - Added Timecop because we're beyond the date chosen in the tests. Tempus fugit!
         
     | 
| 
      
 5 
     | 
    
         
            +
            - Rewrite of the internals.
         
     | 
| 
      
 6 
     | 
    
         
            +
            - API should be pretty much the same from the outside, but enough things on the inside change to warrant the major version bump.
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Chronic updated to 0.10.2.
         
     | 
| 
       11 
8 
     | 
    
         | 
| 
       12 
9 
     | 
    
         
             
            ----
         
     | 
| 
       13 
10 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
            ##  
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            * Bit of easier debugging added in.
         
     | 
| 
       17 
     | 
    
         
            -
            * Bug fixes, thanks to https://github.com/dodomarocgenex for finding and helping with them.
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
            ----
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
            ## Wednesday the 22nd of February 2017, v1.1.0 ##
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            * Numerizer duplication removed. Thanks to https://github.com/bjonord.
         
     | 
| 
       24 
     | 
    
         
            -
            * Some very minor changes to the project, no other code changes.
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
            ----
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            ## Monday the 11th of November 2015, v1.0.2 ##
         
     | 
| 
      
 11 
     | 
    
         
            +
            ## Monday the 11th of November 2013, v1.0.2 ##
         
     | 
| 
       30 
12 
     | 
    
         | 
| 
       31 
13 
     | 
    
         
             
            * Shoulda and simplecov aren't runtime dependencies, fixed that in the gemfile.
         
     | 
| 
       32 
14 
     | 
    
         
             
            * Got the version number right this time ;-)
         
     | 
| 
       33 
15 
     | 
    
         | 
| 
       34 
16 
     | 
    
         
             
            ----
         
     | 
| 
       35 
17 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
            ## Monday the 11th of November  
     | 
| 
      
 18 
     | 
    
         
            +
            ## Monday the 11th of November 2013, v1.0.1 ##
         
     | 
| 
       37 
19 
     | 
    
         | 
| 
       38 
20 
     | 
    
         
             
            * Moved library to new maintainer [https://github.com/yb66/tickle](@yb66)
         
     | 
| 
       39 
21 
     | 
    
         
             
            * Moved library to [http://semver.org/](semver).
         
     | 
    
        data/Gemfile
    CHANGED
    
    | 
         @@ -2,9 +2,18 @@ source "https://rubygems.org" 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            gemspec
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            group : 
     | 
| 
       6 
     | 
    
         
            -
              gem " 
     | 
| 
      
 5 
     | 
    
         
            +
            group :development do
         
     | 
| 
      
 6 
     | 
    
         
            +
              gem "wirble"
         
     | 
| 
      
 7 
     | 
    
         
            +
              gem "maruku"
         
     | 
| 
      
 8 
     | 
    
         
            +
              gem "yard"
         
     | 
| 
      
 9 
     | 
    
         
            +
              gem "pry-byebug"
         
     | 
| 
      
 10 
     | 
    
         
            +
              gem "activesupport"
         
     | 
| 
       7 
11 
     | 
    
         
             
            end
         
     | 
| 
       8 
12 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            gem " 
     | 
| 
      
 13 
     | 
    
         
            +
            group :test do
         
     | 
| 
      
 14 
     | 
    
         
            +
              gem "rspec"
         
     | 
| 
      
 15 
     | 
    
         
            +
              gem "rspec-its"
         
     | 
| 
      
 16 
     | 
    
         
            +
              gem "timecop"
         
     | 
| 
      
 17 
     | 
    
         
            +
              gem "simplecov"
         
     | 
| 
      
 18 
     | 
    
         
            +
              gem "rake"
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
    
        data/LICENCE
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -11,7 +11,7 @@ Take a look at the `develop` branch where all this stuff will be happening. 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
            Tickle is a natural language parser for recurring events.
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
            Tickle is designed to be a complement to [Chronic](https://rubygems.org/gems/chronic) and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc. 
     | 
| 
      
 14 
     | 
    
         
            +
            Tickle is designed to be a complement to [Chronic](https://rubygems.org/gems/chronic) and can interpret things such as "every 2 days", "every Sunday", “Sundays", “Weekly", etc.
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
            Tickle has one main method, `Tickle.parse`, which returns the next time the event should occur, at which point you simply call `Tickle.parse` again.   
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
         @@ -407,7 +407,7 @@ or if you're using Bundler, add this to the Gemfile: 
     | 
|
| 
       407 
407 
     | 
    
         | 
| 
       408 
408 
     | 
    
         
             
            Chronic gem:
         
     | 
| 
       409 
409 
     | 
    
         | 
| 
       410 
     | 
    
         
            -
            `gem install  
     | 
| 
      
 410 
     | 
    
         
            +
            `gem install chronic`
         
     | 
| 
       411 
411 
     | 
    
         | 
| 
       412 
412 
     | 
    
         
             
            thoughtbot's [shoulda](https://rubygems.org/gems/shoulda):
         
     | 
| 
       413 
413 
     | 
    
         | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -1,11 +1,8 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require ' 
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
              test.pattern = 'test/**/test_*.rb'
         
     | 
| 
       5 
     | 
    
         
            -
              test.verbose = true
         
     | 
| 
       6 
     | 
    
         
            -
            end
         
     | 
| 
      
 1 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec::Core::RakeTask.new(:spec)
         
     | 
| 
       7 
4 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
            task :default => : 
     | 
| 
      
 5 
     | 
    
         
            +
            task :default => :spec
         
     | 
| 
       9 
6 
     | 
    
         | 
| 
       10 
7 
     | 
    
         | 
| 
       11 
8 
     | 
    
         
             
            desc "(Re-) generate documentation and place it in the docs/ dir. Open the index.html file in there to read it."
         
     | 
    
        data/benchmarks/main.rb
    ADDED
    
    | 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'benchmark'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative "../lib/tickle.rb"
         
     | 
| 
      
 3 
     | 
    
         
            +
            warn Benchmark.measure {
         
     | 
| 
      
 4 
     | 
    
         
            +
              Tickle.parse('day')
         
     | 
| 
      
 5 
     | 
    
         
            +
            #   Tickle.parse('week')
         
     | 
| 
      
 6 
     | 
    
         
            +
              Tickle.parse('month')
         
     | 
| 
      
 7 
     | 
    
         
            +
              Tickle.parse('year')
         
     | 
| 
      
 8 
     | 
    
         
            +
              Tickle.parse('daily')
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   Tickle.parse('weekly')
         
     | 
| 
      
 10 
     | 
    
         
            +
              Tickle.parse('monthly')
         
     | 
| 
      
 11 
     | 
    
         
            +
              Tickle.parse('yearly')
         
     | 
| 
      
 12 
     | 
    
         
            +
              Tickle.parse('3 days')
         
     | 
| 
      
 13 
     | 
    
         
            +
            #   Tickle.parse('3 weeks')
         
     | 
| 
      
 14 
     | 
    
         
            +
              Tickle.parse('3 months')
         
     | 
| 
      
 15 
     | 
    
         
            +
              Tickle.parse('3 years')
         
     | 
| 
      
 16 
     | 
    
         
            +
              Tickle.parse('other day')
         
     | 
| 
      
 17 
     | 
    
         
            +
            #   Tickle.parse('other week')
         
     | 
| 
      
 18 
     | 
    
         
            +
              Tickle.parse('other month')
         
     | 
| 
      
 19 
     | 
    
         
            +
              Tickle.parse('other year')
         
     | 
| 
      
 20 
     | 
    
         
            +
              Tickle.parse('Monday')
         
     | 
| 
      
 21 
     | 
    
         
            +
              Tickle.parse('Wednesday')
         
     | 
| 
      
 22 
     | 
    
         
            +
              Tickle.parse('Friday')
         
     | 
| 
      
 23 
     | 
    
         
            +
              Tickle.parse('February', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 24 
     | 
    
         
            +
              Tickle.parse('May', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 25 
     | 
    
         
            +
              Tickle.parse('june', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 26 
     | 
    
         
            +
              Tickle.parse('beginning of the week')
         
     | 
| 
      
 27 
     | 
    
         
            +
              Tickle.parse('middle of the week')
         
     | 
| 
      
 28 
     | 
    
         
            +
              Tickle.parse('end of the week')
         
     | 
| 
      
 29 
     | 
    
         
            +
              Tickle.parse('beginning of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 30 
     | 
    
         
            +
              Tickle.parse('middle of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 31 
     | 
    
         
            +
              Tickle.parse('end of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 32 
     | 
    
         
            +
              Tickle.parse('beginning of the year', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 33 
     | 
    
         
            +
              Tickle.parse('middle of the year', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 34 
     | 
    
         
            +
              Tickle.parse('end of the year', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 35 
     | 
    
         
            +
              Tickle.parse('the 3rd of May', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 36 
     | 
    
         
            +
              Tickle.parse('the 3rd of February', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 37 
     | 
    
         
            +
              Tickle.parse('the 3rd of February 2022', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 38 
     | 
    
         
            +
              Tickle.parse('the 3rd of Feb 2022', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 39 
     | 
    
         
            +
              Tickle.parse('the 4th of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 40 
     | 
    
         
            +
              Tickle.parse('the 10th of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 41 
     | 
    
         
            +
              Tickle.parse('the tenth of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 42 
     | 
    
         
            +
              Tickle.parse('first', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 43 
     | 
    
         
            +
              Tickle.parse('the first of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 44 
     | 
    
         
            +
              Tickle.parse('the thirtieth', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 45 
     | 
    
         
            +
              Tickle.parse('the fifth', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 46 
     | 
    
         
            +
              Tickle.parse('the 1st Wednesday of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 47 
     | 
    
         
            +
              Tickle.parse('the 3rd Sunday of May', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 48 
     | 
    
         
            +
              Tickle.parse('the 3rd Sunday of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 49 
     | 
    
         
            +
              Tickle.parse('the 23rd of June', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 50 
     | 
    
         
            +
              Tickle.parse('the twenty third of June', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 51 
     | 
    
         
            +
              Tickle.parse('the thirty first of July', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 52 
     | 
    
         
            +
              Tickle.parse('the twenty first', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 53 
     | 
    
         
            +
              Tickle.parse('the twenty first of the month', {:start=>Time.parse("2020-04-01 00:00:00 +0000"), :now=>Time.parse("2020-04-01 00:00:00 +0000")})
         
     | 
| 
      
 54 
     | 
    
         
            +
              Tickle.parse('starting today and ending one week from now')
         
     | 
| 
      
 55 
     | 
    
         
            +
              Tickle.parse('starting tomorrow and ending one week from now')
         
     | 
| 
      
 56 
     | 
    
         
            +
              Tickle.parse('starting Monday repeat every month')
         
     | 
| 
      
 57 
     | 
    
         
            +
              Tickle.parse('starting May 13th repeat every week')
         
     | 
| 
      
 58 
     | 
    
         
            +
              Tickle.parse('starting May 13th repeat every other day')
         
     | 
| 
      
 59 
     | 
    
         
            +
              Tickle.parse('every other day starts May 13th')
         
     | 
| 
      
 60 
     | 
    
         
            +
              Tickle.parse('every other day starts May 13')
         
     | 
| 
      
 61 
     | 
    
         
            +
              Tickle.parse('every other day starting May 13th')
         
     | 
| 
      
 62 
     | 
    
         
            +
              Tickle.parse('every other day starting May 13')
         
     | 
| 
      
 63 
     | 
    
         
            +
              Tickle.parse('every week starts this wednesday')
         
     | 
| 
      
 64 
     | 
    
         
            +
              Tickle.parse('every week starting this wednesday')
         
     | 
| 
      
 65 
     | 
    
         
            +
              Tickle.parse('every other day starting May 1st 2021')
         
     | 
| 
      
 66 
     | 
    
         
            +
              Tickle.parse('every other day starting May 1 2021')
         
     | 
| 
      
 67 
     | 
    
         
            +
              Tickle.parse('every other week starting this Sunday')
         
     | 
| 
      
 68 
     | 
    
         
            +
              Tickle.parse('every week starting this wednesday until May 13th')
         
     | 
| 
      
 69 
     | 
    
         
            +
              Tickle.parse('every week starting this wednesday ends May 13th')
         
     | 
| 
      
 70 
     | 
    
         
            +
              Tickle.parse('every week starting this wednesday ending May 13th')
         
     | 
| 
      
 71 
     | 
    
         
            +
            }
         
     | 
    
        data/lib/ext/array.rb
    ADDED
    
    
| 
         @@ -0,0 +1,64 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Date
         
     | 
| 
      
 2 
     | 
    
         
            +
              # returns the days in the sending month
         
     | 
| 
      
 3 
     | 
    
         
            +
              def days_in_month
         
     | 
| 
      
 4 
     | 
    
         
            +
                d,m,y = mday,month,year
         
     | 
| 
      
 5 
     | 
    
         
            +
                d += 1 while Date.valid_civil?(y,m,d)
         
     | 
| 
      
 6 
     | 
    
         
            +
                d - 1
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              # no idea what this is for
         
     | 
| 
      
 11 
     | 
    
         
            +
              def bump(attr, amount=nil)
         
     | 
| 
      
 12 
     | 
    
         
            +
                amount ||= 1
         
     | 
| 
      
 13 
     | 
    
         
            +
                case attr
         
     | 
| 
      
 14 
     | 
    
         
            +
                when :day then
         
     | 
| 
      
 15 
     | 
    
         
            +
                  Date.civil(self.year, self.month, self.day + amount)
         
     | 
| 
      
 16 
     | 
    
         
            +
                when :wday then
         
     | 
| 
      
 17 
     | 
    
         
            +
                  amount = Date::ABBR_DAYNAMES.index(amount) if amount.is_a?(String)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  raise Exception, "specified day of week invalid.  Use #{Date::ABBR_DAYNAMES}" unless amount
         
     | 
| 
      
 19 
     | 
    
         
            +
                  diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
         
     | 
| 
      
 20 
     | 
    
         
            +
                  Date.civil(self.year, self.month, self.day + diff)
         
     | 
| 
      
 21 
     | 
    
         
            +
                when :week then
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Date.civil(self.year, self.month, self.day + (7*amount))
         
     | 
| 
      
 23 
     | 
    
         
            +
                when :month then
         
     | 
| 
      
 24 
     | 
    
         
            +
                  Date.civil(self.year, self.month+amount, self.day)
         
     | 
| 
      
 25 
     | 
    
         
            +
                when :year then
         
     | 
| 
      
 26 
     | 
    
         
            +
                  Date.civil(self.year + amount, self.month, self.day)
         
     | 
| 
      
 27 
     | 
    
         
            +
                when :sec then
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Date.civil(self.year, self.month, self.day, self.hour, self.minute, self.sec + amount)
         
     | 
| 
      
 29 
     | 
    
         
            +
                else
         
     | 
| 
      
 30 
     | 
    
         
            +
                  raise Exception, "type \"#{attr}\" not supported."
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            class Time
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              # same again, no idea what this is for
         
     | 
| 
      
 38 
     | 
    
         
            +
              def bump(attr, amount=nil)
         
     | 
| 
      
 39 
     | 
    
         
            +
                amount ||= 1
         
     | 
| 
      
 40 
     | 
    
         
            +
                case attr
         
     | 
| 
      
 41 
     | 
    
         
            +
                when :sec then
         
     | 
| 
      
 42 
     | 
    
         
            +
                  Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec + amount)
         
     | 
| 
      
 43 
     | 
    
         
            +
                when :min then
         
     | 
| 
      
 44 
     | 
    
         
            +
                  Time.local(self.year, self.month, self.day, self.hour, self.min + amount, self.sec)
         
     | 
| 
      
 45 
     | 
    
         
            +
                when :hour then
         
     | 
| 
      
 46 
     | 
    
         
            +
                  Time.local(self.year, self.month, self.day, self.hour + amount, self.min, self.sec)
         
     | 
| 
      
 47 
     | 
    
         
            +
                when :day then
         
     | 
| 
      
 48 
     | 
    
         
            +
                  Time.local(self.year, self.month, self.day + amount, self.hour, self.min, self.sec)
         
     | 
| 
      
 49 
     | 
    
         
            +
                when :wday then
         
     | 
| 
      
 50 
     | 
    
         
            +
                  amount = Time::RFC2822_DAY_NAME.index(amount) if amount.is_a?(String)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  raise Exception, "specified day of week invalid.  Use #{Time::RFC2822_DAY_NAME}" unless amount
         
     | 
| 
      
 52 
     | 
    
         
            +
                  diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
         
     | 
| 
      
 53 
     | 
    
         
            +
                  Time.local(self.year, self.month, self.day + diff, self.hour, self.min, self.sec)
         
     | 
| 
      
 54 
     | 
    
         
            +
                when :week then
         
     | 
| 
      
 55 
     | 
    
         
            +
                  Time.local(self.year, self.month, self.day + (amount * 7), self.hour, self.min, self.sec)
         
     | 
| 
      
 56 
     | 
    
         
            +
                when :month then
         
     | 
| 
      
 57 
     | 
    
         
            +
                  Time.local(self.year, self.month + amount, self.day, self.hour, self.min, self.sec)
         
     | 
| 
      
 58 
     | 
    
         
            +
                when :year then
         
     | 
| 
      
 59 
     | 
    
         
            +
                  Time.local(self.year + amount, self.month, self.day, self.hour, self.min, self.sec)
         
     | 
| 
      
 60 
     | 
    
         
            +
                else
         
     | 
| 
      
 61 
     | 
    
         
            +
                  raise Exception, "type \"#{attr}\" not supported."
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/ext/string.rb
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tickle
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Ordinal < ::String
         
     | 
| 
      
 3 
     | 
    
         
            +
                # returns true if the sending string is a text or numeric ordinal (e.g. first or 1st)
         
     | 
| 
      
 4 
     | 
    
         
            +
                def is_ordinal?
         
     | 
| 
      
 5 
     | 
    
         
            +
                  scanner = %w{first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth eighteenth nineteenth twenty thirty thirtieth}
         
     | 
| 
      
 6 
     | 
    
         
            +
                  regex = /\b(\d*)(st|nd|rd|th)\b/
         
     | 
| 
      
 7 
     | 
    
         
            +
                  !(self =~ regex).nil? || scanner.include?(self.downcase)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def ordinal_as_number
         
     | 
| 
      
 11 
     | 
    
         
            +
                  return self unless self.is_ordinal?
         
     | 
| 
      
 12 
     | 
    
         
            +
                  scanner = {/first/ => '1st',
         
     | 
| 
      
 13 
     | 
    
         
            +
                    /second/ => '2nd',
         
     | 
| 
      
 14 
     | 
    
         
            +
                    /third/ => '3rd',
         
     | 
| 
      
 15 
     | 
    
         
            +
                    /fourth/ => '4th',
         
     | 
| 
      
 16 
     | 
    
         
            +
                    /fifth/ => '5th',
         
     | 
| 
      
 17 
     | 
    
         
            +
                    /sixth/ => '6th',
         
     | 
| 
      
 18 
     | 
    
         
            +
                    /seventh/ => '7th',
         
     | 
| 
      
 19 
     | 
    
         
            +
                    /eighth/ => '8th',
         
     | 
| 
      
 20 
     | 
    
         
            +
                    /ninth/ => '9th',
         
     | 
| 
      
 21 
     | 
    
         
            +
                    /tenth/ => '10th',
         
     | 
| 
      
 22 
     | 
    
         
            +
                    /eleventh/ => '11th',
         
     | 
| 
      
 23 
     | 
    
         
            +
                    /twelfth/ => '12th',
         
     | 
| 
      
 24 
     | 
    
         
            +
                    /thirteenth/ => '13th',
         
     | 
| 
      
 25 
     | 
    
         
            +
                    /fourteenth/ => '14th',
         
     | 
| 
      
 26 
     | 
    
         
            +
                    /fifteenth/ => '15th',
         
     | 
| 
      
 27 
     | 
    
         
            +
                    /sixteenth/ => '16th',
         
     | 
| 
      
 28 
     | 
    
         
            +
                    /seventeenth/ => '17th',
         
     | 
| 
      
 29 
     | 
    
         
            +
                    /eighteenth/ => '18th',
         
     | 
| 
      
 30 
     | 
    
         
            +
                    /nineteenth/ => '19th',
         
     | 
| 
      
 31 
     | 
    
         
            +
                    /twentieth/ => '20th',
         
     | 
| 
      
 32 
     | 
    
         
            +
                    /thirtieth/ => '30th',
         
     | 
| 
      
 33 
     | 
    
         
            +
                  }
         
     | 
| 
      
 34 
     | 
    
         
            +
                  result = self
         
     | 
| 
      
 35 
     | 
    
         
            +
                  scanner.keys.each {|scanner_item| result = scanner[scanner_item] if scanner_item =~ self}
         
     | 
| 
      
 36 
     | 
    
         
            +
                  return result.gsub(/\b(\d*)(st|nd|rd|th)\b/, '\1')
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tickle.rb
    CHANGED
    
    | 
         @@ -9,29 +9,40 @@ 
     | 
|
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            $LOAD_PATH.unshift(File.dirname(__FILE__))     # For use/testing when no gem is installed
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            if ENV["DEBUG"]
         
     | 
| 
       13 
     | 
    
         
            -
              warn "DEBUG MODE ON" 
         
     | 
| 
       14 
     | 
    
         
            -
              require 'pry-byebug' 
         
     | 
| 
       15 
     | 
    
         
            -
              require 'pry-state'
         
     | 
| 
       16 
     | 
    
         
            -
              binding.pry
         
     | 
| 
       17 
     | 
    
         
            -
            end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
12 
     | 
    
         
             
            require 'date'
         
     | 
| 
       20 
13 
     | 
    
         
             
            require 'time'
         
     | 
| 
       21 
     | 
    
         
            -
            require ' 
     | 
| 
      
 14 
     | 
    
         
            +
            require 'chronic'
         
     | 
| 
       22 
15 
     | 
    
         | 
| 
       23 
16 
     | 
    
         
             
            require 'tickle/tickle'
         
     | 
| 
       24 
17 
     | 
    
         
             
            require 'tickle/handler'
         
     | 
| 
       25 
18 
     | 
    
         
             
            require 'tickle/repeater'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require_relative "tickle/tickled.rb"
         
     | 
| 
      
 20 
     | 
    
         
            +
            require_relative "ext/array.rb"
         
     | 
| 
      
 21 
     | 
    
         
            +
            require_relative "ext/date_and_time.rb"
         
     | 
| 
      
 22 
     | 
    
         
            +
            require_relative "ext/string.rb"
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            # these are required not because they're used by the library
         
     | 
| 
      
 25 
     | 
    
         
            +
            # but because they clobber so much that testing
         
     | 
| 
      
 26 
     | 
    
         
            +
            # without them will miss possible problems
         
     | 
| 
      
 27 
     | 
    
         
            +
            require 'active_support/core_ext/string/conversions'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require 'active_support/core_ext/date/calculations'
         
     | 
| 
      
 29 
     | 
    
         
            +
            require 'active_support/core_ext/date_time/calculations'
         
     | 
| 
      
 30 
     | 
    
         
            +
            require 'active_support/core_ext/time/calculations'
         
     | 
| 
       26 
31 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
            # Tickle is a natural language parser for recurring events.
         
     | 
| 
      
 33 
     | 
    
         
            +
            module Tickle
         
     | 
| 
       28 
34 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
              def self. 
     | 
| 
      
 35 
     | 
    
         
            +
              def self.parse(asked, options = {})
         
     | 
| 
      
 36 
     | 
    
         
            +
                # check to see if a datetime was passed
         
     | 
| 
      
 37 
     | 
    
         
            +
                # if so, give it back
         
     | 
| 
      
 38 
     | 
    
         
            +
                # TODO Consider converting to a Tickled
         
     | 
| 
      
 39 
     | 
    
         
            +
                return asked if asked.respond_to? :day
         
     | 
| 
       30 
40 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                 
     | 
| 
      
 41 
     | 
    
         
            +
                tickled = Tickled.new asked.dup, options
         
     | 
| 
      
 42 
     | 
    
         
            +
                _parse tickled
         
     | 
| 
       33 
43 
     | 
    
         
             
              end
         
     | 
| 
       34 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
       35 
46 
     | 
    
         
             
              def self.is_date(str)
         
     | 
| 
       36 
47 
     | 
    
         
             
                begin
         
     | 
| 
       37 
48 
     | 
    
         
             
                  Date.parse(str.to_s)
         
     | 
| 
         @@ -40,108 +51,4 @@ module Tickle #:nodoc: 
     | 
|
| 
       40 
51 
     | 
    
         
             
                  return false
         
     | 
| 
       41 
52 
     | 
    
         
             
                end
         
     | 
| 
       42 
53 
     | 
    
         
             
              end
         
     | 
| 
       43 
     | 
    
         
            -
            end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
            class Date #:nodoc:
         
     | 
| 
       46 
     | 
    
         
            -
              # returns the days in the sending month
         
     | 
| 
       47 
     | 
    
         
            -
              def days_in_month
         
     | 
| 
       48 
     | 
    
         
            -
                d,m,y = mday,month,year
         
     | 
| 
       49 
     | 
    
         
            -
                d += 1 while Date.valid_civil?(y,m,d)
         
     | 
| 
       50 
     | 
    
         
            -
                d - 1
         
     | 
| 
       51 
     | 
    
         
            -
              end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
              def bump(attr, amount=nil)
         
     | 
| 
       54 
     | 
    
         
            -
                amount ||= 1
         
     | 
| 
       55 
     | 
    
         
            -
                case attr
         
     | 
| 
       56 
     | 
    
         
            -
                when :day then
         
     | 
| 
       57 
     | 
    
         
            -
                  Date.civil(self.year, self.month, self.day).next_day(amount)
         
     | 
| 
       58 
     | 
    
         
            -
                when :wday then
         
     | 
| 
       59 
     | 
    
         
            -
                  amount = Date::ABBR_DAYNAMES.index(amount) if amount.is_a?(String)
         
     | 
| 
       60 
     | 
    
         
            -
                  raise Exception, "specified day of week invalid.  Use #{Date::ABBR_DAYNAMES}" unless amount
         
     | 
| 
       61 
     | 
    
         
            -
                  diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
         
     | 
| 
       62 
     | 
    
         
            -
                  Date.civil(self.year, self.month, self.day).next_day(diff)
         
     | 
| 
       63 
     | 
    
         
            -
                when :week then
         
     | 
| 
       64 
     | 
    
         
            -
                  Date.civil(self.year, self.month, self.day).next_day(7*amount)
         
     | 
| 
       65 
     | 
    
         
            -
                when :month then
         
     | 
| 
       66 
     | 
    
         
            -
                  Date.civil(self.year, self.month, self.day).next_month(amount)
         
     | 
| 
       67 
     | 
    
         
            -
                when :year then
         
     | 
| 
       68 
     | 
    
         
            -
                  Date.civil(self.year, self.month, self.day).next_year(amount)
         
     | 
| 
       69 
     | 
    
         
            -
                else
         
     | 
| 
       70 
     | 
    
         
            -
                  raise Exception, "type \"#{attr}\" not supported."
         
     | 
| 
       71 
     | 
    
         
            -
                end
         
     | 
| 
       72 
     | 
    
         
            -
              end
         
     | 
| 
       73 
     | 
    
         
            -
            end
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
            class Time #:nodoc:
         
     | 
| 
       76 
     | 
    
         
            -
              def bump(attr, amount=nil)
         
     | 
| 
       77 
     | 
    
         
            -
                amount ||= 1
         
     | 
| 
       78 
     | 
    
         
            -
                case attr
         
     | 
| 
       79 
     | 
    
         
            -
                when :sec then
         
     | 
| 
       80 
     | 
    
         
            -
                  Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + amount
         
     | 
| 
       81 
     | 
    
         
            -
                when :min then
         
     | 
| 
       82 
     | 
    
         
            -
                  Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + (amount * 60)
         
     | 
| 
       83 
     | 
    
         
            -
                when :hour then
         
     | 
| 
       84 
     | 
    
         
            -
                  Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + (amount * 60 * 60)
         
     | 
| 
       85 
     | 
    
         
            -
                when :day then
         
     | 
| 
       86 
     | 
    
         
            -
                  Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + (amount * 60 * 60 * 24)
         
     | 
| 
       87 
     | 
    
         
            -
                when :wday then
         
     | 
| 
       88 
     | 
    
         
            -
                  amount = Time::RFC2822_DAY_NAME.index(amount) if amount.is_a?(String)
         
     | 
| 
       89 
     | 
    
         
            -
                  raise Exception, "specified day of week invalid.  Use #{Time::RFC2822_DAY_NAME}" unless amount
         
     | 
| 
       90 
     | 
    
         
            -
                  diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
         
     | 
| 
       91 
     | 
    
         
            -
                  DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_day(diff)
         
     | 
| 
       92 
     | 
    
         
            -
                when :week then
         
     | 
| 
       93 
     | 
    
         
            -
                  DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_day(amount * 7)
         
     | 
| 
       94 
     | 
    
         
            -
                when :month then
         
     | 
| 
       95 
     | 
    
         
            -
                  DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_month(amount)
         
     | 
| 
       96 
     | 
    
         
            -
                when :year then
         
     | 
| 
       97 
     | 
    
         
            -
                  DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_year(amount)
         
     | 
| 
       98 
     | 
    
         
            -
                else
         
     | 
| 
       99 
     | 
    
         
            -
                  raise Exception, "type \"#{attr}\" not supported."
         
     | 
| 
       100 
     | 
    
         
            -
                end.to_time.localtime
         
     | 
| 
       101 
     | 
    
         
            -
              end
         
     | 
| 
       102 
     | 
    
         
            -
            end
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
            class String #:nodoc:
         
     | 
| 
       105 
     | 
    
         
            -
              # returns true if the sending string is a text or numeric ordinal (e.g. first or 1st)
         
     | 
| 
       106 
     | 
    
         
            -
              def is_ordinal?
         
     | 
| 
       107 
     | 
    
         
            -
                scanner = %w{first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth eighteenth nineteenth twenty thirty thirtieth}
         
     | 
| 
       108 
     | 
    
         
            -
                regex = /\b(\d*)(st|nd|rd|th)\b/
         
     | 
| 
       109 
     | 
    
         
            -
                !(self =~ regex).nil? || scanner.include?(self.downcase)
         
     | 
| 
       110 
     | 
    
         
            -
              end
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
              def ordinal_as_number
         
     | 
| 
       113 
     | 
    
         
            -
                return self unless self.is_ordinal?
         
     | 
| 
       114 
     | 
    
         
            -
                scanner = {/first/ => '1st',
         
     | 
| 
       115 
     | 
    
         
            -
                  /second/ => '2nd',
         
     | 
| 
       116 
     | 
    
         
            -
                  /third/ => '3rd',
         
     | 
| 
       117 
     | 
    
         
            -
                  /fourth/ => '4th',
         
     | 
| 
       118 
     | 
    
         
            -
                  /fifth/ => '5th',
         
     | 
| 
       119 
     | 
    
         
            -
                  /sixth/ => '6th',
         
     | 
| 
       120 
     | 
    
         
            -
                  /seventh/ => '7th',
         
     | 
| 
       121 
     | 
    
         
            -
                  /eighth/ => '8th',
         
     | 
| 
       122 
     | 
    
         
            -
                  /ninth/ => '9th',
         
     | 
| 
       123 
     | 
    
         
            -
                  /tenth/ => '10th',
         
     | 
| 
       124 
     | 
    
         
            -
                  /eleventh/ => '11th',
         
     | 
| 
       125 
     | 
    
         
            -
                  /twelfth/ => '12th',
         
     | 
| 
       126 
     | 
    
         
            -
                  /thirteenth/ => '13th',
         
     | 
| 
       127 
     | 
    
         
            -
                  /fourteenth/ => '14th',
         
     | 
| 
       128 
     | 
    
         
            -
                  /fifteenth/ => '15th',
         
     | 
| 
       129 
     | 
    
         
            -
                  /sixteenth/ => '16th',
         
     | 
| 
       130 
     | 
    
         
            -
                  /seventeenth/ => '17th',
         
     | 
| 
       131 
     | 
    
         
            -
                  /eighteenth/ => '18th',
         
     | 
| 
       132 
     | 
    
         
            -
                  /nineteenth/ => '19th',
         
     | 
| 
       133 
     | 
    
         
            -
                  /twentieth/ => '20th',
         
     | 
| 
       134 
     | 
    
         
            -
                  /thirtieth/ => '30th',
         
     | 
| 
       135 
     | 
    
         
            -
                }
         
     | 
| 
       136 
     | 
    
         
            -
                result = self
         
     | 
| 
       137 
     | 
    
         
            -
                scanner.keys.each {|scanner_item| result = scanner[scanner_item] if scanner_item =~ self}
         
     | 
| 
       138 
     | 
    
         
            -
                return result.gsub(/\b(\d*)(st|nd|rd|th)\b/, '\1')
         
     | 
| 
       139 
     | 
    
         
            -
              end
         
     | 
| 
       140 
     | 
    
         
            -
            end
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
            class Array #:nodoc:
         
     | 
| 
       143 
     | 
    
         
            -
              # compares two arrays to determine if they both contain the same elements
         
     | 
| 
       144 
     | 
    
         
            -
              def same?(y)
         
     | 
| 
       145 
     | 
    
         
            -
                self.sort == y.sort
         
     | 
| 
       146 
     | 
    
         
            -
              end
         
     | 
| 
       147 
     | 
    
         
            -
            end
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     |