kronic 0.2.1 → 0.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.
data/HISTORY CHANGED
@@ -1,3 +1,9 @@
1
+ 0.3.0
2
+ * Support month before day ("June 14")
3
+ * Support day ordinals ("14th June")
4
+ * Use Time.zone if available
5
+ * Fix Kronic.format for ruby 1.8
6
+
1
7
  0.2.1
2
8
  * Removed dependency on active_support, no external dependencies!
3
9
  * Dates in the future with a year specified are parsed correctly
data/README.rdoc CHANGED
@@ -8,7 +8,7 @@ Chronic and Tickle both parse a *heap* of formats. That's not useful to me when
8
8
 
9
9
  In addition, Kronic can take a date and give you a human readable form, neither of which Chronic nor Tickle does.
10
10
 
11
- Oh yeah, Kronic is less than 100 lines of code.
11
+ Oh yeah, Kronic is about 100 lines of code.
12
12
 
13
13
  == Usage
14
14
 
data/lib/kronic.rb CHANGED
@@ -2,25 +2,28 @@ require 'date'
2
2
 
3
3
  class Kronic
4
4
  # Public: Converts a human readable day (Today, yesterday) to a Date.
5
+ # If Time.zone is available and set (added by active_support and rails),
6
+ # Time.zone.today will be used as a reference point, otherwise Date.today
7
+ # will be used.
5
8
  #
6
- # Will call #to_s on the input, so can process Symbols or whatever other
7
- # object you wish to throw at it.
8
- #
9
- # string - The String to convert to a Date. Supported formats are: Today,
10
- # yesterday, tomorrow, last thursday, this thursday, 14 Sep,
11
- # 14 June 2010. Parsing is case-insensitive.
9
+ # string - The String to convert to a Date. #to_s is called on the parameter.
10
+ # Supported formats are: Today, yesterday, tomorrow, last thursday,
11
+ # this thursday, 14 Sep, Sep 14, 14 June 2010. Parsing is
12
+ # case-insensitive.
12
13
  #
13
14
  # Returns the Date, or nil if the input could not be parsed.
14
15
  def self.parse(string)
15
16
  string = string.to_s.downcase.strip
16
- today = Date.today
17
+ now = today
17
18
 
18
- parse_nearby_days(string, today) ||
19
- parse_last_or_this_day(string, today) ||
20
- parse_exact_date(string, today)
19
+ parse_nearby_days(string, now) ||
20
+ parse_last_or_this_day(string, now) ||
21
+ parse_exact_date(string, now)
21
22
  end
22
23
 
23
- # Public: Converts a date to a human readable string.
24
+ # Public: Converts a date to a human readable string. If Time.zone is
25
+ # available and set (added by active_support and rails), Time.zone.today
26
+ # will be used as a reference point, otherwise Date.today will be used.
24
27
  #
25
28
  # date - The Date to be converted
26
29
  # opts - The Hash options used to customize formatting
@@ -29,7 +32,7 @@ class Kronic
29
32
  # Returns a relative string ("Today", "This Monday") if available, otherwise
30
33
  # the full representation of the date ("19 September 2010").
31
34
  def self.format(date, opts = {})
32
- case (date.to_date - (opts[:today] || Date.today)).to_i
35
+ case (date - (opts[:today] || today)).to_i
33
36
  when (2..7) then "This " + date.strftime("%A")
34
37
  when 1 then "Tomorrow"
35
38
  when 0 then "Today"
@@ -42,6 +45,17 @@ class Kronic
42
45
  class << self
43
46
  private
44
47
 
48
+ NUMBER = /^[0-9]+$/
49
+ NUMBER_WITH_ORDINAL = /^[0-9]+(st|nd|rd|th)?$/
50
+
51
+ def today
52
+ if Time.respond_to?(:zone) && Time.zone
53
+ Time.zone.today
54
+ else
55
+ Date.today
56
+ end
57
+ end
58
+
45
59
  # Examples
46
60
  #
47
61
  # month_from_name("january") # => 1
@@ -75,25 +89,34 @@ class Kronic
75
89
  end
76
90
  end
77
91
 
78
- # Parse "14 Sep, 14 September, 14 September 2010"
92
+ # Parse "14 Sep", "14 September", "14 September 2010", "Sept 14 2010"
79
93
  def parse_exact_date(string, today)
80
94
  tokens = string.split(/\s+/)
81
95
 
82
- if tokens[0] =~ /^[0-9]+$/ && tokens[1]
83
- day = tokens[0].to_i
84
- month = month_from_name(tokens[1])
85
- year = if tokens[2]
86
- tokens[2] =~ /^[0-9]+$/ ? tokens[2].to_i : nil
87
- else
88
- today.year
96
+ if tokens.length >= 2
97
+ if tokens[0] =~ NUMBER_WITH_ORDINAL
98
+ parse_exact_date_parts(tokens[0], tokens[1], tokens[2], today)
99
+ elsif tokens[1] =~ NUMBER_WITH_ORDINAL
100
+ parse_exact_date_parts(tokens[1], tokens[0], tokens[2], today)
89
101
  end
102
+ end
103
+ end
104
+
105
+ # Parses day, month and year parts
106
+ def parse_exact_date_parts(raw_day, raw_month, raw_year, today)
107
+ day = raw_day.to_i
108
+ month = month_from_name(raw_month)
109
+ year = if raw_year
110
+ raw_year =~ NUMBER ? raw_year.to_i : nil
111
+ else
112
+ today.year
113
+ end
90
114
 
