public
Fork of mojombo/chronic
Description: Chronic is a pure Ruby natural language date parser.
Homepage: http://chronic.rubyforge.org
Clone URL: git://github.com/technoweenie/chronic.git
add endianness option (Mark Johnson/Thomas Lee)
mojombo (author)
Tue Feb 19 23:56:48 -0800 2008
commit  bd654b26ab052a74aab15c8e1a6e026a8010458b
tree    8e222e5102accd8b27c826f976f7b01d79085479
parent  66a0d3faf30584b4b10a3bd72b21246e8a299d8a
...
45
46
47
48
 
 
49
50
51
...
244
245
246
247
248
 
...
45
46
47
 
48
49
50
51
52
...
245
246
247
 
248
249
0
@@ -45,7 +45,8 @@ module Chronic
0
       default_options = {:context => :future,
0
                          :now => Time.now,
0
                          :guess => true,
0
- :ambiguous_time_range => 6}
0
+ :ambiguous_time_range => 6,
0
+ :endian_precedence => nil}
0
       options = default_options.merge specified_options
0
       
0
       # handle options that were set to nil
0
@@ -244,4 +245,4 @@ module Chronic
0
   class InvalidArgumentException < Exception
0
     
0
   end
0
-end
0
\ No newline at end of file
0
+end
...
2
3
4
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
7
8
...
15
16
17
18
19
 
 
20
21
22
...
34
35
36
 
 
 
 
37
38
39
40
41
42
43
 
 
 
44
45
46
...
49
50
51
52
53
 
 
54
55
56
...
59
60
61
62
63
 
 
64
65
66
...
69
70
71
72
73
 
 
74
75
76
...
84
85
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
88
89
...
474
475
476
 
 
 
 
477
478
479
480
 
...
2
3
4
 
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
31
32
33
 
 
34
35
36
37
38
...
50
51
52
53
54
55
56
57
58
59
60
61
 
 
62
63
64
65
66
67
...
70
71
72
 
 
73
74
75
76
77
...
80
81
82
 
 
83
84
85
86
87
...
90
91
92
 
 
93
94
95
96
97
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
515
516
517
518
519
520
521
522
523
 
524
525
0
@@ -2,7 +2,23 @@ module Chronic
0
 
0
   class << self
0
   
0
- def definitions #:nodoc:
0
+ def definitions(options={}) #:nodoc:
0
+ options[:endian_precedence] = [:middle, :little] if options[:endian_precedence].nil?
0
+
0
+ # ensure the endian precedence is exactly two elements long
0
+ raise ChronicPain, "More than two elements specified for endian precedence array" unless options[:endian_precedence].length == 2
0
+
0
+ # handler for dd/mm/yyyy
0
+ @little_endian_handler ||= Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
0
+
0
+ # handler for mm/dd/yyyy
0
+ @middle_endian_handler ||= Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy)
0
+
0
+ # ensure we have valid endian values
0
+ options[:endian_precedence].each do |e|
0
+ raise ChronicPain, "Unknown endian type: #{e.to_s}" unless instance_variable_defined?(endian_variable_name_for(e))
0
+ end
0
+
0
    @definitions ||=
0
       {:time => [Handler.new([:repeater_time, :repeater_day_portion?], nil)],
0
         
0
@@ -15,8 +31,8 @@ module Chronic
0
                  Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
0
                  Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
0
                  Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
0
- Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy),
0
- Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy),
0
+ @middle_endian_handler,
0
+ @little_endian_handler,
0
                  Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
0
                  Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)],
0
                  
0
@@ -34,13 +50,18 @@ module Chronic
0
        :narrow => [Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
0
                    Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)]
0
       }
0
+
0
+ apply_endian_precedences(options[:endian_precedence])
0
+
0
+ @definitions
0
     end
0
     
0
     def tokens_to_span(tokens, options) #:nodoc:
0
       # maybe it's a specific date
0
       
0
- self.definitions[:date].each do |handler|
0
- if handler.match(tokens, self.definitions)
0
+ definitions = self.definitions(options)
0
+ definitions[:date].each do |handler|
0
+ if handler.match(tokens, definitions)
0
           puts "-date" if Chronic.debug
0
           good_tokens = tokens.select { |o| !o.get_tag Separator }
0
           return self.send(handler.handler_method, good_tokens, options)
0
@@ -49,8 +70,8 @@ module Chronic
0
             
