chronic_2011 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.
- data/.gitignore +6 -0
 - data/HISTORY.md +4 -0
 - data/LICENSE +21 -0
 - data/README.md +180 -0
 - data/Rakefile +46 -0
 - data/chronic.gemspec +18 -0
 - data/lib/chronic.rb +117 -0
 - data/lib/chronic/chronic.rb +346 -0
 - data/lib/chronic/grabber.rb +33 -0
 - data/lib/chronic/handler.rb +88 -0
 - data/lib/chronic/handlers.rb +553 -0
 - data/lib/chronic/mini_date.rb +38 -0
 - data/lib/chronic/numerizer.rb +121 -0
 - data/lib/chronic/ordinal.rb +47 -0
 - data/lib/chronic/pointer.rb +32 -0
 - data/lib/chronic/repeater.rb +142 -0
 - data/lib/chronic/repeaters/repeater_day.rb +53 -0
 - data/lib/chronic/repeaters/repeater_day_name.rb +52 -0
 - data/lib/chronic/repeaters/repeater_day_portion.rb +108 -0
 - data/lib/chronic/repeaters/repeater_fortnight.rb +71 -0
 - data/lib/chronic/repeaters/repeater_hour.rb +58 -0
 - data/lib/chronic/repeaters/repeater_minute.rb +58 -0
 - data/lib/chronic/repeaters/repeater_month.rb +79 -0
 - data/lib/chronic/repeaters/repeater_month_name.rb +94 -0
 - data/lib/chronic/repeaters/repeater_season.rb +109 -0
 - data/lib/chronic/repeaters/repeater_season_name.rb +43 -0
 - data/lib/chronic/repeaters/repeater_second.rb +42 -0
 - data/lib/chronic/repeaters/repeater_time.rb +128 -0
 - data/lib/chronic/repeaters/repeater_week.rb +74 -0
 - data/lib/chronic/repeaters/repeater_weekday.rb +85 -0
 - data/lib/chronic/repeaters/repeater_weekend.rb +66 -0
 - data/lib/chronic/repeaters/repeater_year.rb +77 -0
 - data/lib/chronic/scalar.rb +116 -0
 - data/lib/chronic/season.rb +26 -0
 - data/lib/chronic/separator.rb +94 -0
 - data/lib/chronic/span.rb +31 -0
 - data/lib/chronic/tag.rb +36 -0
 - data/lib/chronic/time_zone.rb +32 -0
 - data/lib/chronic/token.rb +47 -0
 - data/test/helper.rb +12 -0
 - data/test/test_chronic.rb +148 -0
 - data/test/test_daylight_savings.rb +118 -0
 - data/test/test_handler.rb +104 -0
 - data/test/test_mini_date.rb +32 -0
 - data/test/test_numerizer.rb +72 -0
 - data/test/test_parsing.rb +977 -0
 - data/test/test_repeater_day_name.rb +51 -0
 - data/test/test_repeater_day_portion.rb +254 -0
 - data/test/test_repeater_fortnight.rb +62 -0
 - data/test/test_repeater_hour.rb +68 -0
 - data/test/test_repeater_minute.rb +34 -0
 - data/test/test_repeater_month.rb +50 -0
 - data/test/test_repeater_month_name.rb +56 -0
 - data/test/test_repeater_season.rb +40 -0
 - data/test/test_repeater_time.rb +70 -0
 - data/test/test_repeater_week.rb +62 -0
 - data/test/test_repeater_weekday.rb +55 -0
 - data/test/test_repeater_weekend.rb +74 -0
 - data/test/test_repeater_year.rb +69 -0
 - data/test/test_span.rb +23 -0
 - data/test/test_token.rb +25 -0
 - metadata +156 -0
 
    
        data/HISTORY.md
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) Tom Preston-Werner
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 13 
     | 
    
         
            +
            all copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
      
 21 
     | 
    
         
            +
            THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,180 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
            =======
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            ## DESCRIPTION
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            Chronic is a natural language date/time parser written in pure Ruby. See below
         
     | 
| 
      
 7 
     | 
    
         
            +
            for the wide variety of formats Chronic will parse.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ## INSTALLATION
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            ### RubyGems
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                $ [sudo] gem install chronic
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            ### GitHub
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                $ git clone git://github.com/mojombo/chronic.git
         
     | 
| 
      
 19 
     | 
    
         
            +
                $ cd chronic && gem build chronic.gemspec
         
     | 
| 
      
 20 
     | 
    
         
            +
                $ gem install chronic-<version>.gem
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ## USAGE
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            You can parse strings containing a natural language date using the
         
     | 
| 
      
 26 
     | 
    
         
            +
            `Chronic.parse` method.
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                require 'chronic'
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                Time.now   #=> Sun Aug 27 23:18:25 PDT 2006
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                Chronic.parse('tomorrow')
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #=> Mon Aug 28 12:00:00 PDT 2006
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                Chronic.parse('monday', :context => :past)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #=> Mon Aug 21 12:00:00 PDT 2006
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                Chronic.parse('this tuesday 5:00')
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #=> Tue Aug 29 17:00:00 PDT 2006
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                Chronic.parse('this tuesday 5:00', :ambiguous_time_range => :none)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #=> Tue Aug 29 05:00:00 PDT 2006
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                Chronic.parse('may 27th', :now => Time.local(2000, 1, 1))
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #=> Sat May 27 12:00:00 PDT 2000
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                Chronic.parse('may 27th', :guess => false)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
         
     | 
| 
      
 49 
     | 
    
         
            +
                  
         
     | 
| 
      
 50 
     | 
    
         
            +
                Chronic.parse('6/4/2012', :endian_precedence => :little)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #=> Fri Apr 06 00:00:00 PDT 2012
         
     | 
| 
      
 52 
     | 
    
         
            +
                  
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            See `Chronic.parse` for detailed usage instructions.
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            ## EXAMPLES
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            Chronic can parse a huge variety of date and time formats. Following is a
         
     | 
| 
      
 60 
     | 
    
         
            +
            small sample of strings that will be properly parsed. Parsing is case
         
     | 
| 
      
 61 
     | 
    
         
            +
            insensitive and will handle common abbreviations and misspellings.
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Simple
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            * thursday
         
     | 
| 
      
 66 
     | 
    
         
            +
            * november
         
     | 
| 
      
 67 
     | 
    
         
            +
            * summer
         
     | 
| 
      
 68 
     | 
    
         
            +
            * friday 13:00
         
     | 
| 
      
 69 
     | 
    
         
            +
            * mon 2:35
         
     | 
| 
      
 70 
     | 
    
         
            +
            * 4pm
         
     | 
| 
      
 71 
     | 
    
         
            +
            * 6 in the morning
         
     | 
| 
      
 72 
     | 
    
         
            +
            * friday 1pm
         
     | 
| 
      
 73 
     | 
    
         
            +
            * sat 7 in the evening
         
     | 
| 
      
 74 
     | 
    
         
            +
            * yesterday
         
     | 
