natural-date 1.2 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 542d489e665790093de2be56251385422e79d4e2
4
- data.tar.gz: 7ee809b6b7bfad9535bdca731effad0bef68108e
3
+ metadata.gz: c67af377850cb1f455ec9f16d20b11d46775ce32
4
+ data.tar.gz: 8fee5e98a916dee160b302a2e951862b1a9e9097
5
5
  SHA512:
6
- metadata.gz: 55711080ed2742f5ed38ecacc94db1a9ef9a45035d0714151146f46dd6e88ca2214d3f77fd40025e647713641e95ced01939ee487223071bb72608f48ca4d06c
7
- data.tar.gz: f83fbd5aae5cd47e64a3b50ecdaf599de0dc6ee7143b10e33a894d51784351739203579f9a97cfe72f3357cd21aa299358999dc32c6ca486d3546543e29847f4
6
+ metadata.gz: 710e4c81e0f646632c199ee1a2203d6a9cefedf2ab12c43799ea9a037c29d8e5eb9c4648e0b193accf74d2a30e701c709073eca689bb3ba304335d86153efd67
7
+ data.tar.gz: 1996da7c86a768655b85c8b3de403fd29eb52e73841375022cc19f68206114e43b6856a5c7cf89bca9fa1c297ffeda80a693413835b12a0a9a4b404cc579e5ac
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Natural Date - Alpha
2
2
 
3
- Natural language date/time parser in Ruby. `natural-date` can convert from plain text to date expressions that can
4
- symbolize since single dates till recurrent dates.
3
+ Natural language date parser in Ruby. `natural-date` can convert from plain text to date expressions that can
4
+ symbolize both single dates and recurrent dates.
5
5
 
6
6
  ## Installation
7
7
 
@@ -50,9 +50,10 @@ natural_date.match?(Date.new(2017, 8, 1))
50
50
  natural_date.fetch_dates(Date.today..(Date.today + 5))
51
51
  # => array with dates matched inside the interval
52
52
 
53
- # If you don't pass any interval a default interval of Date.today..Date.today + 365 will be given
53
+ # If you don't pass any interval a default interval of reference_date..reference_date + 365 will be given
54
54
  natural_date.fetch_dates
55
55
  # => array with dates matched inside the interval
56
+
56
57
  ```
57
58
 
58
59
  ## Types of expressions
@@ -63,9 +64,10 @@ refer both single and recurring dates.
63
64
  - **Days**: Can be written as numbers `1..31` or ordinals like `['1st'..'31st']`.
64
65
  - **Months**: Can be written using the whole name `['January'..'December']` or using the first 3 letters `['Jan'..'Dec']`, also they are case insensitive `'JAN' == 'Jan' == 'jAn'` also you can use numbers if you use the 'of' world before `'1 of 12' == '1st December'`.
65
66
  - **Years**: You can write the year as usual 4 digits number like `2016` or you can ignore the year, if you ignore it the year is going to be guessed based on the expression and the reference date
66
- - **Week Days**: As months you can write both whole name and abbreviation (first 3 letters) 'monday' == 'mon'.
67
+ - **Week Days**: As months you can write both whole name and abbreviation (first 3 letters) `'monday' == 'mon'`.
67
68
 
68
69
  ```ruby
70
+ # first you need to create a Factory based on a language, nowadays only english and brazilian portuguese are available.
69
71
  factory = NaturalDateExpressionFactory.new(:en)
70
72
 
71
73
  # Day and month
@@ -105,6 +107,13 @@ factory.create('every monday of January')
105
107
  # => every monday of January any year
106
108
  factory.create('every monday and friday')
107
109
  # => every monday and friday of any month and any year.
