public
Fork of mojombo/chronic
Description: "Chronic is a pure Ruby natural language date parser." + improvements, corrections, speedups, and additions
Homepage: http://chronic.rubyforge.org
Clone URL: git://github.com/jf/chronic.git
Search Repo:
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
...
45
46
47
 
48
49
50
51
52
0
@@ -45,7 +45,8 @@
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
...
2
3
4
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
7
8
...
15
16
17
18
19
 
 
20
21
22
23
...
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
...
473
474
475
 
 
 
 
476
477
478
...
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
39
...
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
...
514
515
516
517
518
519
520
521
522
523
0
@@ -2,7 +2,23 @@
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 @@
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
0
@@ -34,13 +50,18 @@
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 @@
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 @@
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 @@
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 @@
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
@@ -473,6 +514,10 @@
0
       end
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
   
...
611
612
613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
615
616
...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
0
@@ -611,6 +611,20 @@
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")

Comments

    No one has commented yet.