| 
      
 75 
     | 
    
         
            +
            * today
         
     | 
| 
      
 76 
     | 
    
         
            +
            * tomorrow
         
     | 
| 
      
 77 
     | 
    
         
            +
            * this tuesday
         
     | 
| 
      
 78 
     | 
    
         
            +
            * next month
         
     | 
| 
      
 79 
     | 
    
         
            +
            * last winter
         
     | 
| 
      
 80 
     | 
    
         
            +
            * this morning
         
     | 
| 
      
 81 
     | 
    
         
            +
            * last night
         
     | 
| 
      
 82 
     | 
    
         
            +
            * this second
         
     | 
| 
      
 83 
     | 
    
         
            +
            * yesterday at 4:00
         
     | 
| 
      
 84 
     | 
    
         
            +
            * last friday at 20:00
         
     | 
| 
      
 85 
     | 
    
         
            +
            * last week tuesday
         
     | 
| 
      
 86 
     | 
    
         
            +
            * tomorrow at 6:45pm
         
     | 
| 
      
 87 
     | 
    
         
            +
            * afternoon yesterday
         
     | 
| 
      
 88 
     | 
    
         
            +
            * thursday last week
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
            Complex
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            * 3 years ago
         
     | 
| 
      
 93 
     | 
    
         
            +
            * 5 months before now
         
     | 
| 
      
 94 
     | 
    
         
            +
            * 7 hours ago
         
     | 
| 
      
 95 
     | 
    
         
            +
            * 7 days from now
         
     | 
| 
      
 96 
     | 
    
         
            +
            * 1 week hence
         
     | 
| 
      
 97 
     | 
    
         
            +
            * in 3 hours
         
     | 
| 
      
 98 
     | 
    
         
            +
            * 1 year ago tomorrow
         
     | 
| 
      
 99 
     | 
    
         
            +
            * 3 months ago saturday at 5:00 pm
         
     | 
| 
      
 100 
     | 
    
         
            +
            * 7 hours before tomorrow at noon
         
     | 
| 
      
 101 
     | 
    
         
            +
            * 3rd wednesday in november
         
     | 
| 
      
 102 
     | 
    
         
            +
            * 3rd month next year
         
     | 
| 
      
 103 
     | 
    
         
            +
            * 3rd thursday this september
         
     | 
| 
      
 104 
     | 
    
         
            +
            * 4th day last week
         
     | 
| 
      
 105 
     | 
    
         
            +
            * fourteenth of june 2010 at eleven o'clock in the evening
         
     | 
| 
      
 106 
     | 
    
         
            +
            * may seventh '97 at three in the morning
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
            Specific Dates
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            * January 5
         
     | 
| 
      
 111 
     | 
    
         
            +
            * 22nd of june
         
     | 
| 
      
 112 
     | 
    
         
            +
            * 5th may 2017
         
     | 
| 
      
 113 
     | 
    
         
            +
            * February twenty first
         
     | 
| 
      
 114 
     | 
    
         
            +
            * dec 25
         
     | 
| 
      
 115 
     | 
    
         
            +
            * may 27th
         
     | 
| 
      
 116 
     | 
    
         
            +
            * October 2006
         
     | 
| 
      
 117 
     | 
    
         
            +
            * oct 06
         
     | 
| 
      
 118 
     | 
    
         
            +
            * jan 3 2010
         
     | 
| 
      
 119 
     | 
    
         
            +
            * february 14, 2004
         
     | 
| 
      
 120 
     | 
    
         
            +
            * february 14th, 2004
         
     | 
| 
      
 121 
     | 
    
         
            +
            * 3 jan 2000
         
     | 
| 
      
 122 
     | 
    
         
            +
            * 17 april 85
         
     | 
| 
      
 123 
     | 
    
         
            +
            * 5/27/1979
         
     | 
| 
      
 124 
     | 
    
         
            +
            * 27/5/1979
         
     | 
| 
      
 125 
     | 
    
         
            +
            * 05/06
         
     | 
| 
      
 126 
     | 
    
         
            +
            * 1979-05-27
         
     | 
| 
      
 127 
     | 
    
         
            +
            * Friday
         
     | 
| 
      
 128 
     | 
    
         
            +
            * 5
         
     | 
| 
      
 129 
     | 
    
         
            +
            * 4:00
         
     | 
| 
      
 130 
     | 
    
         
            +
            * 17:00
         
     | 
| 
      
 131 
     | 
    
         
            +
            * 0800
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
            Specific Times (many of the above with an added time)
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            * January 5 at 7pm
         
     | 
| 
      
 136 
     | 
    
         
            +
            * 22nd of june at 8am
         
     | 
| 
      
 137 
     | 
    
         
            +
            * 1979-05-27 05:00:00
         
     | 
| 
      
 138 
     | 
    
         
            +
            * etc
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
            ## TIME ZONES
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            Chronic allows you to set which Time class to use when constructing times. By
         
     | 
| 
      
 144 
     | 
    
         
            +
            default, the built in Ruby time class creates times in your system's local
         
     | 
| 
      
 145 
     | 
    
         
            +
            time zone. You can set this to something like ActiveSupport's
         
     | 
| 
      
 146 
     | 
    
         
            +
            [TimeZone](http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html)
         
     | 
| 
      
 147 
     | 
    
         
            +
            class to get full time zone support.
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                >> Time.zone = "UTC"
         
     | 
| 
      
 150 
     | 
    
         
            +
                >> Chronic.time_class = Time.zone
         
     | 
| 
      
 151 
     | 
    
         
            +
                >> Chronic.parse("June 15 2006 at 5:45 AM")
         
     | 
| 
      
 152 
     | 
    
         
            +
                => Thu, 15 Jun 2006 05:45:00 UTC +00:00
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            ## LIMITATIONS
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            Chronic uses Ruby's built in Time class for all time storage and computation.
         
     | 
| 
      
 158 
     | 
    
         
            +
            Because of this, only times that the Time class can handle will be properly
         
     | 
| 
      
 159 
     | 
    
         
            +
            parsed. Parsing for times outside of this range will simply return nil.
         
     | 
| 
      
 160 
     | 
    
         
            +
            Support for a wider range of times is planned for a future release.
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
            ## CONTRIBUTE
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
            If you'd like to hack on Chronic, start by forking the repo on GitHub:
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
            https://github.com/mojombo/chronic
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            The best way to get your changes merged back into core is as follows:
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            1. Clone down your fork
         
     | 
| 
      
 172 
     | 
    
         
            +
            1. Create a thoughtfully named topic branch to contain your change
         
     | 
| 
      
 173 
     | 
    
         
            +
            1. Hack away
         
     | 
| 
      
 174 
     | 
    
         
            +
            1. Add tests and make sure everything still passes by running `rake`
         
     | 
| 
      
 175 
     | 
    
         
            +
            1. Ensure your tests pass in multiple timezones. ie `TZ=utc rake` `TZ=BST rake`
         
     | 