110
+
111
+ # You can also pass several dates expressions using a ';' or a '\n' to separate them
112
+ factory.create('1 2 of May 2016 ; 3 4 June 2016')
113
+ # => ['1st May 2016', '2nd May 2016', '3rd June 2016', '4th June 2016']
114
+
115
+ factory.create("1 May 2016\n4 June 2016")
116
+ # => ['1st May 2016', '4th June 2016']
108
117
  ```
109
118
 
110
119
  ## Contributing
@@ -7,9 +7,13 @@ require 'natural-date/translator/mod_applier'
7
7
  require 'natural-date/translator/mounter'
8
8
  require 'natural-date/translator/normalizer'
9
9
  require 'natural-date/translator/splitter_literal_date'
10
- require 'natural-date/translator/time_mounter'
11
10
  require 'natural-date/translator/unknown_cleaner'
12
11
  require 'natural-date/translator/year_finder'
12
+ require 'natural-date/matcher/week_matcher'
13
+ require 'natural-date/matcher/month_matcher'
14
+ require 'natural-date/matcher/literal_matcher'
15
+ require 'natural-date/matcher/day_matcher'
16
+ require 'natural-date/matcher/year_matcher'
13
17
  require 'natural-date/language_bundle'
14
18
  require 'natural-date/natural_date_expression_factory'
15
19
  require 'natural-date/natural_date_expression'
@@ -0,0 +1,5 @@
1
+ module DayMatcher
2
+ def self.match? date, reference_date, expression_map
3
+ !expression_map[:day] || expression_map[:day].include?(date.day)
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module LiteralMatcher
2
+ def self.match? date, expression_map
3
+ # TODO
4
+ !expression_map[:literal] || expression_map[:literal].any? { |token| match_literal_token?(token, args) }
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module MonthMatcher
2
+ def self.match? date, reference_date, expression_map
3
+ !expression_map[:month] || expression_map[:month].include?(date.month)
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ module WeekMatcher
2
+ def self.match? date, reference_date, expression_map
3
+ !expression_map[:week_day] || expression_map[:week_day].any? { |token| match_week_token?(token, date) }
4
+ end
5
+
6
+ private
7
+
8
+ def self.match_month? date, expression_map
9
+ !expression_map[:month] || expression_map[:month].include?(date.month)
10
+ end
11
+
12
+ def self.match_week_token? token, date
13
+ return match_nth_week_token?(token, date) if token.to_s.include?('.')
14
+ token.to_i == date.wday
15
+ end
16
+
17
+ def self.match_nth_week_token? token, date
18
+ nth, token_wday = token.split('.')
19
+
20
+ wdays = (date.beginning_of_month..date.end_of_month).to_a.select do |day|
21
+ day.wday == token_wday.to_i
22
+ end
23
+
24
+ case nth
25
+ when 'first_1'
26
+ wdays.first == date
27
+ when 'last_999'
28
+ wdays.last == date
29
+ when 'prior_last_999'
30
+ wdays[wdays.size - 2] == date
31
+ else
32
+ wdays[nth.to_i - 1] == date
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ module YearMatcher
2
+ def self.match? date, reference_date, expression_map
3
+ return expression_map[:year].include?(date.year) if expression_map[:year]
4
+ return true if expression_map[:week_day] || !expression_map[:day] || !expression_map[:month]
5
+
6
+ require 'pry'
7
+
8
+ binding.pry unless date
9
+
10
+ date.year == reference_date.year
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  class NaturalDateExpression
2
- VERSION = "1.2"
2
+ VERSION = "1.3"
3
3
 
4
4
  class DateMatch
5
5
  attr_reader :first_matched_expression, :tested_date, :reference_date
@@ -30,13 +30,16 @@ class NaturalDateExpression
30
30
  match(date).matches?
31
31
  end
32
32
 
33
+ MATCHERS = [
34
+ WeekMatcher,
35
+ MonthMatcher,
36
+ DayMatcher,
37
+ YearMatcher
38
+ ].freeze
39
+
33
40
  def match date
34
41
  matches = @data.map do |expression_map|
35
- match_week?(date, expression_map) &&
36
- match_month?(date, expression_map) &&
37
- match_literal?(date, expression_map) &&
38
- match_day?(date, expression_map) &&
39
- match_year?(date, expression_map)
42
+ MATCHERS.map { |matcher| matcher.match?(date, @reference_date, expression_map) }.all?
40
43
  end
41
44
 
42
45
  DateMatch.new(matches.any?,
@@ -54,55 +57,6 @@ class NaturalDateExpression
54
57
  end
55
58
 
56
59
  def fetch_dates dates_range = nil
57
- (dates_range || (Date.today..(Date.today + 365))).to_a.select { |date| self =~ date }
58
- end
59
-
60
- private
61
-
62
- def match_year? date, expression_map
63
- return expression_map[:year].include?(date.year) if expression_map[:year]
64
- return true if expression_map[:week_day] || !expression_map[:day] || !expression_map[:month]
65
-
66
- date.year == @reference_date.year
67
- end
68
-
69
- def match_day? date, expression_map
70
- !expression_map[:day] || expression_map[:day].include?(date.day)
71
- end
72
-
73
- def match_literal? date, expression_map
74
- !expression_map[:literal] || expression_map[:literal].any? { |token| match_literal_token?(token, args) }
75
- end
76
-
77
- def match_week? date, expression_map
78
- !expression_map[:week_day] || expression_map[:week_day].any? { |token| match_week_token?(token, date) }
79
- end
80
-
81
- def match_month? date, expression_map
82
- !expression_map[:month] || expression_map[:month].include?(date.month)
83
- end
84
-
85
- def match_week_token? token, date
86
- return match_nth_week_token?(token, date) if token.to_s.include?('.')
87
- token.to_i == date.wday
88
- end
89
-
90
- def match_nth_week_token? token, date
91
- nth, token_wday = token.split('.')
92
-
93
- wdays = (date.beginning_of_month..date.end_of_month).to_a.select do |day|
94
- day.wday == token_wday.to_i
95
- end
96
-
97
- case nth
98
- when 'first_1'
99
- wdays.first == date
100
- when 'last_999'
101
- wdays.last == date
102
- when 'prior_last_999'
103
- wdays[wdays.size - 2] == date
104
- else
105
- wdays[nth.to_i - 1] == date
106
- end
60
+ (dates_range || (@reference_date..(@reference_date + 365))).to_a.select { |date| self =~ date }
107
61
  end
108
62
  end
@@ -3,15 +3,15 @@ class NaturalDateExpressionFactory
3
3
  @lang = lang
4
4
  end
5
5
 
6
- STEPS = {}
7
- EXPRESSION_SPLITTER_STEP = {}
8
-
9
6
  def create expression_string, reference_date = Date.today
10
7
  NaturalDateExpression.new(create_data_expression(expression_string, reference_date), reference_date, expression_string)
11
8
  end
12
9
 
13
10
  private
14
11
 
12
+ STEPS = {}
13
+ EXPRESSION_SPLITTER_STEP = {}
14
+
15
15
  def create_data_expression expression_string, reference_date
16
16
  expression_splitter.map(expression_string.to_s).map do |expression|
17
17
  steps.reduce(expression) do |tokens, step|
@@ -40,7 +40,6 @@ class NaturalDateExpressionFactory
40
40
  [ Translator::Cleaner,
41
41
  Translator::SplitterLiteralDate,
42
42
  Translator::Mounter,
43
- Translator::TimeMounter,
44
43
  Translator::Normalizer,
45
44
  Translator::Expander,
46
45
  Translator::ModApplier,
@@ -9,13 +9,13 @@ keys:
9
9
  last_999: 'last'
10
10
  of_month: 'of month'
11
11
  week_day:
12
- sun_0: 'sunday sun'
13
- mon_1: 'monday mon'
14
- tue_2: 'tuesday tue'
15
- wed_3: 'wednesday wed'
16
- thu_4: 'thursday thu'
17
- fri_5: 'friday fri'
18
- sat_6: 'saturday sat'
12
+ sun_0: 'sunday sundays sun'
13
+ mon_1: 'monday mondays mon'
14
+ tue_2: 'tuesday tuesdays tue'
15
+ wed_3: 'wednesday wednesdays wed'
16
+ thu_4: 'thursday thursdays thu'
17
+ fri_5: 'friday fridays fri'
18
+ sat_6: 'saturday saturdays sat'
19
19
  day:
20
20
  day_1: '1 1th 1st'
21
21
  day_2: '2 2th 2nd'
@@ -49,7 +49,7 @@ keys:
49
49
  day_30: '30 30th'
50
50
  day_31: '31 31th 31st'
51
51
  month:
52
- jan_1: 'jan janeiro'
52
+ jan_1: 'jan january'
53
53
  feb_2: 'feb february'
54
54
  mar_3: 'mar march'
55
55
  apr_4: 'apr april'
@@ -25,4 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "bundler", "~> 1.13"
26
26
  spec.add_development_dependency "rake", "~> 10.0"
27
27
  spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "pry", "~> 0.10.0"
28
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: natural-date
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.2'
4
+ version: '1.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew S Aguiar
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-10 00:00:00.000000000 Z
11
+ date: 2016-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.10.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.10.0
55
69
  description: Natural language date/time parser in Ruby. natural-date can convert from
56
70
  plain text to date expressions symbolizing since single dates till recurrent dates
57
71
  email:
@@ -72,9 +86,13 @@ files:
72
86
  - bin/setup
73
87
  - lib/natural-date.rb
74
88
  - lib/natural-date/language_bundle.rb
89
+ - lib/natural-date/matcher/day_matcher.rb
90
+ - lib/natural-date/matcher/literal_matcher.rb
91
+ - lib/natural-date/matcher/month_matcher.rb
92
+ - lib/natural-date/matcher/week_matcher.rb
93
+ - lib/natural-date/matcher/year_matcher.rb
75
94
  - lib/natural-date/natural_date_expression.rb
76
95
  - lib/natural-date/natural_date_expression_factory.rb
77
- - lib/natural-date/translator.rb
78
96
  - lib/natural-date/translator/cleaner.rb
79
97
  - lib/natural-date/translator/en.yml
80
98
  - lib/natural-date/translator/expander.rb
@@ -86,7 +104,6 @@ files:
86
104
  - lib/natural-date/translator/pt-BR.yml
87
105
  - lib/natural-date/translator/splitter_literal_date.rb
88
106
  - lib/natural-date/translator/step.rb
89
- - lib/natural-date/translator/time_mounter.rb
90
107
  - lib/natural-date/translator/unknown_cleaner.rb
91
108
  - lib/natural-date/translator/year_finder.rb
92
109
  - natural-date.gemspec
@@ -1,2 +0,0 @@
1
- module Translator
2
- end
@@ -1,55 +0,0 @@
1
- module Translator
2
- class TimeMounter < Step
3
- def map tokens, reference_date
4
- tokens
5
- .map { |token| normalize(token) }
6
- end
7
-
8
- private
9
-
10
- def normalize token
11
- case token.first
12
- when :unknown
13
- if time? token
14
- [:time, create_token_value(token.last.upcase)]
15
- else
16
- token
17
- end
18
- else token
19
- end
20
- end
21
-
22
- def time? token
23
- token_key = token.last.to_s.upcase
24
-
25
- %w(H AM PM :).any? do |s|
26
- token.last.to_s.upcase.include? s
27
- end
28
- end
29
-
30
- def create_token_value raw_value
31
- if raw_value.include? ':'
32
- hour, minute = raw_value.split(':')
33
-
34
- "#{adjust_hour(hour, raw_value)}:#{adjust_minute(minute)}"
35
- else
36
- #TODO
37
- raw_value
38
- end
39
- end
40
-
41
- def adjust_minute minute
42
- minute.to_i
43
- end
44
-
45
- def adjust_hour hour, raw_value
46
- if raw_value.include? 'PM'
47
- Time.parse("#{hour}pm").hour
48
- elsif raw_value.include? 'AM'
49
- Time.parse("#{hour}am").hour
50
- else
51
- hour.to_i
52
- end
53
- end
54
- end
55
- end