0
       # I guess it's not a specific date, maybe it's just an anchor
0
             
0
- self.definitions[:anchor].each do |handler|
0
- if handler.match(tokens, self.definitions)
0
+ definitions[:anchor].each do |handler|
0
+ if handler.match(tokens, definitions)
0
           puts "-anchor" if Chronic.debug
0
           good_tokens = tokens.select { |o| !o.get_tag Separator }
0
           return self.send(handler.handler_method, good_tokens, options)
0
@@ -59,8 +80,8 @@ module Chronic
0
             
0
       # not an anchor, perhaps it's an arrow
0
       
0
- self.definitions[:arrow].each do |handler|
0
- if handler.match(tokens, self.definitions)
0
+ definitions[:arrow].each do |handler|
0
+ if handler.match(tokens, definitions)
0
           puts "-arrow" if Chronic.debug
0
           good_tokens = tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) }
0
           return self.send(handler.handler_method, good_tokens, options)
0
@@ -69,8 +90,8 @@ module Chronic
0
       
0
       # not an arrow, let's hope it's a narrow
0
       
0
- self.definitions[:narrow].each do |handler|
0
- if handler.match(tokens, self.definitions)
0
+ definitions[:narrow].each do |handler|
0
+ if handler.match(tokens, definitions)
0
           puts "-narrow" if Chronic.debug
0
           #good_tokens = tokens.select { |o| !o.get_tag Separator }
0
           return self.send(handler.handler_method, tokens, options)
0
@@ -84,6 +105,26 @@ module Chronic
0
     
0
     #--------------
0
     
0
+ def apply_endian_precedences(precedences)
0
+ date_defs = @definitions[:date]
0
+
0
+ # map the precedence array to indices on @definitions[:date]
0
+ indices = precedences.map { |e|
0
+ handler = instance_variable_get(endian_variable_name_for(e))
0
+ date_defs.index(handler)
0
+ }
0
+
0
+ # swap the handlers if we discover they are at odds with the desired preferences
0
+ swap(date_defs, indices.first, indices.last) if indices.first > indices.last
0
+ end
0
+
0
+ def endian_variable_name_for(e)
0
+ "@#{e.to_s}_endian_handler".to_sym
0
+ end
0
+
0
+ # exchange two elements in an array
0
+ def swap(arr, a, b); arr[a], arr[b] = arr[b], arr[a]; end
0
+
0
     def day_or_time(day_start, time_tokens, options)
0
       outer_span = Span.new(day_start, day_start + (24 * 60 * 60))
0
       
0
@@ -474,6 +515,10 @@ module Chronic
0
       return false if token_index != tokens.size
0
       return true
0
     end
0
+
0
+ def ==(other)
0
+ self.pattern == other.pattern
0
+ end
0
   end
0
   
0
-end
0
\ No newline at end of file
0
+end
...
611
612
613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
615
616
...
689
690
691
692
693
 
...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
...
703
704
705
 
706
707
0
@@ -611,6 +611,20 @@ class TestParsing < Test::Unit::TestCase
0
     assert_equal Time.local(2006, 8, 21), span.end
0
   end
0
   
0
+ def test_parse_with_endian_precedence
0
+ date = '11/02/2007'
0
+
0
+ expect_for_middle_endian = Time.local(2007, 11, 2, 12)
0
+ expect_for_little_endian = Time.local(2007, 2, 11, 12)
0
+
0
+ # default precedence should be toward middle endianness
0
+ assert_equal expect_for_middle_endian, Chronic.parse(date)
0
+
0
+ assert_equal expect_for_middle_endian, Chronic.parse(date, :endian_precedence => [:middle, :little])
0
+
0
+ assert_equal expect_for_little_endian, Chronic.parse(date, :endian_precedence => [:little, :middle])
0
+ end
0
+
0
   def test_parse_words
0
     assert_equal parse_now("33 days from now"), parse_now("thirty-three days from now")
0
     assert_equal parse_now("2867532 seconds from now"), parse_now("two million eight hundred and sixty seven thousand five hundred and thirty two seconds from now")
0
@@ -689,4 +703,4 @@ class TestParsing < Test::Unit::TestCase
0
   def parse_now(string, options={})
0
     Chronic.parse(string, {:now => TIME_2006_08_16_14_00_00 }.merge(options))
0
   end
0
-end
0
\ No newline at end of file
0
+end

Comments

    No one has commented yet.