| 
      
 176 
     | 
    
         
            +
            1. If you are adding new functionality, document it in the README
         
     | 
| 
      
 177 
     | 
    
         
            +
            1. Do not change the version number, we will do that on our end
         
     | 
| 
      
 178 
     | 
    
         
            +
            1. If necessary, rebase your commits into logical chunks, without errors
         
     | 
| 
      
 179 
     | 
    
         
            +
            1. Push the branch up to GitHub
         
     | 
| 
      
 180 
     | 
    
         
            +
            1. Send a pull request for your branch
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'date'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            def version
         
     | 
| 
      
 4 
     | 
    
         
            +
              contents = File.read File.expand_path('../lib/chronic.rb', __FILE__)
         
     | 
| 
      
 5 
     | 
    
         
            +
              contents[/VERSION = "([^"]+)"/, 1]
         
     | 
| 
      
 6 
     | 
    
         
            +
            end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            task :test do
         
     | 
| 
      
 9 
     | 
    
         
            +
              $:.unshift './test'
         
     | 
| 
      
 10 
     | 
    
         
            +
              Dir.glob('test/test_*.rb').each { |t| require File.basename(t) }
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            desc "Generate RCov test coverage and open in your browser"
         
     | 
| 
      
 14 
     | 
    
         
            +
            task :coverage do
         
     | 
| 
      
 15 
     | 
    
         
            +
              require 'rcov'
         
     | 
| 
      
 16 
     | 
    
         
            +
              sh "rm -fr coverage"
         
     | 
| 
      
 17 
     | 
    
         
            +
              sh "rcov test/test_*.rb"
         
     | 
| 
      
 18 
     | 
    
         
            +
              sh "open coverage/index.html"
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            desc "Open an irb session preloaded with this library"
         
     | 
| 
      
 22 
     | 
    
         
            +
            task :console do
         
     | 
| 
      
 23 
     | 
    
         
            +
              sh "irb -Ilib -rchronic"
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            desc "Release Chronic version #{version}"
         
     | 
| 
      
 27 
     | 
    
         
            +
            task :release => :build do
         
     | 
| 
      
 28 
     | 
    
         
            +
              unless `git branch` =~ /^\* master$/
         
     | 
| 
      
 29 
     | 
    
         
            +
                puts "You must be on the master branch to release!"
         
     | 
| 
      
 30 
     | 
    
         
            +
                exit!
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
              sh "git commit --allow-empty -a -m 'Release #{version}'"
         
     | 
| 
      
 33 
     | 
    
         
            +
              sh "git tag v#{version}"
         
     | 
| 
      
 34 
     | 
    
         
            +
              sh "git push origin master"
         
     | 
| 
      
 35 
     | 
    
         
            +
              sh "git push origin v#{version}"
         
     | 
| 
      
 36 
     | 
    
         
            +
              sh "gem push pkg/chronic-#{version}.gem"
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            desc "Build a gem from the gemspec"
         
     | 
| 
      
 40 
     | 
    
         
            +
            task :build do
         
     | 
| 
      
 41 
     | 
    
         
            +
              sh "mkdir -p pkg"
         
     | 
| 
      
 42 
     | 
    
         
            +
              sh "gem build chronic.gemspec"
         
     | 
| 
      
 43 
     | 
    
         
            +
              sh "mv chronic_2011-#{version}.gem pkg"
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            task :default => :test
         
     | 
    
        data/chronic.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'chronic'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 5 
     | 
    
         
            +
              s.name = 'chronic_2011'
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.version = Chronic::VERSION
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.date = '2012-05-16'
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.summary     = 'Natural language date/time parsing'
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.description = 'The original Chronic gem is a natural language date/time parser written in pure Ruby. This gem, Chronic 2011, returns a Date or Time depending on the user input.'
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.authors  = ['Jason Lew']
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.rdoc_options = ['--charset=UTF-8']
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.extra_rdoc_files = %w[README.md HISTORY.md LICENSE]
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.files = `git ls-files`.split("\n")
         
     | 
| 
      
 14 
     | 
    
         
            +
              s.test_files = `git ls-files -- test`.split("\n")
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              s.add_development_dependency 'rake'
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.add_development_dependency 'minitest'
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/chronic.rb
    ADDED
    
    | 
         @@ -0,0 +1,117 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'time'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'date'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            # Parse natural language dates and times into Time or Chronic::Span objects.
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # Examples:
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   require 'chronic'
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            #   Time.now   #=> Sun Aug 27 23:18:25 PDT 2006
         
     | 
| 
      
 11 
     | 
    
         
            +
            #
         
     | 
| 
      
 12 
     | 
    
         
            +
            #   Chronic.parse('tomorrow')
         
     | 
| 
      
 13 
     | 
    
         
            +
            #     #=> Mon Aug 28 12:00:00 PDT 2006
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            #   Chronic.parse('monday', :context => :past)
         
     | 
| 
      
 16 
     | 
    
         
            +
            #     #=> Mon Aug 21 12:00:00 PDT 2006
         
     | 
| 
      
 17 
     | 
    
         
            +
            #
         
     | 
| 
      
 18 
     | 
    
         
            +
            #   Chronic.parse('this tuesday 5:00')
         
     | 
| 
      
 19 
     | 
    
         
            +
            #     #=> Tue Aug 29 17:00:00 PDT 2006
         
     | 
| 
      
 20 
     | 
    
         
            +
            #
         
     | 
| 
      
 21 
     | 
    
         
            +
            #   Chronic.parse('this tuesday 5:00', :ambiguous_time_range => :none)
         
     | 
| 
      
 22 
     | 
    
         
            +
            #     #=> Tue Aug 29 05:00:00 PDT 2006
         
     | 
| 
      
 23 
     | 
    
         
            +
            #
         
     | 
| 
      
 24 
     | 
    
         
            +
            #   Chronic.parse('may 27th', :now => Time.local(2000, 1, 1))
         
     | 
| 
      
 25 
     | 
    
         
            +
            #     #=> Sat May 27 12:00:00 PDT 2000
         
     | 
| 
      
 26 
     | 
    
         
            +
            #
         
     | 
| 
      
 27 
     | 
    
         
            +
            #   Chronic.parse('may 27th', :guess => false)
         
     | 
| 
      
 28 
     | 
    
         
            +
            #     #=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
         
     | 
| 
      
 29 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 30 
     | 
    
         
            +
              VERSION = "0.1.0"
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # Returns true when debug mode is enabled.
         
     | 
| 
      
 35 
     | 
    
         
            +
                attr_accessor :debug
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                # Examples:
         
     | 
| 
      
 38 
     | 
    
         
            +
                #
         
     | 
| 
      
 39 
     | 
    
         
            +
                #   require 'chronic'
         
     | 
| 
      
 40 
     | 
    
         
            +
                #   require 'active_support/time'
         
     | 
| 
      
 41 
     | 
    
         
            +
                #
         
     | 
