chronic 0.4.1 → 0.4.3

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.
@@ -1,19 +1,30 @@
1
1
  module Chronic
2
- class Separator < Tag #:nodoc:
2
+ class Separator < Tag
3
+
4
+ # Scan an Array of {Token}s and apply any necessary Separator tags to
5
+ # each token
6
+ #
7
+ # @param [Array<Token>] tokens Array of tokens to scan
8
+ # @param [Hash] options Options specified in {Chronic.parse}
9
+ # @return [Array] list of tokens
3
10
  def self.scan(tokens, options)
4
- tokens.each_index do |i|
5
- if t = scan_for_commas(tokens[i]) then tokens[i].tag(t); next end
6
- if t = scan_for_slash_or_dash(tokens[i]) then tokens[i].tag(t); next end
7
- if t = scan_for_at(tokens[i]) then tokens[i].tag(t); next end
8
- if t = scan_for_in(tokens[i]) then tokens[i].tag(t); next end
9
- if t = scan_for_on(tokens[i]) then tokens[i].tag(t); next end
11
+ tokens.each do |token|
12
+ if t = scan_for_commas(token) then token.tag(t); next end
13
+ if t = scan_for_slash_or_dash(token) then token.tag(t); next end
14
+ if t = scan_for_at(token) then token.tag(t); next end
15
+ if t = scan_for_in(token) then token.tag(t); next end
16
+ if t = scan_for_on(token) then token.tag(t); next end
10
17
  end
11
18
  end
12
19
 
20
+ # @param [Token] token
21
+ # @return [SeparatorComma, nil]
13
22
  def self.scan_for_commas(token)
14
23
  scan_for token, SeparatorComma, { /^,$/ => :comma }
15
24
  end
16
25
 
26
+ # @param [Token] token
27
+ # @return [SeparatorSlashOrDash, nil]
17
28
  def self.scan_for_slash_or_dash(token)
18
29
  scan_for token, SeparatorSlashOrDash,
19
30
  {
@@ -22,14 +33,20 @@ module Chronic
22
33
  }
23
34
  end
24
35
 
36
+ # @param [Token] token
37
+ # @return [SeparatorAt, nil]
25
38
  def self.scan_for_at(token)
26
39
  scan_for token, SeparatorAt, { /^(at|@)$/ => :at }
27
40
  end
28
41
 
42
+ # @param [Token] token
43
+ # @return [SeparatorIn, nil]
29
44
  def self.scan_for_in(token)
30
45
  scan_for token, SeparatorIn, { /^in$/ => :in }
31
46
  end
32
47
 
48
+ # @param [Token] token
49
+ # @return [SeparatorOn, nil]
33
50
  def self.scan_for_on(token)
34
51
  scan_for token, SeparatorOn, { /^on$/ => :on }
35
52
  end
data/lib/chronic/tag.rb CHANGED
@@ -1,13 +1,17 @@
1
1
  module Chronic
2
2
  # Tokens are tagged with subclassed instances of this class when
3
3
  # they match specific criteria
4
- class Tag #:nodoc:
4
+ class Tag
5
+
6
+ # @return [Symbol]
5
7
  attr_accessor :type
6
8
 
9
+ # @param [Symbol] type
7
10
  def initialize(type)
8
11
  @type = type
9
12
  end
10
13
 
14
+ # @param [Time] s Set the start timestamp for this Tag
11
15
  def start=(s)
12
16
  @now = s
13
17
  end
@@ -15,6 +19,11 @@ module Chronic
15
19
  class << self
16
20
  private
17
21
 
22
+ # @param [Token] token
23
+ # @param [Class] klass The class instance to create
24
+ # @param [Regexp, Hash] items
25
+ # @return [Object, nil] either a new instance of `klass` or `nil` if
26
+ # no match is found
18
27
  def scan_for(token, klass, items={})
19
28
  case items
20
29
  when Regexp
@@ -1,11 +1,20 @@
1
1
  module Chronic
2
- class TimeZone < Tag #:nodoc:
2
+ class TimeZone < Tag
3
+
4
+ # Scan an Array of {Token}s and apply any necessary TimeZone tags to
5
+ # each token
6
+ #
7
+ # @param [Array<Token>] tokens Array of tokens to scan
8
+ # @param [Hash] options Options specified in {Chronic.parse}
9
+ # @return [Array] list of tokens
3
10
  def self.scan(tokens, options)