91
- return nil unless day && month && year
115
+ return nil unless day && month && year
92
116
 
93
- result = Date.new(year, month, day)
94
- result = result << 12 if result > today && !tokens[2]
95
- result
96
- end
117
+ result = Date.new(year, month, day)
118
+ result = result << 12 if result > today && !raw_year
119
+ result
97
120
  end
98
121
  end
99
122
  end
data/spec/kronic_spec.rb CHANGED
@@ -18,14 +18,18 @@ describe Kronic do
18
18
  :today => Date.new(2010, 9, 18),
19
19
  :last_monday => Date.new(2010, 9, 13),
20
20
  :next_monday => Date.new(2010, 9, 20),
21
- :sep_4 => Date.new(2010, 9, 4),
22
- :sep_20 => Date.new(2009, 9, 20),
23
- :sep_28 => Date.new(2010, 9, 28)
21
+ :sep_4 => Date.new(2010, 9, 4),
22
+ :sep_20 => Date.new(2009, 9, 20),
23
+ :sep_28 => Date.new(2010, 9, 28)
24
24
  }.fetch(key)
25
25
  end
26
+ def date(key); self.class.date(key); end;
26
27
 
27
- before :all do
28
- Timecop.freeze(self.class.date(:today))
28
+ before :each do
29
+ Time.zone = nil
30
+ ENV['TZ'] = "Australia/Melbourne"
31
+ d = date(:today)
32
+ Timecop.freeze(Time.utc(d.year, d.month, d.day))
29
33
  end
30
34
 
31
35
  should_parse('Today', date(:today))
@@ -41,7 +45,12 @@ describe Kronic do
41
45
  should_parse('4 September', date(:sep_4))
42
46
  should_parse('20 Sep', date(:sep_20))
43
47
  should_parse('28 Sep 2010', date(:sep_28))
44
- should_parse('14 Sep 2008', Date.new(2008, 9, 14))
48
+ should_parse('14 Sep 2008', Date.new(2008, 9, 14))
49
+ should_parse('14th Sep 2008', Date.new(2008, 9, 14))
50
+ should_parse('23rd Sep 2008', Date.new(2008, 9, 23))
51
+ should_parse('September 14 2008', Date.new(2008, 9, 14))
52
+ should_parse('Sep 4th', date(:sep_4))
53
+ should_parse('September 4', date(:sep_4))
45
54
  should_parse('bogus', nil)
46
55
  should_parse('14', nil)
47
56
  should_parse('14 bogus in', nil)
@@ -53,4 +62,30 @@ describe Kronic do
53
62
  should_format('Last Monday', date(:last_monday))
54
63
  should_format('This Monday', date(:next_monday))
55
64
  should_format('14 September 2008', Date.new(2008, 9, 14))
65
+
66
+ describe 'timezone support' do
67
+ before :all do
68
+ Time.extend(MethodVisibility)
69
+ end
70
+
71
+ it 'should be timezone aware if activesupport Time.zone is set' do
72
+ Time.zone = "US/Eastern"
73
+ Kronic.parse("today").should == date(:today) - 1
74
+ Kronic.format(date(:today) - 1).should == "Today"
75
+ end
76
+
77
+ it 'should fallback to Date.today if Time.zone is not available' do
78
+ Time.hide_class_method(:zone) do
79
+ Kronic.parse("today").should == date(:today)
80
+ Kronic.format(date(:today)).should == "Today"
81
+ end
82
+ end
83
+
84
+ it 'should fallback to Date.today if Time.zone is not set' do
85
+ Time.zone = nil
86
+ Kronic.parse("today").should == date(:today)
87
+ Kronic.format(date(:today)).should == "Today"
88
+ end
89
+ end
90
+
56
91
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,22 @@
1
1
  require 'rspec'
2
2
  require 'timecop'
3
+ require 'active_support/core_ext'
3
4
 
4
5
  $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
5
6
  require 'kronic'
7
+
8
+ module MethodVisibility
9
+ # Used to toggle whether Time.zone is available, for testing with and
10
+ # without activesupport.
11
+ def hide_class_method(method)
12
+ metaclass = (class << self; self; end)
13
+ metaclass.send :alias_method, :old_method, method
14
+ metaclass.send :remove_method, method
15
+ begin
16
+ yield
17
+ ensure
18
+ metaclass.send :alias_method, method, :old_method
19
+ metaclass.send :remove_method, :old_method
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -4,9 +4,8 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
8
- - 1
9
- version: 0.2.1
7
+ - 3
8
+ version: "0.3"
10
9
  platform: ruby
11
10
  authors:
12
11
  - Xavier Shay
@@ -14,7 +13,7 @@ autorequire:
14
13
  bindir: bin
15
14
  cert_chain: []
16
15
 
17
- date: 2010-09-20 00:00:00 +01:00
16
+ date: 2010-09-27 00:00:00 +01:00
18
17
  default_executable:
19
18
  dependencies:
20
19
  - !ruby/object:Gem::Dependency
@@ -47,6 +46,32 @@ dependencies:
47
46
  version: "0"
48
47
  type: :development
49
48
  version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: activesupport
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: tzinfo
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ type: :development
74
+ version_requirements: *id004
50
75
  description:
51
76
  email:
52
77
  - hello@xaviershay.com
@@ -63,7 +88,7 @@ files:
63
88
  - README.rdoc
64
89
  - HISTORY
65
90
  - Rakefile
66
- has_rdoc: true
91
+ has_rdoc: false
67
92
  homepage: http://github.com/xaviershay/kronic
68
93
  licenses: []
69
94