| 
      
 42 
     | 
    
         
            +
                #   Time.zone = 'UTC'
         
     | 
| 
      
 43 
     | 
    
         
            +
                #   Chronic.time_class = Time.zone
         
     | 
| 
      
 44 
     | 
    
         
            +
                #   Chronic.parse('June 15 2006 at 5:54 AM')
         
     | 
| 
      
 45 
     | 
    
         
            +
                #     # => Thu, 15 Jun 2006 05:45:00 UTC +00:00
         
     | 
| 
      
 46 
     | 
    
         
            +
                #
         
     | 
| 
      
 47 
     | 
    
         
            +
                # Returns The Time class Chronic uses internally.
         
     | 
| 
      
 48 
     | 
    
         
            +
                attr_accessor :time_class
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                # The current Time Chronic is using to base from.
         
     | 
| 
      
 51 
     | 
    
         
            +
                #
         
     | 
| 
      
 52 
     | 
    
         
            +
                # Examples:
         
     | 
| 
      
 53 
     | 
    
         
            +
                #
         
     | 
| 
      
 54 
     | 
    
         
            +
                #   Time.now #=> 2011-06-06 14:13:43 +0100
         
     | 
| 
      
 55 
     | 
    
         
            +
                #   Chronic.parse('yesterday') #=> 2011-06-05 12:00:00 +0100
         
     | 
| 
      
 56 
     | 
    
         
            +
                #
         
     | 
| 
      
 57 
     | 
    
         
            +
                #   now = Time.local(2025, 12, 24)
         
     | 
| 
      
 58 
     | 
    
         
            +
                #   Chronic.parse('tomorrow', :now => now) #=> 2025-12-25 12:00:00 +0000
         
     | 
| 
      
 59 
     | 
    
         
            +
                #
         
     | 
| 
      
 60 
     | 
    
         
            +
                # Returns a Time object.
         
     | 
| 
      
 61 
     | 
    
         
            +
                attr_accessor :now
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              self.debug = true #jlew
         
     | 
| 
      
 65 
     | 
    
         
            +
              self.time_class = Time
         
     | 
| 
      
 66 
     | 
    
         
            +
              
         
     | 
| 
      
 67 
     | 
    
         
            +
              autoload :Handler, 'chronic/handler'
         
     | 
| 
      
 68 
     | 
    
         
            +
              autoload :Handlers, 'chronic/handlers'
         
     | 
| 
      
 69 
     | 
    
         
            +
              autoload :MiniDate, 'chronic/mini_date'
         
     | 
| 
      
 70 
     | 
    
         
            +
              autoload :Tag, 'chronic/tag'
         
     | 
| 
      
 71 
     | 
    
         
            +
              autoload :Span, 'chronic/span'
         
     | 
| 
      
 72 
     | 
    
         
            +
              autoload :Token, 'chronic/token'
         
     | 
| 
      
 73 
     | 
    
         
            +
              autoload :Grabber, 'chronic/grabber'
         
     | 
| 
      
 74 
     | 
    
         
            +
              autoload :Pointer, 'chronic/pointer'
         
     | 
| 
      
 75 
     | 
    
         
            +
              autoload :Scalar, 'chronic/scalar'
         
     | 
| 
      
 76 
     | 
    
         
            +
              autoload :Ordinal, 'chronic/ordinal'
         
     | 
| 
      
 77 
     | 
    
         
            +
              autoload :OrdinalDay, 'chronic/ordinal'
         
     | 
| 
      
 78 
     | 
    
         
            +
              autoload :Separator, 'chronic/separator'
         
     | 
| 
      
 79 
     | 
    
         
            +
              autoload :TimeZone, 'chronic/time_zone'
         
     | 
| 
      
 80 
     | 
    
         
            +
              autoload :Numerizer, 'chronic/numerizer'
         
     | 
| 
      
 81 
     | 
    
         
            +
              autoload :Season, 'chronic/season'
         
     | 
| 
      
 82 
     | 
    
         
            +
              
         
     | 
| 
      
 83 
     | 
    
         
            +
              autoload :Repeater, 'chronic/repeater'
         
     | 
| 
      
 84 
     | 
    
         
            +
              autoload :RepeaterYear, 'chronic/repeaters/repeater_year'
         
     | 
| 
      
 85 
     | 
    
         
            +
              autoload :RepeaterSeason, 'chronic/repeaters/repeater_season'
         
     | 
| 
      
 86 
     | 
    
         
            +
              autoload :RepeaterSeasonName, 'chronic/repeaters/repeater_season_name'
         
     | 
| 
      
 87 
     | 
    
         
            +
              autoload :RepeaterMonth, 'chronic/repeaters/repeater_month'
         
     | 
| 
      
 88 
     | 
    
         
            +
              autoload :RepeaterMonthName, 'chronic/repeaters/repeater_month_name'
         
     | 
| 
      
 89 
     | 
    
         
            +
              autoload :RepeaterFortnight, 'chronic/repeaters/repeater_fortnight'
         
     | 
| 
      
 90 
     | 
    
         
            +
              autoload :RepeaterWeek, 'chronic/repeaters/repeater_week'
         
     | 
| 
      
 91 
     | 
    
         
            +
              autoload :RepeaterWeekend, 'chronic/repeaters/repeater_weekend'
         
     | 
| 
      
 92 
     | 
    
         
            +
              autoload :RepeaterWeekday, 'chronic/repeaters/repeater_weekday'
         
     | 
| 
      
 93 
     | 
    
         
            +
              autoload :RepeaterDay, 'chronic/repeaters/repeater_day'
         
     | 
| 
      
 94 
     | 
    
         
            +
              autoload :RepeaterDayName, 'chronic/repeaters/repeater_day_name'
         
     | 
| 
      
 95 
     | 
    
         
            +
              autoload :RepeaterDayPortion, 'chronic/repeaters/repeater_day_portion'
         
     | 
| 
      
 96 
     | 
    
         
            +
              autoload :RepeaterHour, 'chronic/repeaters/repeater_hour'
         
     | 
| 
      
 97 
     | 
    
         
            +
              autoload :RepeaterMinute, 'chronic/repeaters/repeater_minute'
         
     | 
| 
      
 98 
     | 
    
         
            +
              autoload :RepeaterSecond, 'chronic/repeaters/repeater_second'
         
     | 
| 
      
 99 
     | 
    
         
            +
              autoload :RepeaterTime, 'chronic/repeaters/repeater_time'
         
     | 
| 
      
 100 
     | 
    
         
            +
              
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            require 'chronic/chronic'
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            class Time
         
     | 
| 
      
 106 
     | 
    
         
            +
              
         
     | 
| 
      
 107 
     | 
    
         
            +
              def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
         
     | 
| 
      
 108 
     | 
    
         
            +
                warn "Time.construct will be deprecated in version 0.7.0. Please use Chronic.construct instead"
         
     | 