4
- tokens.each_index do |i|
5
- if t = scan_for_all(tokens[i]) then tokens[i].tag(t); next end
11
+ tokens.each do |token|
12
+ if t = scan_for_all(token) then token.tag(t); next end
6
13
  end
7
14
  end
8
15
 
16
+ # @param [Token] token
17
+ # @return [TimeZone, nil]
9
18
  def self.scan_for_all(token)
10
19
  scan_for token, self,
11
20
  {
data/lib/chronic/token.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  module Chronic
2
- class Token #:nodoc:
3
- attr_accessor :word, :tags
2
+ class Token
3
+
4
+ # @return [String] The word this Token represents
5
+ attr_accessor :word
6
+
7
+ # @return [Array] A list of tag associated with this Token
8
+ attr_accessor :tags
4
9
 
5
10
  def initialize(word)
6
11
  @word = word
@@ -8,21 +13,26 @@ module Chronic
8
13
  end
9
14
 
10
15
  # Tag this token with the specified tag
16
+ #
17
+ # @param [Tag] new_tag A instance of {Tag} or one of its subclasses
11
18
  def tag(new_tag)
12
19
  @tags << new_tag
13
20
  end
14
21
 
15
22
  # Remove all tags of the given class
23
+ #
24
+ # @param [Class] The tag class to remove
16
25
  def untag(tag_class)
17
26
  @tags.delete_if { |m| m.kind_of? tag_class }
18
27
  end
19
28
 
20
- # Return true if this token has any tags
29
+ # @return [Boolean] true if this token has any tags
21
30
  def tagged?
22
31
  @tags.size > 0
23
32
  end
24
33
 
25
- # Return the Tag that matches the given class
34
+ # @param [Class] tag_class The tag class to search for
35
+ # @return [Tag] The first Tag that matches the given class
26
36
  def get_tag(tag_class)
27
37
  @tags.find { |m| m.kind_of? tag_class }
28
38
  end
data/lib/chronic.rb CHANGED
@@ -1,33 +1,82 @@
1
- #=============================================================================
1
+ require 'time'
2
+ require 'date'
3
+
4
+ # Parse natural language dates and times into Time or {Chronic::Span} objects
2
5
  #
3
- # Name: Chronic
4
- # Author: Tom Preston-Werner
5
- # Purpose: Parse natural language dates and times into Time or
6
- # Chronic::Span objects
6
+ # @example
7
+ # require 'chronic'
7
8
  #
8
- #=============================================================================
9
-
9
+ # Time.now #=> Sun Aug 27 23:18:25 PDT 2006
10
+ #
11
+ # Chronic.parse('tomorrow')
12
+ # #=> Mon Aug 28 12:00:00 PDT 2006
13
+ #
14
+ # Chronic.parse('monday', :context => :past)
15
+ # #=> Mon Aug 21 12:00:00 PDT 2006
16
+ #
17
+ # Chronic.parse('this tuesday 5:00')
18
+ # #=> Tue Aug 29 17:00:00 PDT 2006
19
+ #
20
+ # Chronic.parse('this tuesday 5:00', :ambiguous_time_range => :none)
21
+ # #=> Tue Aug 29 05:00:00 PDT 2006
22
+ #
23
+ # Chronic.parse('may 27th', :now => Time.local(2000, 1, 1))
24
+ # #=> Sat May 27 12:00:00 PDT 2000
25
+ #
26
+ # Chronic.parse('may 27th', :guess => false)
27
+ # #=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
28
+ #
29
+ # @author Tom Preston-Werner, Lee Jarvis
10
30
  module Chronic
11
- VERSION = "0.4.1"
31
+ VERSION = "0.4.3"
12
32
 
13
33
  class << self
34
+
35
+ # @return [Boolean] true when debug mode is enabled
14
36
  attr_accessor :debug
37
+
38
+ # @example
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
+ # @return [Time] The time class Chronic uses internally
15
48
  attr_accessor :time_class
49
+
50
+ # The current Time Chronic is using to base from
51
+ #
52
+ # @example
53
+ # Time.now #=> 2011-06-06 14:13:43 +0100
54
+ # Chronic.parse('yesterday') #=> 2011-06-05 12:00:00 +0100
55
+ #
56
+ # now = Time.local(2025, 12, 24)
57
+ # Chronic.parse('tomorrow', :now => now) #=> 2025-12-25 12:00:00 +0000
58
+ #
59
+ # @return [Time, nil]
60
+ attr_accessor :now
16
61
  end
17
62
 
18
63
  self.debug = false
19
64
  self.time_class = Time
20
65
  end
21
66
 
22
- require 'time'
23
- require 'date'
24
-
25
67
  require 'chronic/chronic'
26
68
  require 'chronic/handlers'
27
69
  require 'chronic/mini_date'
28
70
  require 'chronic/tag'
29
71
  require 'chronic/span'
30
72
  require 'chronic/token'
73
+ require 'chronic/grabber'
74
+ require 'chronic/pointer'
75
+ require 'chronic/scalar'
76
+ require 'chronic/ordinal'
77
+ require 'chronic/separator'
78
+ require 'chronic/time_zone'
79
+ require 'chronic/numerizer'
31
80
 
32
81
  require 'chronic/repeater'
33
82
  require 'chronic/repeaters/repeater_year'
@@ -47,42 +96,6 @@ require 'chronic/repeaters/repeater_minute'
47
96
  require 'chronic/repeaters/repeater_second'
48
97
  require 'chronic/repeaters/repeater_time'
49
98
 
50
- require 'chronic/grabber'
51
- require 'chronic/pointer'
52
- require 'chronic/scalar'
53
- require 'chronic/ordinal'
54
- require 'chronic/separator'
55
- require 'chronic/time_zone'
56
-
57
- require 'chronic/numerizer'
58
-
59
- # class Time
60
- # def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
61
- # # extra_seconds = second > 60 ? second - 60 : 0
62
- # # extra_minutes = minute > 59 ? minute - 59 : 0
63
- # # extra_hours = hour > 23 ? hour - 23 : 0
64
- # # extra_days = day >
65
- #
66
- # if month > 12
67
- # if month % 12 == 0
68
- # year += (month - 12) / 12
69
- # month = 12
70
- # else
71
- # year += month / 12
72
- # month = month % 12
73
- # end
74
- # end
75
- #
76
- # base = Time.local(year, month)
77
- # puts base
78
- # offset = ((day - 1) * 24 * 60 * 60) + (hour * 60 * 60) + (minute * 60) + second
79
- # puts offset.to_s
80
- # date = base + offset
81
- # puts date
82
- # date
83
- # end
84
- # end
85
-
86
99
  class Time
87
100
  def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
88
101
  if second >= 60
data/test/test_Chronic.rb CHANGED
@@ -21,7 +21,7 @@ class TestChronic < Test::Unit::TestCase
21
21
 
22
22
  assert_equal :morning, tokens[1].tags[0].type
23
23
 
24
- tokens = Chronic.dealias_and_disambiguate_times(tokens, {})
24
+ tokens = Chronic::Handlers.dealias_and_disambiguate_times(tokens, {})
25
25
 
26
26
  assert_equal :am, tokens[1].tags[0].type
27
27
  assert_equal 2, tokens.size
@@ -34,7 +34,7 @@ class TestChronic < Test::Unit::TestCase
34
34
 
35
35
  assert_equal :morning, tokens[1].tags[0].type
36
36
 
37
- tokens = Chronic.dealias_and_disambiguate_times(tokens, {})
37
+ tokens = Chronic::Handlers.dealias_and_disambiguate_times(tokens, {})
38
38
 
39
39
  assert_equal :morning, tokens[1].tags[0].type
40
40
  assert_equal 2, tokens.size
@@ -51,4 +51,54 @@ class TestChronic < Test::Unit::TestCase
51
51
  assert_equal Time.local(2006, 11, 16), Chronic.guess(span)
52
52
  end
53
53
 
54
+ def test_now
55
+ Chronic.parse('now', :now => Time.local(2006, 01))
56
+ assert_equal Time.local(2006, 01), Chronic.now
57
+
58
+ Chronic.parse('now', :now => Time.local(2007, 01))
59
+ assert_equal Time.local(2007, 01), Chronic.now
60
+ end
61
+
62
+ def test_endian_definitions
63
+ # middle, little
64
+ endians = [
65
+ Chronic::Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy),
66
+ Chronic::Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
67
+ ]
68
+
69
+ assert_equal endians, Chronic.definitions[:endian]
70
+
71
+ defs = Chronic.definitions(:endian_precedence => :little)
72
+ assert_equal endians.reverse, defs[:endian]
73
+
74
+ defs = Chronic.definitions(:endian_precedence => [:little, :middle])
75
+ assert_equal endians.reverse, defs[:endian]
76
+
77
+ assert_raises(Chronic::InvalidArgumentException) do
78
+ Chronic.definitions(:endian_precedence => :invalid)
79
+ end
80
+ end
81
+
82
+ def test_passing_options
83
+ assert_raises(Chronic::InvalidArgumentException) do
84
+ Chronic.parse('now', :invalid => :option)
85
+ end
86
+
87
+ assert_raises(Chronic::InvalidArgumentException) do
88
+ Chronic.parse('now', :context => :invalid_context)
89
+ end
90
+ end
91
+
92
+ def test_debug
93
+ require 'stringio'
94
+ $stdout = StringIO.new
95
+ Chronic.debug = true
96
+
97
+ Chronic.parse 'now'
98
+ assert $stdout.string.include?('this(grabber-this)')
99
+ ensure
100
+ $stdout = STDOUT
101
+ Chronic.debug = false
102
+ end
103
+
54
104
  end
