natural-date 1.2 → 1.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.
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