| 
      
 109 
     | 
    
         
            +
                Chronic.construct(year, month, day, hour, minute, second)
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              def to_minidate
         
     | 
| 
      
 113 
     | 
    
         
            +
                warn "Time.to_minidate will be deprecated in version 0.7.0. Please use Chronic::MiniDate.from_time(time) instead"
         
     | 
| 
      
 114 
     | 
    
         
            +
                Chronic::MiniDate.from_time(self)
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
              
         
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,346 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # Returns a Hash of default configuration options.
         
     | 
| 
      
 4 
     | 
    
         
            +
              DEFAULT_OPTIONS = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                :context => :future,
         
     | 
| 
      
 6 
     | 
    
         
            +
                :now => nil,
         
     | 
| 
      
 7 
     | 
    
         
            +
                :guess => true,
         
     | 
| 
      
 8 
     | 
    
         
            +
                :ambiguous_time_range => 6,
         
     | 
| 
      
 9 
     | 
    
         
            +
                :endian_precedence    => [:middle, :little],
         
     | 
| 
      
 10 
     | 
    
         
            +
                :ambiguous_year_future_bias => 50
         
     | 
| 
      
 11 
     | 
    
         
            +
              }
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
              SEC_PER_DAY = 86400
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                # Parses a string containing a natural language date or time.
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                # If the parser can find a date or time, either a Time or Chronic::Span
         
     | 
| 
      
 20 
     | 
    
         
            +
                # will be returned (depending on the value of `:guess`). If no
         
     | 
| 
      
 21 
     | 
    
         
            +
                # date or time can be found, `nil` will be returned.
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                # text - The String text to parse.
         
     | 
| 
      
 24 
     | 
    
         
            +
                # opts - An optional Hash of configuration options:
         
     | 
| 
      
 25 
     | 
    
         
            +
                #        :context - If your string represents a birthday, you can set
         
     | 
| 
      
 26 
     | 
    
         
            +
                #                   this value to :past and if an ambiguous string is
         
     | 
| 
      
 27 
     | 
    
         
            +
                #                   given, it will assume it is in the past.
         
     | 
| 
      
 28 
     | 
    
         
            +
                #        :now - Time, all computations will be based off of time
         
     | 
| 
      
 29 
     | 
    
         
            +
                #               instead of Time.now.
         
     | 
| 
      
 30 
     | 
    
         
            +
                #        :guess - By default the parser will guess a single point in time
         
     | 
| 
      
 31 
     | 
    
         
            +
                #                 for the given date or time. If you'd rather have the
         
     | 
| 
      
 32 
     | 
    
         
            +
                #                 entire time span returned, set this to false
         
     | 
| 
      
 33 
     | 
    
         
            +
                #                 and a Chronic::Span will be returned.
         
     | 
| 
      
 34 
     | 
    
         
            +
                #        :ambiguous_time_range - If an Integer is given, ambiguous times
         
     | 
| 
      
 35 
     | 
    
         
            +
                #                  (like 5:00) will be assumed to be within the range of
         
     | 
| 
      
 36 
     | 
    
         
            +
                #                  that time in the AM to that time in the PM. For
         
     | 
| 
      
 37 
     | 
    
         
            +
                #                  example, if you set it to `7`, then the parser will
         
     | 
| 
      
 38 
     | 
    
         
            +
                #                  look for the time between 7am and 7pm. In the case of
         
     | 
| 
      
 39 
     | 
    
         
            +
                #                  5:00, it would assume that means 5:00pm. If `:none`
         
     | 
| 
      
 40 
     | 
    
         
            +
                #                  is given, no assumption will be made, and the first
         
     | 
| 
      
 41 
     | 
    
         
            +
                #                  matching instance of that time will be used.
         
     | 
| 
      
 42 
     | 
    
         
            +
                #        :endian_precedence - By default, Chronic will parse "03/04/2011"
         
     | 
| 
      
 43 
     | 
    
         
            +
                #                 as the fourth day of the third month. Alternatively you
         
     | 
| 
      
 44 
     | 
    
         
            +
                #                 can tell Chronic to parse this as the third day of the
         
     | 
| 
      
 45 
     | 
    
         
            +
                #                 fourth month by setting this to [:little, :middle].
         
     | 
| 
      
 46 
     | 
    
         
            +
                #        :ambiguous_year_future_bias - When parsing two digit years
         
     | 
| 
      
 47 
     | 
    
         
            +
                #                 (ie 79) unlike Rubys Time class, Chronic will attempt
         
     | 
| 
      
 48 
     | 
    
         
            +
                #                 to assume the full year using this figure. Chronic will
         
     | 
| 
      
 49 
     | 
    
         
            +
                #                 look x amount of years into the future and past. If the
         
     | 
| 
      
 50 
     | 
    
         
            +
                #                 two digit year is `now + x years` it's assumed to be the
         
     | 
| 
      
 51 
     | 
    
         
            +
                #                 future, `now - x years` is assumed to be the past.
         
     | 
| 
      
 52 
     | 
    
         
            +
                #
         
     | 
| 
      
 53 
     | 
    
         
            +
                # Returns a new Time object, or Chronic::Span if :guess option is false.
         
     | 
| 
      
 54 
     | 
    
         
            +
                def parse(text, opts={})
         
     | 
| 
      
 55 
     | 
    
         
            +
                  puts "THE CHRONIC!!!"
         
     | 
| 
      
 56 
     | 
    
         
            +
                  
         
     | 
| 
      
 57 
     | 
    
         
            +
                  options = DEFAULT_OPTIONS.merge opts
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  # ensure the specified options are valid
         
     | 
| 
      
 60 
     | 
    
         
            +
                  (opts.keys - DEFAULT_OPTIONS.keys).each do |key|
         
     | 
| 
      
 61 
     | 
    
         
            +
                    raise ArgumentError, "#{key} is not a valid option key."
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  unless [:past, :future, :none].include?(options[:context])
         
     | 
| 
      
 65 
     | 
    
         
            +
                    raise ArgumentError, "Invalid context, :past/:future only"
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  options[:text] = text
         
     | 
| 
      
 69 
     | 
    
         
            +
                  Chronic.now = options[:now] || Chronic.time_class.now
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  # tokenize words
         
     | 
| 
      
 72 
     | 
    
         
            +
                  tokens = tokenize(text, options)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  
         
     | 
| 
      
 74 
     | 
    
         
            +
                  puts "tokens: #{tokens}"  #jlew
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  if Chronic.debug
         
     | 
| 
      
 77 
     | 
    
         
            +
                    puts "+#{'-' * 51}\n| #{tokens}\n+#{'-' * 51}"
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  span = tokens_to_span(tokens, options)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  
         
     | 
| 
      
 82 
     | 
    
         
            +
                  puts "span: #{span}"
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  if span
         
     | 
| 
      
 85 
     | 
    
         
            +
                    options[:guess] ? guess(span) : span
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                # Clean up the specified text ready for parsing.
         
     | 