@@ -23,6 +23,10 @@ class TestRepeaterMonth < Test::Unit::TestCase
23
23
 
24
24
  time = Chronic::RepeaterMonth.new(:month).offset_by(@now, 10, :past)
25
25
  assert_equal Time.local(2005, 10, 16, 14), time
26
+
27
+ time = Chronic::RepeaterMonth.new(:month).offset_by(Time.local(2010, 3, 29), 1, :past)
28
+ assert_equal 2, time.month
29
+ assert_equal 28, time.day
26
30
  end
27
31
 
28
32
  def test_offset
data/test/test_parsing.rb CHANGED
@@ -274,6 +274,12 @@ class TestParsing < Test::Unit::TestCase
274
274
  time = parse_now("13:45")
275
275
  assert_equal Time.local(2006, 8, 17, 13, 45), time
276
276
 
277
+ time = parse_now("1:01pm")
278
+ assert_equal Time.local(2006, 8, 16, 13, 01), time
279
+
280
+ time = parse_now("2:01pm")
281
+ assert_equal Time.local(2006, 8, 16, 14, 01), time
282
+
277
283
  time = parse_now("november")
278
284
  assert_equal Time.local(2006, 11, 16), time
279
285
  end
metadata CHANGED
@@ -1,8 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronic
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.4.1
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 3
10
+ version: 0.4.3
6
11
  platform: ruby
