medjool 0.1

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 ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 andygeers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ medjool
2
+ =======
3
+ Date parsing with context.
4
+
5
+ The Date.parse in ActiveSupport method is awesome. The only thing it lacks is the ability to provide a bit more context to override what 'now' is considered to be. By default, Medjool defers date parsing directly to Date.parse, but on subsequent calls it will make sure that the result is after the previously parsed date.
6
+
7
+ Usage
8
+ =====
9
+
10
+ parser = Medjool::Parser.new({:now => "2013-08-26".to_date})
11
+ parser.parse("Tuesday") => "2013-08-27"
12
+ parser.parse("Wednesday") => "2013-08-28"
13
+ parser.parse("Tuesday") => "2013-09-03"
14
+
15
+
16
+ Tests
17
+ =====
18
+ To run the tests, type:
19
+
20
+ rake test
21
+
22
+ License
23
+ =======
24
+ Medjool is licensed under an MIT license.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'date'
2
+
3
+ def version
4
+ contents = File.read File.expand_path('../lib/medjool.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-#{version}.gem pkg"
44
+ end
45
+
46
+ task :default => :test
data/lib/medjool.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Medjool
2
+ VERSION = 0.1
3
+
4
+ require 'medjool/parser'
5
+ require 'medjool/regexs'
6
+
7
+ class << self
8
+
9
+ end
10
+
11
+ def self.parse(t, context = {})
12
+ Medjool::Parser.new(context).parse(t)
13
+ end
14
+ end
@@ -0,0 +1,102 @@
1
+ require 'active_support/core_ext'
2
+
3
+ class Medjool::Parser
4
+
5
+ attr_reader :context
6
+
7
+ def initialize(context = {})
8
+ @context = context
9
+ end
10
+
11
+ def parse(text)
12
+ if Medjool::DATE_MATCHER.match(text)
13
+ base_date = Date.parse(text)
14
+
15
+ unless @context[:now]
16
+ # In the absence of context, always fall back on the default guess
17
+ guess_date = base_date
18
+ else
19
+ # Determine the ambiguity level for this data
20
+ ambiguity = determine_ambiguity(text)
21
+
22
+ now = @context[:now].to_date
23
+
24
+ case ambiguity
25
+ when :none
26
+ return base_date
27
+
28
+ when :weekly
29
+ # Pick the nearest week that meets the context
30
+ guess_date = now + (base_date.wday - now.wday).days - 1.week
31
+
32
+ while guess_date < now
33
+ guess_date += 1.week
34
+ end
35
+ when :monthly
36
+ # Pick the nearest month where the provided day of the month meets the context
37
+ y = now.year
38
+ m = now.month - 1
39
+ guess_date = nil
40
+
41
+ while guess_date.nil? || guess_date < now
42
+ m += 1
43
+ if m > 12
44
+ m = 1
45
+ y += 1
46
+ end
47
+ begin
48
+ guess_date = Date.new(y, m, base_date.day)
49
+ rescue ArgumentError
50
+ # This might happen e.g. 31st Feb,
51
+ # so just carry on to the next month
52
+ next
53
+ end
54
+ end
55
+
56
+ when :yearly
57
+ # Skip ahead a year at a time unless we meet the context
58
+ guess_date = Date.new(now.year, base_date.month, base_date.day)
59
+ while guess_date < now
60
+ guess_date += 1.year
61
+ end
62
+
63
+ end
64
+ end
65
+
66
+ @context[:now] = guess_date
67
+ return guess_date
68
+ else
69
+ return nil
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ def determine_ambiguity(text)
76
+ if /#{Medjool::DM_DM_YYYY_MATCHER}|#{Medjool::YYYY_MM_DD_MATCHER}/.match(text)
77
+ # Plain as day
78
+ return :none
79
+ end
80
+
81
+ # Work out how much detail we have
82
+ data_present = {
83
+ :day_name => Medjool::DAYNAME_MATCHER.match(text),
84
+ :month => Medjool::MONTH_MATCHER.match(text),
85
+ :ordinal => Medjool::ORDINAL_MATCHER.match(text)
86
+ }
87
+
88
+ if data_present[:month] && data_present[:ordinal]
89
+ # 1st December
90
+ return :yearly
91
+ elsif data_present[:ordinal]
92
+ # Monday 1 or just 1st
93
+ return :monthly
94
+ elsif data_present[:day_name] && !data_present[:month]
95
+ # Tuesday
96
+ return :weekly
97
+ else
98
+ # Unknown
99
+ return nil
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,10 @@
1
+ module Medjool
2
+ DAYNAME_MATCHER = /(\s*Mon(day)?,?\s*|\s*Tue(s(day)?)?,?\s*|\s*Wed(nesday)?,?\s*|\s*Thur(s(day)?)?,?\s*|\s*Fri(day)?,?\s*|\s*Sat(urday)?,?\s*|\s*Sun(day)?,?\s*)/
3
+ MONTH_MATCHER = /\s*(Jan(uary)?|Feb(ruary)?|Mar(ch)?|Apr(il)?|May|June?|July?|Aug(ust)?|Sept(ember)?|Oct(ober)?|Nov(ember)?|Dec(ember)?),?\s*/
4
+ YYYY_MM_DD_MATCHER = /(\s*[0-9]{4}-[0-9]{2}-[0-9]{2}\s*)/
5
+ DM_DM_YYYY_MATCHER = /(\s*[0-9]{2}[-\/][0-9]{2}[-\/][0-9]{2,4}\s*)/
6
+ ORDINAL_MATCHER = /(\s*([0-9]{1,2}(st|rd|nd|th)?),?\s*)/
7
+ YEAR_MATCHER = /(\s*([0-9]{4}\s*|\s*'?[0-9]{2}),?\s*)/
8
+ TEXT_DATE_MATCHER = /(#{DAYNAME_MATCHER}|#{ORDINAL_MATCHER}|#{YEAR_MATCHER}|#{MONTH_MATCHER})/
9
+ DATE_MATCHER = /^(#{TEXT_DATE_MATCHER}+|#{DM_DM_YYYY_MATCHER}|#{YYYY_MM_DD_MATCHER})/
10
+ end
data/medjool.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+ require 'medjool'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'medjool'
6
+ s.version = Medjool::VERSION
7
+ #s.rubyforge_project = 'medjool'
8
+ s.summary = 'Date parsing with context'
9
+ s.description = 'Medjool is a date parser written in pure Ruby, which processes dates within a context.'
10
+ s.authors = ['Andy Geers']
11
+ s.email = ['andy@geero.net']
12
+ s.homepage = 'http://github.com/andygeers/medjool'
13
+ s.rdoc_options = ['--charset=UTF-8']
14
+ s.extra_rdoc_files = %w[README.md LICENSE]
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- test`.split("\n")
17
+
18
+ s.add_dependency 'activesupport', '~> 3.2.12'
19
+ s.add_development_dependency 'rake'
20
+ s.add_development_dependency 'minitest', '~> 5.0'
21
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,15 @@
1
+ unless defined? Medjool
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'medjool'
4
+ end
5
+
6
+ require 'minitest'
7
+ require 'minitest/autorun'
8
+ require 'active_support/core_ext/string'
9
+ require 'timecop'
10
+
11
+ class TestCase < MiniTest::Test
12
+ def self.test(name, &block)
13
+ define_method("test_#{name.gsub(/\W/, '_')}", &block) if block
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ require 'helper'
2
+
3
+ class TestMedjool < TestCase
4
+
5
+ def setup
6
+ # Friday 23rd August 2013
7
+ Timecop.freeze("2013-08-23".to_date)
8
+ end
9
+
10
+ def teardown
11
+ Timecop.return
12
+ end
13
+
14
+ def test_parse_without_context
15
+ @variations = ["Monday", "1st July", "2nd July 2010", "1 July 2009", "Monday 2nd July 2009", "Monday 2nd", "Monday 2", "Monday 2 July"]
16
+ @variations.each do |t|
17
+ assert_equal Date.parse(t), Medjool.parse(t)
18
+ end
19
+ end
20
+
21
+ def test_parse_with_context
22
+ assert_equal Date.parse("Monday") + 1.week, Medjool.parse("Monday", { :now => 1.week.from_now })
23
+
24
+ assert_equal "2014-03-31".to_date, Medjool.parse("31st", { :now => "2014-02-01" })
25
+
26
+ assert_equal "2014-03-31".to_date, Medjool.parse("31st", { :now => "2014-02-01" })
27
+ end
28
+
29
+ def test_day_month_and_ordinal
30
+ assert_equal "2013-10-01".to_date, Medjool.parse("Monday 1st October", {:now => "2013-08-23".to_date})
31
+ assert_equal "2014-10-01".to_date, Medjool.parse("Monday 1st October", {:now => "2013-10-02".to_date})
32
+
33
+ assert_equal "2013-10-01".to_date, Medjool.parse("1st October", {:now => "2013-08-23".to_date})
34
+ assert_equal "2014-10-01".to_date, Medjool.parse("1st October", {:now => "2013-10-02".to_date})
35
+ end
36
+
37
+ def test_ordinal_only
38
+ assert_equal "2013-09-01".to_date, Medjool.parse("1st", {:now => "2013-08-23".to_date})
39
+ assert_equal "2013-08-01".to_date, Medjool.parse("1st", {:now => "2013-08-01".to_date})
40
+ end
41
+
42
+ def test_day_only
43
+ assert_equal "2013-08-27".to_date, Medjool.parse("Tuesday", {:now => "2013-08-26".to_date})
44
+ assert_equal "2013-08-27".to_date, Medjool.parse("Tuesday", {:now => "2013-08-27".to_date})
45
+ assert_equal "2013-09-03".to_date, Medjool.parse("Tuesday", {:now => "2013-08-28".to_date})
46
+ end
47
+
48
+ def test_absolute_dates
49
+ parser = Medjool::Parser.new
50
+ assert_equal "2013-07-06".to_date, parser.parse("06/07/2013")
51
+ assert_equal "2013-07-06".to_date, parser.parse("06/07/2013")
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: medjool
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Andy Geers
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2013-08-26 00:00:00 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: activesupport
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ hash: 23
28
+ segments:
29
+ - 3
30
+ - 2
31
+ - 12
32
+ version: 3.2.12
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: minitest
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ hash: 31
58
+ segments:
59
+ - 5
60
+ - 0
61
+ version: "5.0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ description: Medjool is a date parser written in pure Ruby, which processes dates within a context.
65
+ email:
66
+ - andy@geero.net
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - README.md
73
+ - LICENSE
74
+ files:
75
+ - .gitignore
76
+ - LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - lib/medjool.rb
80
+ - lib/medjool/parser.rb
81
+ - lib/medjool/regexs.rb
82
+ - medjool.gemspec
83
+ - test/helper.rb
84
+ - test/test_medjool.rb
85
+ homepage: http://github.com/andygeers/medjool
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options:
90
+ - --charset=UTF-8
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ requirements: []
112
+
113
+ rubyforge_project:
114
+ rubygems_version: 1.8.24
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: Date parsing with context
118
+ test_files:
119
+ - test/helper.rb
120
+ - test/test_medjool.rb