| 
      
 90 
     | 
    
         
            +
                #
         
     | 
| 
      
 91 
     | 
    
         
            +
                # Clean up the string by stripping unwanted characters, converting
         
     | 
| 
      
 92 
     | 
    
         
            +
                # idioms to their canonical form, converting number words to numbers
         
     | 
| 
      
 93 
     | 
    
         
            +
                # (three => 3), and converting ordinal words to numeric
         
     | 
| 
      
 94 
     | 
    
         
            +
                # ordinals (third => 3rd)
         
     | 
| 
      
 95 
     | 
    
         
            +
                #
         
     | 
| 
      
 96 
     | 
    
         
            +
                # text - The String text to normalize.
         
     | 
| 
      
 97 
     | 
    
         
            +
                #
         
     | 
| 
      
 98 
     | 
    
         
            +
                # Examples:
         
     | 
| 
      
 99 
     | 
    
         
            +
                #
         
     | 
| 
      
 100 
     | 
    
         
            +
                #   Chronic.pre_normalize('first day in May')
         
     | 
| 
      
 101 
     | 
    
         
            +
                #     #=> "1st day in may"
         
     | 
| 
      
 102 
     | 
    
         
            +
                #
         
     | 
| 
      
 103 
     | 
    
         
            +
                #   Chronic.pre_normalize('tomorrow after noon')
         
     | 
| 
      
 104 
     | 
    
         
            +
                #     #=> "next day future 12:00"
         
     | 
| 
      
 105 
     | 
    
         
            +
                #
         
     | 
| 
      
 106 
     | 
    
         
            +
                #   Chronic.pre_normalize('one hundred and thirty six days from now')
         
     | 
| 
      
 107 
     | 
    
         
            +
                #     #=> "136 days future this second"
         
     | 
| 
      
 108 
     | 
    
         
            +
                #
         
     | 
| 
      
 109 
     | 
    
         
            +
                # Returns a new String ready for Chronic to parse.
         
     | 
| 
      
 110 
     | 
    
         
            +
                def pre_normalize(text)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  text = text.to_s.downcase
         
     | 
| 
      
 112 
     | 
    
         
            +
                  text.gsub!(/\./, ':')
         
     | 
| 
      
 113 
     | 
    
         
            +
                  text.gsub!(/['"]/, '')
         
     | 
| 
      
 114 
     | 
    
         
            +
                  text.gsub!(/,/, ' ')
         
     | 
| 
      
 115 
     | 
    
         
            +
                  text.gsub!(/\bsecond (of|day|month|hour|minute|second)\b/, '2nd \1')
         
     | 
| 
      
 116 
     | 
    
         
            +
                  text = Numerizer.numerize(text)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  text.gsub!(/ \-(\d{4})\b/, ' tzminus\1')
         
     | 
| 
      
 118 
     | 
    
         
            +
                  text.gsub!(/([\/\-\,\@])/) { ' ' + $1 + ' ' }
         
     | 
| 
      
 119 
     | 
    
         
            +
                  text.gsub!(/(?:^|\s)0(\d+:\d+\s*pm?\b)/, '\1')
         
     | 
| 
      
 120 
     | 
    
         
            +
                  text.gsub!(/\btoday\b/, 'this day')
         
     | 
| 
      
 121 
     | 
    
         
            +
                  text.gsub!(/\btomm?orr?ow\b/, 'next day')
         
     | 
| 
      
 122 
     | 
    
         
            +
                  text.gsub!(/\byesterday\b/, 'last day')
         
     | 
| 
      
 123 
     | 
    
         
            +
                  text.gsub!(/\bnoon\b/, '12:00pm')
         
     | 
| 
      
 124 
     | 
    
         
            +
                  text.gsub!(/\bmidnight\b/, '24:00')
         
     | 
| 
      
 125 
     | 
    
         
            +
                  text.gsub!(/\bnow\b/, 'this second')
         
     | 
| 
      
 126 
     | 
    
         
            +
                  text.gsub!(/\b(?:ago|before(?: now)?)\b/, 'past')
         
     | 
| 
      
 127 
     | 
    
         
            +
                  text.gsub!(/\bthis (?:last|past)\b/, 'last')
         
     | 
| 
      
 128 
     | 
    
         
            +
                  text.gsub!(/\b(?:in|during) the (morning)\b/, '\1')
         
     | 
| 
      
 129 
     | 
    
         
            +
                  text.gsub!(/\b(?:in the|during the|at) (afternoon|evening|night)\b/, '\1')
         
     | 
| 
      
 130 
     | 
    
         
            +
                  text.gsub!(/\btonight\b/, 'this night')
         
     | 
| 
      
 131 
     | 
    
         
            +
                  text.gsub!(/\b\d+:?\d*[ap]\b/,'\0m')
         
     | 
| 
      
 132 
     | 
    
         
            +
                  text.gsub!(/(\d)([ap]m|oclock)\b/, '\1 \2')
         
     | 
| 
      
 133 
     | 
    
         
            +
                  text.gsub!(/\b(hence|after|from)\b/, 'future')
         
     | 
| 
      
 134 
     | 
    
         
            +
                  text
         
     | 
| 
      
 135 
     | 
    
         
            +
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                # Convert number words to numbers (three => 3, fourth => 4th).
         
     | 
| 
      
 138 
     | 
    
         
            +
                #
         
     | 
| 
      
 139 
     | 
    
         
            +
                # text - The String to convert.
         
     | 
| 
      
 140 
     | 
    
         
            +
                #
         
     | 
| 
      
 141 
     | 
    
         
            +
                # Returns a new String with words converted to numbers.
         
     | 
| 
      
 142 
     | 
    
         
            +
                def numericize_numbers(text)
         
     | 
| 
      
 143 
     | 
    
         
            +
                  warn "Chronic.numericize_numbers will be deprecated in version 0.7.0. Please use Chronic::Numerizer.numerize instead"
         
     | 
| 
      
 144 
     | 
    
         
            +
                  Numerizer.numerize(text)
         
     | 
| 
      
 145 
     | 
    
         
            +
                end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                # Guess a specific time within the given span.
         
     | 
| 
      
 148 
     | 
    
         
            +
                #
         
     | 
| 
      
 149 
     | 
    
         
            +
                # span - The Chronic::Span object to calcuate a guess from.
         
     | 
| 
      
 150 
     | 
    
         
            +
                #
         
     | 
| 
      
 151 
     | 
    
         
            +
                # Returns a new Time object or a new Date object
         
     | 
| 
      
 152 
     | 
    
         
            +
                def guess(span)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  if span.width > 1
         
     | 
| 
      
 154 
     | 
    
         
            +
                    if span.width == SEC_PER_DAY
         
     | 
| 
      
 155 
     | 
    
         
            +
                      (span.begin + (span.width / 2)).to_date
         
     | 
| 
      
 156 
     | 
    
         
            +
                    else
         
     | 
| 
      
 157 
     | 
    
         
            +
                      span.begin + (span.width / 2)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  else
         
     | 
| 
      
 160 
     | 
    
         
            +
                    span.begin
         
     | 
| 
      
 161 
     | 
    
         
            +
                  end
         
     | 
| 
      
 162 
     | 
    
         
            +
                end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                # List of Handler definitions. See #parse for a list of options this
         
     | 
| 
      
 165 
     | 
    
         
            +
                # method accepts.
         
     | 
| 
      
 166 
     | 
    
         
            +
                #
         
     | 
| 
      
 167 
     | 
    
         
            +
                # options - An optional Hash of configuration options:
         
     | 
| 
      
 168 
     | 
    
         
            +
                #           :endian_precedence -
         
     | 
| 
      
 169 
     | 
    
         
            +
                #
         
     | 
| 
      
 170 
     | 
    
         
            +
                # Returns A Hash of Handler definitions.
         
     | 
| 
      
 171 
     | 
    
         
            +
                def definitions(options={})
         
     | 
| 
      
 172 
     | 
    
         
            +
                  options[:endian_precedence] ||= [:middle, :little]
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                  @definitions ||= {
         
     | 
| 
      
 175 
     | 
    
         
            +
                    :time => [
         
     | 
| 
      
 176 
     | 
    
         
            +
                      Handler.new([:repeater_time, :repeater_day_portion?], nil)
         
     | 
| 
      
 177 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                    :date => [
         
     | 
| 
      
 180 
     | 
    
         
            +
                      Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, :separator_slash_or_dash?, :time_zone, :scalar_year], :handle_rdn_rmn_sd_t_tz_sy),
         
     | 
| 
      
 181 
     | 
    
         
            +
                      Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day], :handle_rdn_rmn_sd),
         
     | 
| 
      
 182 
     | 
    
         
            +
                      Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :scalar_year], :handle_rdn_rmn_sd_sy),
         
     | 