7
12
  authors:
8
13
  - Tom Preston-Werner
@@ -11,7 +16,8 @@ autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
18
 
14
- date: 2011-06-05 00:00:00 Z
19
+ date: 2011-06-08 00:00:00 +01:00
20
+ default_executable:
15
21
  dependencies: []
16
22
 
17
23
  description: Chronic is a natural language date/time parser written in pure Ruby.
@@ -27,6 +33,8 @@ extra_rdoc_files:
27
33
  - HISTORY.md
28
34
  - LICENSE
29
35
  files:
36
+ - .gitignore
37
+ - .yardopts
30
38
  - HISTORY.md
31
39
  - LICENSE
32
40
  - Manifest.txt
@@ -86,6 +94,7 @@ files:
86
94
  - test/test_Time.rb
87
95
  - test/test_Token.rb
88
96
  - test/test_parsing.rb
97
+ has_rdoc: true
89
98
  homepage: http://github.com/mojombo/chronic
90
99
  licenses: []
91
100
 
@@ -99,21 +108,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
108
  requirements:
100
109
  - - ">="
101
110
  - !ruby/object:Gem::Version
111
+ hash: 3
112
+ segments:
113
+ - 0
102
114
  version: "0"
103
115
  required_rubygems_version: !ruby/object:Gem::Requirement
104
116
  none: false
105
117
  requirements:
106
118
  - - ">="
107
119
  - !ruby/object:Gem::Version
120
+ hash: 3
121
+ segments:
122
+ - 0
108
123
  version: "0"
109
124
  requirements: []
110
125
 
111
126
  rubyforge_project: chronic
112
- rubygems_version: 1.8.2
127
+ rubygems_version: 1.3.7
113
128
  signing_key:
114
129
  specification_version: 3
115
130
  summary: Natural language date/time parsing.
116
131
  test_files:
132
+ - test/helper.rb
117
133
  - test/test_Chronic.rb
118
134
  - test/test_DaylightSavings.rb
119
135
  - test/test_Handler.rb