| 
      
 183 
     | 
    
         
            +
                      Handler.new([:repeater_day_name, :repeater_month_name, :ordinal_day], :handle_rdn_rmn_od),
         
     | 
| 
      
 184 
     | 
    
         
            +
                      Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :repeater_time, :time_zone], :handle_sy_sm_sd_t_tz),
         
     | 
| 
      
 185 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
         
     | 
| 
      
 186 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :ordinal_day, :scalar_year], :handle_rmn_od_sy),
         
     | 
| 
      
 187 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
         
     | 
| 
      
 188 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :ordinal_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_od_sy),
         
     | 
| 
      
 189 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
         
     | 
| 
      
 190 
     | 
    
         
            +
                      Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
         
     | 
| 
      
 191 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
         
     | 
| 
      
 192 
     | 
    
         
            +
                      Handler.new([:ordinal_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_od_rmn_sy),
         
     | 
| 
      
 193 
     | 
    
         
            +
                      Handler.new([:ordinal_day, :repeater_month_name, :separator_at?, 'time?'], :handle_od_rmn),
         
     | 
| 
      
 194 
     | 
    
         
            +
                      Handler.new([:scalar_year, :repeater_month_name, :ordinal_day], :handle_sy_rmn_od),
         
     | 
| 
      
 195 
     | 
    
         
            +
                      Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
         
     | 
| 
      
 196 
     | 
    
         
            +
                      Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
         
     | 
| 
      
 197 
     | 
    
         
            +
                      Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
         
     | 
| 
      
 198 
     | 
    
         
            +
                      Handler.new([:scalar_day, :repeater_month_name, :separator_at?, 'time?'], :handle_sd_rmn),
         
     | 
| 
      
 199 
     | 
    
         
            +
                      Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
         
     | 
| 
      
 200 
     | 
    
         
            +
                      Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day], :handle_sm_sd),
         
     | 
| 
      
 201 
     | 
    
         
            +
                      Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)
         
     | 
| 
      
 202 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                    # tonight at 7pm
         
     | 
| 
      
 205 
     | 
    
         
            +
                    :anchor => [
         
     | 
| 
      
 206 
     | 
    
         
            +
                      Handler.new([:grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
         
     | 
| 
      
 207 
     | 
    
         
            +
                      Handler.new([:grabber?, :repeater, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
         
     | 
| 
      
 208 
     | 
    
         
            +
                      Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)
         
     | 
| 
      
 209 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                    # 3 weeks from now, in 2 months
         
     | 
| 
      
 212 
     | 
    
         
            +
                    :arrow => [
         
     | 
| 
      
 213 
     | 
    
         
            +
                      Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
         
     | 
| 
      
 214 
     | 
    
         
            +
                      Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
         
     | 
| 
      
 215 
     | 
    
         
            +
                      Handler.new([:scalar, :repeater, :pointer, 'anchor'], :handle_s_r_p_a)
         
     | 
| 
      
 216 
     | 
    
         
            +
                    ],
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                    # 3rd week in march
         
     | 
| 
      
 219 
     | 
    
         
            +
                    :narrow => [
         
     | 
| 
      
 220 
     | 
    
         
            +
                      Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
         
     | 
| 
      
 221 
     | 
    
         
            +
                      Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)
         
     | 
| 
      
 222 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 223 
     | 
    
         
            +
                  }
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                  endians = [
         
     | 
| 
      
 226 
     | 
    
         
            +
                    Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy),
         
     | 
| 
      
 227 
     | 
    
         
            +
                    Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
         
     | 
| 
      
 228 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                  case endian = Array(options[:endian_precedence]).first
         
     | 
| 
      
 231 
     | 
    
         
            +
                  when :little
         
     | 
| 
      
 232 
     | 
    
         
            +
                    @definitions[:endian] = endians.reverse
         
     | 
| 
      
 233 
     | 
    
         
            +
                  when :middle
         
     | 
| 
      
 234 
     | 
    
         
            +
                    @definitions[:endian] = endians
         
     | 
| 
      
 235 
     | 
    
         
            +
                  else
         
     | 
| 
      
 236 
     | 
    
         
            +
                    raise ArgumentError, "Unknown endian option '#{endian}'"
         
     | 
| 
      
 237 
     | 
    
         
            +
                  end
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                  @definitions
         
     | 
| 
      
 240 
     | 
    
         
            +
                end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
                # Construct a new time object determining possible month overflows
         
     | 
| 
      
 243 
     | 
    
         
            +
                # and leap years.
         
     | 
| 
      
 244 
     | 
    
         
            +
                #
         
     | 
| 
      
 245 
     | 
    
         
            +
                # year   - Integer year.
         
     | 
| 
      
 246 
     | 
    
         
            +
                # month  - Integer month.
         
     | 
| 
      
 247 
     | 
    
         
            +
                # day    - Integer day.
         
     | 
| 
      
 248 
     | 
    
         
            +
                # hour   - Integer hour.
         
     | 
| 
      
 249 
     | 
    
         
            +
                # minute - Integer minute.
         
     | 
| 
      
 250 
     | 
    
         
            +
                # second - Integer second.
         
     | 
| 
      
 251 
     | 
    
         
            +
                #
         
     | 
| 
      
 252 
     | 
    
         
            +
                # Returns a new Time object constructed from these params.
         
     | 
| 
      
 253 
     | 
    
         
            +
                def construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
         
     | 
| 
      
 254 
     | 
    
         
            +
                  if second >= 60
         
     | 
| 
      
 255 
     | 
    
         
            +
                    minute += second / 60
         
     | 
| 
      
 256 
     | 
    
         
            +
                    second = second % 60
         
     | 
| 
      
 257 
     | 
    
         
            +
                  end
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
                  if minute >= 60
         
     | 
| 
      
 260 
     | 
    
         
            +
                    hour += minute / 60
         
     | 
| 
      
 261 
     | 
    
         
            +
                    minute = minute % 60
         
     | 
| 
      
 262 
     | 
    
         
            +
                  end
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                  if hour >= 24
         
     | 
| 
      
 265 
     | 
    
         
            +
                    day += hour / 24
         
     | 
| 
      
 266 
     | 
    
         
            +
                    hour = hour % 24
         
     | 
| 
      
 267 
     | 
    
         
            +
                  end
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                  # determine if there is a day overflow. this is complicated by our crappy calendar
         
     | 
| 
      
 270 
     | 
    
         
            +
                  # system (non-constant number of days per month)
         
     | 
| 
      
 271 
     | 
    
         
            +
                  day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
         
     | 
| 
      
 272 
     | 
    
         
            +
                  if day > 28
         
     | 
| 
      
 273 
     | 
    
         
            +
                    # no month ever has fewer than 28 days, so only do this if necessary
         
     | 
| 
      
 274 
     | 
    
         
            +
                    leap_year_month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
         
     | 
| 
      
 275 
     | 
    
         
            +
                    common_year_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
         
     | 
| 
      
 276 
     | 
    
         
            +
                    days_this_month = Date.leap?(year) ? leap_year_month_days[month - 1] : common_year_month_days[month - 1]
         
     | 
| 
      
 277 
     | 
    
         
            +
                    if day > days_this_month
         
     | 
| 
      
 278 
     | 
    
         
            +
                      month += day / days_this_month
         
     | 
| 
      
 279 
     | 
    
         
            +
                      day = day % days_this_month
         
     | 
| 
      
 280 
     | 
    
         
            +
                    end
         
     | 
| 
      
 281 
     | 
    
         
            +
                  end
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
                  if month > 12
         
     | 
| 
      
 284 
     | 
    
         
            +
                    if month % 12 == 0
         
     | 
| 
      
 285 
     | 
    
         
            +
                      year += (month - 12) / 12
         
     | 
| 
      
 286 
     | 
    
         
            +
                      month = 12
         
     | 
| 
      
 287 
     | 
    
         
            +
                    else
         
     | 
| 
      
 288 
     | 
    
         
            +
                      year += month / 12
         
     | 
| 
      
 289 
     | 
    
         
            +
                      month = month % 12
         
     | 
| 
      
 290 
     | 
    
         
            +
                    end
         
     | 
| 
      
 291 
     | 
    
         
            +
                  end
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
                  Chronic.time_class.local(year, month, day, hour, minute, second)
         
     | 
| 
      
 294 
     | 
    
         
            +
                end
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
                private
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
                def tokenize(text, options)
         
     | 
| 
      
 299 
     | 
    
         
            +
                  text = pre_normalize(text)
         
     | 
| 
      
 300 
     | 
    
         
            +
                  tokens = text.split(' ').map { |word| Token.new(word) }
         
     | 
| 
      
 301 
     | 
    
         
            +
                  [Repeater, Grabber, Pointer, Scalar, Ordinal, Separator, TimeZone].each do |tok|
         
     | 
| 
      
 302 
     | 
    
         
            +
                    tok.scan(tokens, options)
         
     | 
| 
      
 303 
     | 
    
         
            +
                  end
         
     | 
| 
      
 304 
     | 
    
         
            +
                  tokens.select { |token| token.tagged? }
         
     | 
| 
      
 305 
     | 
    
         
            +
                end
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                def tokens_to_span(tokens, options)
         
     | 
| 
      
 308 
     | 
    
         
            +
                  definitions = definitions(options)
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
                  (definitions[:endian] + definitions[:date]).each do |handler|
         
     | 
| 
      
 311 
     | 
    
         
            +
                    if handler.match(tokens, definitions)
         
     | 
| 
      
 312 
     | 
    
         
            +
                      good_tokens = tokens.select { |o| !o.get_tag Separator }
         
     | 
| 
      
 313 
     | 
    
         
            +
                      return handler.invoke(:date, good_tokens, options)
         
     | 
| 
      
 314 
     | 
    
         
            +
                    end
         
     | 
| 
      
 315 
     | 
    
         
            +
                  end
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                  definitions[:anchor].each do |handler|
         
     | 
| 
      
 318 
     | 
    
         
            +
                    if handler.match(tokens, definitions)
         
     | 
| 
      
 319 
     | 
    
         
            +
                      good_tokens = tokens.select { |o| !o.get_tag Separator }
         
     | 
| 
      
 320 
     | 
    
         
            +
                      return handler.invoke(:anchor, good_tokens, options)
         
     | 
| 
      
 321 
     | 
    
         
            +
                    end
         
     | 
| 
      
 322 
     | 
    
         
            +
                  end
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                  definitions[:arrow].each do |handler|
         
     | 
| 
      
 325 
     | 
    
         
            +
                    if handler.match(tokens, definitions)
         
     | 
| 
      
 326 
     | 
    
         
            +
                      good_tokens = tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) }
         
     | 
| 
      
 327 
     | 
    
         
            +
                      return handler.invoke(:arrow, good_tokens, options)
         
     | 
| 
      
 328 
     | 
    
         
            +
                    end
         
     | 
| 
      
 329 
     | 
    
         
            +
                  end
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
                  definitions[:narrow].each do |handler|
         
     | 
| 
      
 332 
     | 
    
         
            +
                    if handler.match(tokens, definitions)
         
     | 
| 
      
 333 
     | 
    
         
            +
                      return handler.invoke(:narrow, tokens, options)
         
     | 
| 
      
 334 
     | 
    
         
            +
                    end
         
     | 
| 
      
 335 
     | 
    
         
            +
                  end
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
                  puts "-none" if Chronic.debug
         
     | 
| 
      
 338 
     | 
    
         
            +
                  return nil
         
     | 
| 
      
 339 
     | 
    
         
            +
                end
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
              end
         
     | 
| 
      
 342 
     | 
    
         
            +
             
     | 
| 
      
 343 
     | 
    
         
            +
              # Internal exception
         
     | 
| 
      
 344 
     | 
    
         
            +
              class ChronicPain < Exception
         
     | 
| 
      
 345 
     | 
    
         
            +
              end
         
     | 
| 
      
 346 
     | 
    
         
            +
            end
         
     |