horai 0.7.0 → 0.7.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/README.md +120 -2
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/horai.gemspec +6 -4
- data/lib/horai.rb +5 -266
- data/lib/horai/parser.rb +102 -0
- data/lib/horai/parser/ja_jp.rb +203 -0
- data/spec/horai_spec.rb +55 -61
- metadata +26 -23
data/README.md
CHANGED
@@ -1,3 +1,121 @@
|
|
1
|
-
# What
|
1
|
+
# What to do
|
2
2
|
|
3
|
-
|
3
|
+
Derive DateTime from Time expression with Natural language
|
4
|
+
|
5
|
+
# Sample
|
6
|
+
|
7
|
+
jajp = Horai::JaJP.new
|
8
|
+
|
9
|
+
time = jajp.parse("1999年")
|
10
|
+
=> Fri, 01 Jan 1999 00:00:00 +0900
|
11
|
+
|
12
|
+
time = jajp.parse("1月")
|
13
|
+
=> Sun, 01 Jan 2012 00:00:00 +0900
|
14
|
+
|
15
|
+
time = jajp.parse("1時半")
|
16
|
+
=> Thu, 26 Apr 2012 01:30:00 +0900
|
17
|
+
|
18
|
+
time = jajp.parse("1分半後")
|
19
|
+
=> Thu, 26 Apr 2012 14:11:34 +0900
|
20
|
+
|
21
|
+
time = jajp.parse("5時間半と1分半後")
|
22
|
+
=> Thu, 26 Apr 2012 19:41:38 +0900
|
23
|
+
|
24
|
+
time = jajp.parse("夜の8時に")
|
25
|
+
=> Thu, 26 Apr 2012 20:00:00 +0900
|
26
|
+
|
27
|
+
time = jajp.parse("午後一時に")
|
28
|
+
=> Thu, 26 Apr 2012 13:00:00 +0900
|
29
|
+
|
30
|
+
time = jajp.parse("PM1時に")
|
31
|
+
=> Thu, 26 Apr 2012 13:00:00 +0900
|
32
|
+
|
33
|
+
time = jajp.parse("rpm 6時に")
|
34
|
+
=> Thu, 26 Apr 2012 06:00:00 +0900
|
35
|
+
|
36
|
+
time = jajp.parse("10日の正午に")
|
37
|
+
=> Tue, 10 Apr 2012 12:00:00 +0900
|
38
|
+
|
39
|
+
time = jajp.parse("10:20")
|
40
|
+
=> Thu, 26 Apr 2012 10:20:00 +0900
|
41
|
+
|
42
|
+
time = jajp.parse("10:20:30")
|
43
|
+
=> Thu, 26 Apr 2012 10:20:30 +0900
|
44
|
+
|
45
|
+
time = jajp.parse("10/20")
|
46
|
+
=> Sat, 20 Oct 2012 00:00:00 +0900
|
47
|
+
|
48
|
+
time = jajp.parse("2000/10/20")
|
49
|
+
=> Fri, 20 Oct 2000 00:00:00 +0900
|
50
|
+
|
51
|
+
time = jajp.parse("10/10/20")
|
52
|
+
=> Wed, 20 Oct 2010 00:00:00 +0900
|
53
|
+
|
54
|
+
time = jajp.parse("2000/10/20 12:30:40")
|
55
|
+
=> Fri, 20 Oct 2000 12:30:40 +0900
|
56
|
+
|
57
|
+
time = jajp.parse("10年")
|
58
|
+
=> Fri, 01 Jan 2010 00:00:00 +0900
|
59
|
+
|
60
|
+
time = jajp.parse("30年")
|
61
|
+
=> Tue, 01 Jan 2030 00:00:00 +0900
|
62
|
+
|
63
|
+
time = jajp.parse("90年")
|
64
|
+
=> Mon, 01 Jan 1990 00:00:00 +0900
|
65
|
+
|
66
|
+
time = jajp.parse("来年")
|
67
|
+
=> Tue, 01 Jan 2013 00:00:00 +0900
|
68
|
+
|
69
|
+
time = jajp.parse("来月")
|
70
|
+
=> Tue, 01 May 2012 00:00:00 +0900
|
71
|
+
|
72
|
+
time = jajp.parse("明日")
|
73
|
+
=> Fri, 27 Apr 2012 00:00:00 +0900
|
74
|
+
|
75
|
+
time = jajp.parse("明後日")
|
76
|
+
=> Sat, 28 Apr 2012 00:00:00 +0900
|
77
|
+
|
78
|
+
time = jajp.parse("昨日")
|
79
|
+
=> Wed, 25 Apr 2012 00:00:00 +0900
|
80
|
+
|
81
|
+
time = jajp.parse("10年後の8月")
|
82
|
+
=> Mon, 01 Aug 2022 00:00:00 +0900
|
83
|
+
|
84
|
+
time = jajp.parse("10分後")
|
85
|
+
=> Thu, 26 Apr 2012 14:20:27 +0900
|
86
|
+
|
87
|
+
time = jajp.parse("10日後")
|
88
|
+
=> Sun, 06 May 2012 14:10:27 +0900
|
89
|
+
|
90
|
+
time = jajp.parse("明日の10時")
|
91
|
+
=> Fri, 27 Apr 2012 10:00:00 +0900
|
92
|
+
|
93
|
+
time = jajp.parse("明日の10:20:30")
|
94
|
+
=> Fri, 27 Apr 2012 10:20:30 +0900
|
95
|
+
|
96
|
+
time = jajp.parse("明日の午後5時")
|
97
|
+
=> Fri, 27 Apr 2012 17:00:00 +0900
|
98
|
+
|
99
|
+
time = jajp.parse("明日の正午")
|
100
|
+
=> Fri, 27 Apr 2012 12:00:00 +0900
|
101
|
+
|
102
|
+
time = jajp.parse("3日後の12時")
|
103
|
+
=> Sun, 29 Apr 2012 12:00:00 +0900
|
104
|
+
|
105
|
+
time = jajp.parse("3日後の12時45分")
|
106
|
+
=> Sun, 29 Apr 2012 12:45:00 +0900
|
107
|
+
|
108
|
+
time = jajp.parse("3日後の12:45:55")
|
109
|
+
=> Sun, 29 Apr 2012 12:45:55 +0900
|
110
|
+
|
111
|
+
time = jajp.parse("3日12時間45分後")
|
112
|
+
=> Mon, 30 Apr 2012 02:55:27 +0900
|
113
|
+
|
114
|
+
time = jajp.parse("1時間半後")
|
115
|
+
=> Thu, 26 Apr 2012 15:40:27 +0900
|
116
|
+
|
117
|
+
time = jajp.parse("1分半後")
|
118
|
+
=> Thu, 26 Apr 2012 14:11:57 +0900
|
119
|
+
|
120
|
+
time = jajp.parse("5時間半と1分半後")
|
121
|
+
=> Thu, 26 Apr 2012 19:42:03 +0900
|
data/Rakefile
CHANGED
@@ -17,8 +17,8 @@ Jeweler::Tasks.new do |gem|
|
|
17
17
|
gem.name = "horai"
|
18
18
|
gem.homepage = "http://github.com/wneko/horai"
|
19
19
|
gem.license = "MIT"
|
20
|
-
gem.summary = "
|
21
|
-
gem.description = "
|
20
|
+
gem.summary = "Derive DateTime from Time expression with Natural language"
|
21
|
+
gem.description = "Derive DateTime from Time expression with Natural language (STILL ONLY IN JAPANESE)"
|
22
22
|
gem.email = "aoki@u-ne.co"
|
23
23
|
gem.authors = ["AOKI Yuuto"]
|
24
24
|
# dependencies defined in Gemfile
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.1
|
data/horai.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "horai"
|
8
|
-
s.version = "0.7.
|
8
|
+
s.version = "0.7.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["AOKI Yuuto"]
|
12
|
-
s.date = "2012-04-
|
13
|
-
s.description = "
|
12
|
+
s.date = "2012-04-26"
|
13
|
+
s.description = "Derive DateTime from Time expression with Natural language (STILL ONLY IN JAPANESE)"
|
14
14
|
s.email = "aoki@u-ne.co"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.txt",
|
@@ -27,6 +27,8 @@ Gem::Specification.new do |s|
|
|
27
27
|
"VERSION",
|
28
28
|
"horai.gemspec",
|
29
29
|
"lib/horai.rb",
|
30
|
+
"lib/horai/parser.rb",
|
31
|
+
"lib/horai/parser/ja_jp.rb",
|
30
32
|
"lib/ja_number.rb",
|
31
33
|
"spec/horai_spec.rb",
|
32
34
|
"spec/spec_helper.rb"
|
@@ -35,7 +37,7 @@ Gem::Specification.new do |s|
|
|
35
37
|
s.licenses = ["MIT"]
|
36
38
|
s.require_paths = ["lib"]
|
37
39
|
s.rubygems_version = "1.8.11"
|
38
|
-
s.summary = "
|
40
|
+
s.summary = "Derive DateTime from Time expression with Natural language"
|
39
41
|
|
40
42
|
if s.respond_to? :specification_version then
|
41
43
|
s.specification_version = 3
|
data/lib/horai.rb
CHANGED
@@ -1,272 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require '
|
4
|
-
require
|
5
|
-
|
6
|
-
class Horai
|
7
|
-
NORMALIZE_FROM = '0-9a-zA-Z:'
|
8
|
-
NORMALIZE_TO = '0-9a-zA-Z:'
|
9
|
-
|
10
|
-
DATE_DELIMITER = (/[\/-]/)
|
11
|
-
TIME_DELIMITER = (/[:]/)
|
12
|
-
|
13
|
-
AFTERNOON_PATTERN = (/午後|ごご|夜|よる|(?<![a-z])pm(?![a-z])/i)
|
14
|
-
RELATIVE_KEYWORDS_PATTERN = (/(?<![明午])後(?![年月日])|(?:[経た]っ|し)たら/)
|
15
|
-
RELATIVE_PATTERN = (/(\d+)(?:(?:年|ねん)|(?:月|がつ)|(?:日|にち)|(?:分|ふん|ぷん)|(?:時間?|じ(?:かん)?)|(?:秒|びょう))#{RELATIVE_KEYWORDS_PATTERN}/)
|
16
|
-
|
17
|
-
def self.filter(pattern, type = :absolute, &block)
|
18
|
-
@filters = [] if @filters.nil?
|
19
|
-
@filters << { pattern: pattern, type => block }
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.truncate_time(date)
|
23
|
-
datetime_delta(date, hour: 0, minute: 0, second: 0)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.datetime_delta(date, methods = {})
|
27
|
-
date = date.dup
|
28
|
-
methods.each_pair do |key, value|
|
29
|
-
converter = 1.0.respond_to?(key) ? :to_f : :to_i;
|
30
|
-
date += value.send(converter).send(key) - date.send(key).send(key)
|
31
|
-
end
|
32
|
-
date
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.register_filters
|
36
|
-
dd = DATE_DELIMITER
|
37
|
-
td = TIME_DELIMITER
|
38
|
-
|
39
|
-
# 年 (絶対)
|
40
|
-
filter /(\d+)年/, :absolute do |text, matches, date|
|
41
|
-
year = year_normalize(matches[1].to_i)
|
42
|
-
truncate_time(datetime_delta(date, year: year, month: 1, day: 1))
|
43
|
-
end
|
44
|
-
|
45
|
-
filter /一昨[々昨]年|さきおととし|いっさくさくねん/, :absolute do |text, matches, date|
|
46
|
-
truncate_time(datetime_delta(date - 3.year, month: 1, day: 1))
|
47
|
-
end
|
48
|
-
|
49
|
-
filter /一昨年|おととし|いっさくねん/, :absolute do |text, matches, date|
|
50
|
-
truncate_time(datetime_delta(date - 2.year, month: 1, day: 1))
|
51
|
-
end
|
52
|
-
|
53
|
-
filter /去年|昨年|きょねん|さくねん/, :absolute do |text, matches, date|
|
54
|
-
truncate_time(datetime_delta(date - 1.year, month: 1, day: 1))
|
55
|
-
end
|
56
|
-
|
57
|
-
filter /今年|本年|ことし|ほんねん/, :absolute do |text, matches, date|
|
58
|
-
end
|
59
|
-
|
60
|
-
filter /来年|明年|らいねん|みょうねん/, :absolute do |text, matches, date|
|
61
|
-
truncate_time(datetime_delta(date + 1.year, month: 1, day: 1))
|
62
|
-
end
|
63
|
-
|
64
|
-
filter /再来年|明後年|さらいねん|みょうごねん/, :absolute do |text, matches, date|
|
65
|
-
truncate_time(datetime_delta(date + 2.year, month: 1, day: 1))
|
66
|
-
end
|
67
|
-
|
68
|
-
filter /明[々明]後年|みょうみょうごねん/, :absolute do |text, matches, date|
|
69
|
-
truncate_time(datetime_delta(date + 3.year, month: 1, day: 1))
|
70
|
-
end
|
71
|
-
|
72
|
-
# 月 (絶対)
|
73
|
-
filter /(\d+)月/, :absolute do |text, matches, date|
|
74
|
-
truncate_time(datetime_delta(date, month: matches[1].to_i, day: 1))
|
75
|
-
end
|
76
|
-
|
77
|
-
filter /[先前][々先前]{3}月|せんせんせんげつ/, :absolute do |text, matches, date|
|
78
|
-
truncate_time(datetime_delta(date - 3.month, day: 1))
|
79
|
-
end
|
80
|
-
|
81
|
-
filter /[先前][々先前]月|せんせんげつ/, :absolute do |text, matches, date|
|
82
|
-
truncate_time(datetime_delta(date - 2.month, day: 1))
|
83
|
-
end
|
84
|
-
|
85
|
-
filter /先月|前月|せんげつ/, :absolute do |text, matches, date|
|
86
|
-
truncate_time(datetime_delta(date - 1.month, day: 1))
|
87
|
-
end
|
88
|
-
|
89
|
-
filter /今月|こんげつ/, :absolute do |text, matches, date|
|
90
|
-
end
|
91
|
-
|
92
|
-
filter /来月|らいげつ/, :absolute do |text, matches, date|
|
93
|
-
truncate_time(datetime_delta(date + 1.month, day: 1))
|
94
|
-
end
|
95
|
-
|
96
|
-
filter /再来月|来[々来]月|さらいげつ|らいらいげつ/, :absolute do |text, matches, date|
|
97
|
-
truncate_time(datetime_delta(date + 2.month, day: 1))
|
98
|
-
end
|
99
|
-
|
100
|
-
filter /再[々再]来月|ささらいげつ/, :absolute do |text, matches, date|
|
101
|
-
truncate_time(datetime_delta(date + 3.month, day: 1))
|
102
|
-
end
|
103
|
-
|
104
|
-
# 日 (絶対)
|
105
|
-
filter /(\d+)日/, :absolute do |text, matches, date|
|
106
|
-
truncate_time(datetime_delta(date, day: matches[1]))
|
107
|
-
end
|
108
|
-
|
109
|
-
filter /一昨[々昨]日|さきおと[とつ]い|いっさくさくじつ/, :absolute do |text, matches, date|
|
110
|
-
truncate_time(date - 3.day)
|
111
|
-
end
|
112
|
-
|
113
|
-
filter /一昨日|おと[とつ]い|いっさくじつ/, :absolute do |text, matches, date|
|
114
|
-
truncate_time(date - 2.day)
|
115
|
-
end
|
116
|
-
|
117
|
-
filter /昨日|きのう|さくじつ/, :absolute do |text, matches, date|
|
118
|
-
truncate_time(date - 1.day)
|
119
|
-
end
|
120
|
-
|
121
|
-
filter /明日|あした|みょうじつ/, :absolute do |text, matches, date|
|
122
|
-
truncate_time(date + 1.day)
|
123
|
-
end
|
124
|
-
|
125
|
-
filter /明後日|あさって|みょうごにち/, :absolute do |text, matches, date|
|
126
|
-
truncate_time(date + 2.day)
|
127
|
-
end
|
128
|
-
|
129
|
-
filter /明[々明]後日|しあさって|みょうみょうごにち/, :absolute do |text, matches, date|
|
130
|
-
truncate_time(date + 3.day)
|
131
|
-
end
|
132
|
-
|
133
|
-
# 月日表現 (絶対)
|
134
|
-
filter /(?<![\d\/-])(?<!\d)(\d{1,2})#{dd}(\d{1,2})(?!#{dd})/, :absolute do |text, matches, date|
|
135
|
-
truncate_time(datetime_delta(date, month: matches[1], day: matches[2]))
|
136
|
-
end
|
137
|
-
|
138
|
-
# 年月日表現 (絶対)
|
139
|
-
filter /(?<![\d\/-])(\d{1,2}|\d{4})#{dd}(\d{1,2})#{dd}(\d{1,2})(?!#{dd})/, :absolute do |text, matches, date|
|
140
|
-
year = year_normalize(matches[1].to_i)
|
141
|
-
truncate_time(datetime_delta(date, year: year, month: matches[2], day: matches[3]))
|
142
|
-
end
|
143
|
-
|
144
|
-
# 時分表現 (絶対)
|
145
|
-
filter /(?<![\d:])(\d{1,2})#{td}(\d{2})(?!#{td})/, :absolute do |text, matches, date|
|
146
|
-
datetime_delta(date, hour: matches[1], minute: matches[2], second: 0)
|
147
|
-
end
|
148
|
-
|
149
|
-
# 時分秒表現 (絶対)
|
150
|
-
filter /(?<![\d:])(\d{1,2})#{td}(\d{2})#{td}(\d{2})(?!#{td})/, :absolute do |text, matches, date|
|
151
|
-
datetime_delta(date, hour: matches[1], minute: matches[2], second: matches[3])
|
152
|
-
end
|
153
|
-
|
154
|
-
# 時間 (絶対)
|
155
|
-
filter /正午/, :absolute do |text, matches, date|
|
156
|
-
datetime_delta(date, hour: 12, minute: 0, second: 0)
|
157
|
-
end
|
158
|
-
|
159
|
-
filter /(\d+)時(半)?/, :absolute do |text, matches, date|
|
160
|
-
hour = matches[1]
|
161
|
-
minute = matches[2] ? 30 : 0
|
162
|
-
date = datetime_delta(date, hour: hour, minute: minute, second: 0)
|
163
|
-
date += 12.hour if date.hour <= 12 && text =~ AFTERNOON_PATTERN
|
164
|
-
date
|
165
|
-
end
|
166
|
-
|
167
|
-
filter /(\d+)分(半)?/, :absolute do |text, matches, date|
|
168
|
-
minute = matches[1]
|
169
|
-
second = matches[2] ? 30 : 0
|
170
|
-
datetime_delta(date, minute: minute, second: second)
|
171
|
-
end
|
172
|
-
|
173
|
-
filter /(\d+)秒/, :absolute do |text, matches, date|
|
174
|
-
datetime_delta(date, second: matches[1])
|
175
|
-
end
|
176
|
-
|
177
|
-
# 年 (相対)
|
178
|
-
filter /(\d+)年/, :relative do |text, matches, date|
|
179
|
-
date + matches[1].to_i.year
|
180
|
-
end
|
181
|
-
|
182
|
-
# 月 (相対)
|
183
|
-
filter /(\d+)月/, :relative do |text, matches, date|
|
184
|
-
date + matches[1].to_i.month
|
185
|
-
end
|
186
|
-
|
187
|
-
# 日 (相対)
|
188
|
-
filter /(\d+)日/, :relative do |text, matches, date|
|
189
|
-
date + matches[1].to_f.day
|
190
|
-
end
|
191
|
-
|
192
|
-
# 時間 (相対)
|
193
|
-
filter /(\d+)時間(半)?/, :relative do |text, matches, date|
|
194
|
-
date + matches[1].to_f.hour + (matches[2] ? 0.5 : 0.0).hour
|
195
|
-
end
|
196
|
-
|
197
|
-
filter /(\d+)分(半)?/, :relative do |text, matches, date|
|
198
|
-
date + matches[1].to_f.minute + (matches[2] ? 0.5 : 0.0).minute
|
199
|
-
end
|
200
|
-
|
201
|
-
filter /(\d+)秒/, :relative do |text, matches, date|
|
202
|
-
date + matches[1].to_f.second
|
203
|
-
end
|
204
|
-
|
205
|
-
end
|
206
|
-
|
207
|
-
def self.now
|
208
|
-
@now ||= DateTime.now
|
209
|
-
@now.dup
|
210
|
-
end
|
211
|
-
|
212
|
-
def self.filters
|
213
|
-
return @filters if @filters
|
214
|
-
register_filters
|
215
|
-
@filters
|
216
|
-
end
|
217
|
-
|
218
|
-
def self.relative?(text)
|
219
|
-
text =~ RELATIVE_PATTERN
|
220
|
-
end
|
3
|
+
require 'horai/parser'
|
4
|
+
require 'horai/parser/ja_jp'
|
221
5
|
|
6
|
+
module Horai
|
222
7
|
def self.parse(text)
|
223
|
-
|
224
|
-
|
225
|
-
date = now
|
226
|
-
|
227
|
-
filtered = false
|
228
|
-
|
229
|
-
contexts.each_with_index do |context, index|
|
230
|
-
if contexts.size >= 2 && index + 1 != contexts.size
|
231
|
-
mode = :relative
|
232
|
-
else
|
233
|
-
mode = :absolute
|
234
|
-
end
|
235
|
-
|
236
|
-
self.filters.each do |filter|
|
237
|
-
if (matches = context.match(filter[:pattern])) && filter[mode]
|
238
|
-
date = filter[mode].call(normalized, matches, date)
|
239
|
-
filtered = true unless filtered
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
@now = nil
|
245
|
-
|
246
|
-
return nil unless filtered
|
247
|
-
return date
|
248
|
-
end
|
249
|
-
|
250
|
-
def self.normalize(text)
|
251
|
-
normalized = text
|
252
|
-
normalized.tr!(NORMALIZE_FROM, NORMALIZE_TO)
|
253
|
-
digits = "一二三四五六七八九十百千"
|
254
|
-
classes = "万億兆"
|
255
|
-
normalized.gsub!(/[#{digits}][#{digits}#{classes}]*/) do |match|
|
256
|
-
JaNumber::JaNumberParser::parse(match)
|
257
|
-
end
|
258
|
-
return normalized
|
259
|
-
end
|
260
|
-
|
261
|
-
def self.year_normalize(year)
|
262
|
-
if year < 100
|
263
|
-
year_xx = (now.year / 100).to_i
|
264
|
-
if (year_xx - year).abs < 50
|
265
|
-
year += year_xx * 100
|
266
|
-
else
|
267
|
-
year += (year_xx - 1) * 100
|
268
|
-
end
|
269
|
-
end
|
270
|
-
year
|
8
|
+
@@instance ||= Horai::JaJP.new
|
9
|
+
@@instance.parse(text)
|
271
10
|
end
|
272
11
|
end
|
data/lib/horai/parser.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_support/time'
|
4
|
+
require "ja_number"
|
5
|
+
|
6
|
+
module Horai
|
7
|
+
class Parser
|
8
|
+
DATE_DELIMITER = (/[\/-]/)
|
9
|
+
TIME_DELIMITER = (/[:]/)
|
10
|
+
|
11
|
+
AFTERNOON_PATTERN = (/午後|ごご|夜|よる|(?<![a-z])pm(?![a-z])/i)
|
12
|
+
|
13
|
+
def self.parse(text)
|
14
|
+
@@instance ||= self.new
|
15
|
+
@@instance.parse(text)
|
16
|
+
end
|
17
|
+
|
18
|
+
def filter(pattern, type = :absolute, &block)
|
19
|
+
@filters = [] if @filters.nil?
|
20
|
+
@filters << { pattern: pattern, type => block }
|
21
|
+
end
|
22
|
+
|
23
|
+
def truncate_time(date)
|
24
|
+
datetime_delta(date, hour: 0, minute: 0, second: 0)
|
25
|
+
end
|
26
|
+
|
27
|
+
def datetime_delta(date, methods = {})
|
28
|
+
date = date.dup
|
29
|
+
methods.each_pair do |key, value|
|
30
|
+
converter = 1.0.respond_to?(key) ? :to_f : :to_i;
|
31
|
+
date += value.send(converter).send(key) - date.send(key).send(key)
|
32
|
+
end
|
33
|
+
date
|
34
|
+
end
|
35
|
+
|
36
|
+
def register_filters
|
37
|
+
end
|
38
|
+
|
39
|
+
def now
|
40
|
+
@now ||= DateTime.now
|
41
|
+
@now.dup
|
42
|
+
end
|
43
|
+
|
44
|
+
def filters
|
45
|
+
return @filters if @filters
|
46
|
+
register_filters
|
47
|
+
@filters
|
48
|
+
end
|
49
|
+
|
50
|
+
def relative_keyword_patterns
|
51
|
+
/after/
|
52
|
+
end
|
53
|
+
|
54
|
+
def relative?(text)
|
55
|
+
text =~ relative_keyword_patterns
|
56
|
+
end
|
57
|
+
|
58
|
+
def normalize(text)
|
59
|
+
text
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse(text)
|
63
|
+
normalized = normalize(text)
|
64
|
+
contexts = (normalized + "$").split(relative_keyword_patterns)
|
65
|
+
date = now
|
66
|
+
|
67
|
+
filtered = false
|
68
|
+
|
69
|
+
contexts.each_with_index do |context, index|
|
70
|
+
if contexts.size >= 2 && index + 1 != contexts.size
|
71
|
+
mode = :relative
|
72
|
+
else
|
73
|
+
mode = :absolute
|
74
|
+
end
|
75
|
+
|
76
|
+
filters.each do |filter|
|
77
|
+
if (matches = context.match(filter[:pattern])) && filter[mode]
|
78
|
+
date = filter[mode].call(normalized, matches, date)
|
79
|
+
filtered = true unless filtered
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
@now = nil
|
85
|
+
|
86
|
+
return nil unless filtered
|
87
|
+
return date
|
88
|
+
end
|
89
|
+
|
90
|
+
def year_normalize(year)
|
91
|
+
if year < 100
|
92
|
+
year_xx = (now.year / 100).to_i
|
93
|
+
if (year_xx - year).abs < 50
|
94
|
+
year += year_xx * 100
|
95
|
+
else
|
96
|
+
year += (year_xx - 1) * 100
|
97
|
+
end
|
98
|
+
end
|
99
|
+
year
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'horai/parser'
|
4
|
+
|
5
|
+
module Horai
|
6
|
+
class JaJP < Parser
|
7
|
+
NORMALIZE_FROM = '0-9a-zA-Z:'
|
8
|
+
NORMALIZE_TO = '0-9a-zA-Z:'
|
9
|
+
|
10
|
+
AFTERNOON_PATTERN = (/午後|ごご|夜|よる|(?<![a-z])pm(?![a-z])/i)
|
11
|
+
|
12
|
+
def register_filters
|
13
|
+
dd = DATE_DELIMITER
|
14
|
+
td = TIME_DELIMITER
|
15
|
+
|
16
|
+
# 年 (絶対)
|
17
|
+
filter /(\d+)年/, :absolute do |text, matches, date|
|
18
|
+
year = year_normalize(matches[1].to_i)
|
19
|
+
truncate_time(datetime_delta(date, year: year, month: 1, day: 1))
|
20
|
+
end
|
21
|
+
|
22
|
+
filter /一昨[々昨]年|さきおととし|いっさくさくねん/, :absolute do |text, matches, date|
|
23
|
+
truncate_time(datetime_delta(date - 3.year, month: 1, day: 1))
|
24
|
+
end
|
25
|
+
|
26
|
+
filter /一昨年|おととし|いっさくねん/, :absolute do |text, matches, date|
|
27
|
+
truncate_time(datetime_delta(date - 2.year, month: 1, day: 1))
|
28
|
+
end
|
29
|
+
|
30
|
+
filter /去年|昨年|きょねん|さくねん/, :absolute do |text, matches, date|
|
31
|
+
truncate_time(datetime_delta(date - 1.year, month: 1, day: 1))
|
32
|
+
end
|
33
|
+
|
34
|
+
filter /今年|本年|ことし|ほんねん/, :absolute do |text, matches, date|
|
35
|
+
end
|
36
|
+
|
37
|
+
filter /来年|明年|らいねん|みょうねん/, :absolute do |text, matches, date|
|
38
|
+
truncate_time(datetime_delta(date + 1.year, month: 1, day: 1))
|
39
|
+
end
|
40
|
+
|
41
|
+
filter /再来年|明後年|さらいねん|みょうごねん/, :absolute do |text, matches, date|
|
42
|
+
truncate_time(datetime_delta(date + 2.year, month: 1, day: 1))
|
43
|
+
end
|
44
|
+
|
45
|
+
filter /明[々明]後年|みょうみょうごねん/, :absolute do |text, matches, date|
|
46
|
+
truncate_time(datetime_delta(date + 3.year, month: 1, day: 1))
|
47
|
+
end
|
48
|
+
|
49
|
+
# 月 (絶対)
|
50
|
+
filter /(\d+)月/, :absolute do |text, matches, date|
|
51
|
+
truncate_time(datetime_delta(date, month: matches[1].to_i, day: 1))
|
52
|
+
end
|
53
|
+
|
54
|
+
filter /[先前][々先前]{3}月|せんせんせんげつ/, :absolute do |text, matches, date|
|
55
|
+
truncate_time(datetime_delta(date - 3.month, day: 1))
|
56
|
+
end
|
57
|
+
|
58
|
+
filter /[先前][々先前]月|せんせんげつ/, :absolute do |text, matches, date|
|
59
|
+
truncate_time(datetime_delta(date - 2.month, day: 1))
|
60
|
+
end
|
61
|
+
|
62
|
+
filter /先月|前月|せんげつ/, :absolute do |text, matches, date|
|
63
|
+
truncate_time(datetime_delta(date - 1.month, day: 1))
|
64
|
+
end
|
65
|
+
|
66
|
+
filter /今月|こんげつ/, :absolute do |text, matches, date|
|
67
|
+
end
|
68
|
+
|
69
|
+
filter /来月|らいげつ/, :absolute do |text, matches, date|
|
70
|
+
truncate_time(datetime_delta(date + 1.month, day: 1))
|
71
|
+
end
|
72
|
+
|
73
|
+
filter /再来月|来[々来]月|さらいげつ|らいらいげつ/, :absolute do |text, matches, date|
|
74
|
+
truncate_time(datetime_delta(date + 2.month, day: 1))
|
75
|
+
end
|
76
|
+
|
77
|
+
filter /再[々再]来月|ささらいげつ/, :absolute do |text, matches, date|
|
78
|
+
truncate_time(datetime_delta(date + 3.month, day: 1))
|
79
|
+
end
|
80
|
+
|
81
|
+
# 日 (絶対)
|
82
|
+
filter /(\d+)日/, :absolute do |text, matches, date|
|
83
|
+
truncate_time(datetime_delta(date, day: matches[1]))
|
84
|
+
end
|
85
|
+
|
86
|
+
filter /一昨[々昨]日|さきおと[とつ]い|いっさくさくじつ/, :absolute do |text, matches, date|
|
87
|
+
truncate_time(date - 3.day)
|
88
|
+
end
|
89
|
+
|
90
|
+
filter /一昨日|おと[とつ]い|いっさくじつ/, :absolute do |text, matches, date|
|
91
|
+
truncate_time(date - 2.day)
|
92
|
+
end
|
93
|
+
|
94
|
+
filter /昨日|きのう|さくじつ/, :absolute do |text, matches, date|
|
95
|
+
truncate_time(date - 1.day)
|
96
|
+
end
|
97
|
+
|
98
|
+
filter /明日|あした|みょうじつ/, :absolute do |text, matches, date|
|
99
|
+
truncate_time(date + 1.day)
|
100
|
+
end
|
101
|
+
|
102
|
+
filter /明後日|あさって|みょうごにち/, :absolute do |text, matches, date|
|
103
|
+
truncate_time(date + 2.day)
|
104
|
+
end
|
105
|
+
|
106
|
+
filter /明[々明]後日|しあさって|みょうみょうごにち/, :absolute do |text, matches, date|
|
107
|
+
truncate_time(date + 3.day)
|
108
|
+
end
|
109
|
+
|
110
|
+
# 月日表現 (絶対)
|
111
|
+
filter /(?<![\d\/-])(?<!\d)(\d{1,2})#{dd}(\d{1,2})(?!#{dd})/, :absolute do |text, matches, date|
|
112
|
+
truncate_time(datetime_delta(date, month: matches[1], day: matches[2]))
|
113
|
+
end
|
114
|
+
|
115
|
+
# 年月日表現 (絶対)
|
116
|
+
filter /(?<![\d\/-])(\d{1,2}|\d{4})#{dd}(\d{1,2})#{dd}(\d{1,2})(?!#{dd})/, :absolute do |text, matches, date|
|
117
|
+
year = year_normalize(matches[1].to_i)
|
118
|
+
truncate_time(datetime_delta(date, year: year, month: matches[2], day: matches[3]))
|
119
|
+
end
|
120
|
+
|
121
|
+
# 時分表現 (絶対)
|
122
|
+
filter /(?<![\d:])(\d{1,2})#{td}(\d{2})(?!#{td})/, :absolute do |text, matches, date|
|
123
|
+
datetime_delta(date, hour: matches[1], minute: matches[2], second: 0)
|
124
|
+
end
|
125
|
+
|
126
|
+
# 時分秒表現 (絶対)
|
127
|
+
filter /(?<![\d:])(\d{1,2})#{td}(\d{2})#{td}(\d{2})(?!#{td})/, :absolute do |text, matches, date|
|
128
|
+
datetime_delta(date, hour: matches[1], minute: matches[2], second: matches[3])
|
129
|
+
end
|
130
|
+
|
131
|
+
# 時間 (絶対)
|
132
|
+
filter /正午/, :absolute do |text, matches, date|
|
133
|
+
datetime_delta(date, hour: 12, minute: 0, second: 0)
|
134
|
+
end
|
135
|
+
|
136
|
+
filter /(\d+)時(半)?/, :absolute do |text, matches, date|
|
137
|
+
hour = matches[1]
|
138
|
+
minute = matches[2] ? 30 : 0
|
139
|
+
date = datetime_delta(date, hour: hour, minute: minute, second: 0)
|
140
|
+
date += 12.hour if date.hour <= 12 && text =~ AFTERNOON_PATTERN
|
141
|
+
date
|
142
|
+
end
|
143
|
+
|
144
|
+
filter /(\d+)分(半)?/, :absolute do |text, matches, date|
|
145
|
+
minute = matches[1]
|
146
|
+
second = matches[2] ? 30 : 0
|
147
|
+
datetime_delta(date, minute: minute, second: second)
|
148
|
+
end
|
149
|
+
|
150
|
+
filter /(\d+)秒/, :absolute do |text, matches, date|
|
151
|
+
datetime_delta(date, second: matches[1])
|
152
|
+
end
|
153
|
+
|
154
|
+
# 年 (相対)
|
155
|
+
filter /(\d+)年/, :relative do |text, matches, date|
|
156
|
+
date + matches[1].to_i.year
|
157
|
+
end
|
158
|
+
|
159
|
+
# 月 (相対)
|
160
|
+
filter /(\d+)月/, :relative do |text, matches, date|
|
161
|
+
date + matches[1].to_i.month
|
162
|
+
end
|
163
|
+
|
164
|
+
# 日 (相対)
|
165
|
+
filter /(\d+)日/, :relative do |text, matches, date|
|
166
|
+
date + matches[1].to_f.day
|
167
|
+
end
|
168
|
+
|
169
|
+
# 時間 (相対)
|
170
|
+
filter /(\d+)時間(半)?/, :relative do |text, matches, date|
|
171
|
+
date + matches[1].to_f.hour + (matches[2] ? 0.5 : 0.0).hour
|
172
|
+
end
|
173
|
+
|
174
|
+
filter /(\d+)分(半)?/, :relative do |text, matches, date|
|
175
|
+
date + matches[1].to_f.minute + (matches[2] ? 0.5 : 0.0).minute
|
176
|
+
end
|
177
|
+
|
178
|
+
filter /(\d+)秒/, :relative do |text, matches, date|
|
179
|
+
date + matches[1].to_f.second
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def relative_keyword_patterns
|
184
|
+
(/(?<![明午])後(?![年月日])|(?:[経た]っ|し)たら/)
|
185
|
+
end
|
186
|
+
|
187
|
+
def relative?(text)
|
188
|
+
unit = /(?:年|ねん)|(?:月|がつ)|(?:日|にち)|(?:分|ふん|ぷん)|(?:時間?|じ(?:かん)?)|(?:秒|びょう)/
|
189
|
+
text =~ (/(\d+)#{unit}#{relative_keyword_patterns}/)
|
190
|
+
end
|
191
|
+
|
192
|
+
def normalize(text)
|
193
|
+
normalized = text
|
194
|
+
normalized.tr!(NORMALIZE_FROM, NORMALIZE_TO)
|
195
|
+
digits = "一二三四五六七八九十百千"
|
196
|
+
classes = "万億兆"
|
197
|
+
normalized.gsub!(/[#{digits}][#{digits}#{classes}]*/) do |match|
|
198
|
+
JaNumber::JaNumberParser::parse(match)
|
199
|
+
end
|
200
|
+
return normalized
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
data/spec/horai_spec.rb
CHANGED
@@ -2,16 +2,10 @@
|
|
2
2
|
|
3
3
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
4
4
|
|
5
|
-
|
6
|
-
@now ||= Horai::now
|
5
|
+
$jajp = Horai::JaJP.new
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
# day || @now.day,
|
11
|
-
# hour || @now.hour,
|
12
|
-
# minute || @now.minute,
|
13
|
-
# second || @now.second,
|
14
|
-
# Rational(9, 24)].join(',') + "}"
|
7
|
+
def now (year = nil, month = nil, day = nil, hour = nil, minute = nil, second = nil)
|
8
|
+
@now ||= $jajp.now
|
15
9
|
|
16
10
|
DateTime.new(year || @now.year,
|
17
11
|
month || @now.month,
|
@@ -25,25 +19,25 @@ end
|
|
25
19
|
describe Horai do
|
26
20
|
context 'normalize' do
|
27
21
|
it "number" do
|
28
|
-
|
22
|
+
$jajp.normalize('01234').should === '01234'
|
29
23
|
end
|
30
24
|
it "alphabet" do
|
31
|
-
|
32
|
-
|
25
|
+
$jajp.normalize('abcde').should === 'abcde'
|
26
|
+
$jajp.normalize('ABCDE').should === 'ABCDE'
|
33
27
|
end
|
34
28
|
it "numeric kanji" do
|
35
|
-
|
36
|
-
|
37
|
-
|
29
|
+
$jajp.normalize('十五').should === '15'
|
30
|
+
$jajp.normalize('十四万二千三百四十五').should === '142345'
|
31
|
+
$jajp.normalize('百五十時間後').should === '150時間後'
|
38
32
|
|
39
33
|
pending "漢数字パースライブラリがだめ"
|
40
|
-
|
34
|
+
$jajp.normalize('1万秒').should === '10000秒'
|
41
35
|
end
|
42
36
|
end
|
43
37
|
|
44
38
|
context 'invalid cases' do
|
45
39
|
it 'not even one filter passed' do
|
46
|
-
|
40
|
+
$jajp.parse("なにもなし").should be_nil
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
@@ -53,169 +47,169 @@ describe Horai do
|
|
53
47
|
@sample_text = @sample_date.strftime('%Y年%m月%d日の%H時%M分%S秒')
|
54
48
|
end
|
55
49
|
it "year, month, day, hour, minute, second" do
|
56
|
-
time =
|
50
|
+
time = $jajp.parse(@sample_text)
|
57
51
|
time.to_s.should === @sample_date.to_s
|
58
52
|
end
|
59
53
|
it "year" do
|
60
|
-
time =
|
54
|
+
time = $jajp.parse("1999年")
|
61
55
|
time.to_s.should === now(1999, 1, 1, 0, 0, 0).to_s
|
62
56
|
end
|
63
57
|
it "month" do
|
64
|
-
time =
|
58
|
+
time = $jajp.parse("1月")
|
65
59
|
time.to_s.should === now(nil, 1, 1, 0, 0, 0).to_s
|
66
60
|
end
|
67
61
|
it "half time" do
|
68
|
-
time =
|
62
|
+
time = $jajp.parse("1時半")
|
69
63
|
time.to_s.should === now(nil, nil, nil, 1, 30, 0).to_s
|
70
64
|
end
|
71
65
|
it "half minute" do
|
72
|
-
time =
|
66
|
+
time = $jajp.parse("1分半後")
|
73
67
|
time.to_s.should === (now + 1.5.minute).to_s
|
74
68
|
end
|
75
69
|
it "half hour and minute" do
|
76
|
-
time =
|
70
|
+
time = $jajp.parse("5時間半と1分半後")
|
77
71
|
time.to_s.should === (now + 5.5.hour + 1.5.minute).to_s
|
78
72
|
end
|
79
73
|
it "at night" do
|
80
|
-
time =
|
74
|
+
time = $jajp.parse("夜の8時に")
|
81
75
|
time.to_s.should === (now(nil, nil, nil, 20, 0, 0)).to_s
|
82
76
|
end
|
83
77
|
it "at afternoon" do
|
84
|
-
time =
|
78
|
+
time = $jajp.parse("午後一時に")
|
85
79
|
time.to_s.should === (now(nil, nil, nil, 13, 0, 0)).to_s
|
86
80
|
end
|
87
81
|
it "at afternoon" do
|
88
|
-
time =
|
82
|
+
time = $jajp.parse("PM1時に")
|
89
83
|
time.to_s.should === (now(nil, nil, nil, 13, 0, 0)).to_s
|
90
84
|
end
|
91
85
|
it "at AM and contains *pm*" do
|
92
|
-
time =
|
86
|
+
time = $jajp.parse("rpm 6時に")
|
93
87
|
time.to_s.should === (now(nil, nil, nil, 6, 0, 0)).to_s
|
94
88
|
end
|
95
89
|
it "at noon" do
|
96
|
-
time =
|
90
|
+
time = $jajp.parse("10日の正午に")
|
97
91
|
time.to_s.should === (now(nil, nil, 10, 12, 0, 0)).to_s
|
98
92
|
end
|
99
93
|
it "at hh:mm" do
|
100
|
-
time =
|
94
|
+
time = $jajp.parse("10:20")
|
101
95
|
time.to_s.should === (now(nil, nil, nil, 10, 20, 0)).to_s
|
102
96
|
end
|
103
97
|
it "at hh:mm:ss" do
|
104
|
-
time =
|
98
|
+
time = $jajp.parse("10:20:30")
|
105
99
|
time.to_s.should === (now(nil, nil, nil, 10, 20, 30)).to_s
|
106
100
|
end
|
107
101
|
it "at MM/DD" do
|
108
|
-
time =
|
102
|
+
time = $jajp.parse("10/20")
|
109
103
|
time.to_s.should === now(nil, 10, 20, 0, 0, 0).to_s
|
110
104
|
end
|
111
105
|
it "at YYYY/MM/DD" do
|
112
|
-
time =
|
106
|
+
time = $jajp.parse("2000/10/20")
|
113
107
|
time.to_s.should === now(2000, 10, 20, 0, 0, 0).to_s
|
114
108
|
end
|
115
109
|
it "at YY/MM/DD" do
|
116
|
-
time =
|
110
|
+
time = $jajp.parse("10/10/20")
|
117
111
|
time.to_s.should === now(2010, 10, 20, 0, 0, 0).to_s
|
118
112
|
end
|
119
113
|
it "at YYYY/MM/DD hh:mm:ss" do
|
120
|
-
time =
|
114
|
+
time = $jajp.parse("2000/10/20 12:30:40")
|
121
115
|
time.to_s.should === now(2000, 10, 20, 12, 30, 40).to_s
|
122
116
|
end
|
123
117
|
it "at YY (near current year)" do
|
124
|
-
time =
|
118
|
+
time = $jajp.parse("10年")
|
125
119
|
time.to_s.should === now(2010, 1, 1, 0, 0, 0).to_s
|
126
120
|
end
|
127
121
|
it "at YY (near feature)" do
|
128
|
-
time =
|
122
|
+
time = $jajp.parse("30年")
|
129
123
|
time.to_s.should === now(2030, 1, 1, 0, 0, 0).to_s
|
130
124
|
end
|
131
125
|
it "at YY (not near feature)" do
|
132
|
-
time =
|
126
|
+
time = $jajp.parse("90年")
|
133
127
|
time.to_s.should === now(1990, 1, 1, 0, 0, 0).to_s
|
134
128
|
end
|
135
129
|
end
|
136
130
|
|
137
131
|
context 'parse relative' do
|
138
132
|
it "check" do
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
133
|
+
$jajp.relative?("10分後").should be_true
|
134
|
+
$jajp.relative?("10分経ったら").should be_true
|
135
|
+
$jajp.relative?("10分したら").should be_true
|
136
|
+
$jajp.relative?("10分").should be_false
|
137
|
+
$jajp.relative?("10時10分").should be_false
|
144
138
|
end
|
145
139
|
it "next year" do
|
146
|
-
time =
|
140
|
+
time = $jajp.parse("来年")
|
147
141
|
time.to_s.should === (now(nil, 1, 1, 0, 0, 0) + 1.year).to_s
|
148
142
|
end
|
149
143
|
it "next month" do
|
150
|
-
time =
|
144
|
+
time = $jajp.parse("来月")
|
151
145
|
time.to_s.should === (now(nil, nil, 1, 0, 0, 0) + 1.month).to_s
|
152
146
|
end
|
153
147
|
it "tomorrow" do
|
154
|
-
time =
|
148
|
+
time = $jajp.parse("明日")
|
155
149
|
time.to_s.should === (now(nil, nil, nil, 0, 0, 0) + 1.day).to_s
|
156
150
|
end
|
157
151
|
it "day after tomorrow" do
|
158
|
-
time =
|
152
|
+
time = $jajp.parse("明後日")
|
159
153
|
time.to_s.should === (now(nil, nil, nil, 0, 0, 0) + 2.day).to_s
|
160
154
|
end
|
161
155
|
it "yesterday" do
|
162
|
-
time =
|
156
|
+
time = $jajp.parse("昨日")
|
163
157
|
time.to_s.should === (now(nil, nil, nil, 0, 0, 0) - 1.day).to_s
|
164
158
|
end
|
165
159
|
it "numeric year after and absolute month" do
|
166
|
-
time =
|
160
|
+
time = $jajp.parse("10年後の8月")
|
167
161
|
time.to_s.should === (now(nil, 8, 1, 0, 0, 0) + 10.year).to_s
|
168
162
|
end
|
169
163
|
it "numeric minute after" do
|
170
|
-
time =
|
164
|
+
time = $jajp.parse("10分後")
|
171
165
|
time.to_s.should === (now + 10.minute).to_s
|
172
166
|
end
|
173
167
|
it "numeric day after" do
|
174
|
-
time =
|
168
|
+
time = $jajp.parse("10日後")
|
175
169
|
time.to_s.should === (now + 10.day).to_s
|
176
170
|
end
|
177
171
|
it "tomorrow and absolute time" do
|
178
|
-
time =
|
172
|
+
time = $jajp.parse("明日の10時")
|
179
173
|
time.to_s.should === (now(nil, nil, nil, 10, 0, 0) + 1.day).to_s
|
180
174
|
end
|
181
175
|
it "tomorrow and absolute hh:mm:ss" do
|
182
|
-
time =
|
176
|
+
time = $jajp.parse("明日の10:20:30")
|
183
177
|
time.to_s.should === (now(nil, nil, nil, 10, 20, 30) + 1.day).to_s
|
184
178
|
end
|
185
179
|
it "tomorrow and afternoon" do
|
186
|
-
time =
|
180
|
+
time = $jajp.parse("明日の午後5時")
|
187
181
|
time.to_s.should === (now(nil, nil, nil, 17, 0, 0) + 1.day).to_s
|
188
182
|
end
|
189
183
|
it "tomorrow and noon" do
|
190
|
-
time =
|
184
|
+
time = $jajp.parse("明日の正午")
|
191
185
|
time.to_s.should === (now(nil, nil, nil, 12, 0, 0) + 1.day).to_s
|
192
186
|
end
|
193
187
|
it "numeric day after and absolute time" do
|
194
|
-
time =
|
188
|
+
time = $jajp.parse("3日後の12時")
|
195
189
|
time.to_s.should === (now(nil, nil, nil, 12, 0, 0) + 3.day).to_s
|
196
190
|
end
|
197
191
|
it "numeric day after and absolute time" do
|
198
|
-
time =
|
192
|
+
time = $jajp.parse("3日後の12時45分")
|
199
193
|
time.to_s.should === (now(nil, nil, nil, 12, 45, 0) + 3.day).to_s
|
200
194
|
end
|
201
195
|
it "numeric day after and absolute hh:mm:ss" do
|
202
|
-
time =
|
196
|
+
time = $jajp.parse("3日後の12:45:55")
|
203
197
|
time.to_s.should === (now(nil, nil, nil, 12, 45, 55) + 3.day).to_s
|
204
198
|
end
|
205
199
|
it "numeric day after and relative time" do
|
206
|
-
time =
|
200
|
+
time = $jajp.parse("3日12時間45分後")
|
207
201
|
time.to_s.should === (now + 3.day + 12.hour + 45.minute).to_s
|
208
202
|
end
|
209
203
|
it "half time after" do
|
210
|
-
time =
|
204
|
+
time = $jajp.parse("1時間半後")
|
211
205
|
time.to_s.should === (now + 1.5.hour).to_s
|
212
206
|
end
|
213
207
|
it "half minute after" do
|
214
|
-
time =
|
208
|
+
time = $jajp.parse("1分半後")
|
215
209
|
time.to_s.should === (now + 1.5.minute).to_s
|
216
210
|
end
|
217
211
|
it "half hour and half minute after" do
|
218
|
-
time =
|
212
|
+
time = $jajp.parse("5時間半と1分半後")
|
219
213
|
time.to_s.should === (now + 5.5.hour + 1.5.minute).to_s
|
220
214
|
end
|
221
215
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: horai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: i18n
|
16
|
-
requirement: &
|
16
|
+
requirement: &2171462920 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.6.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2171462920
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
requirement: &
|
27
|
+
requirement: &2171462420 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 3.0.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2171462420
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rparsec-ruby19
|
38
|
-
requirement: &
|
38
|
+
requirement: &2171461920 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2171461920
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &2171461380 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 2.8.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2171461380
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rdoc
|
60
|
-
requirement: &
|
60
|
+
requirement: &2171460260 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '3.12'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2171460260
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: jeweler
|
71
|
-
requirement: &
|
71
|
+
requirement: &2171459280 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 1.8.3
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2171459280
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: guard-shell
|
82
|
-
requirement: &
|
82
|
+
requirement: &2171458480 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *2171458480
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: guard-rspec
|
93
|
-
requirement: &
|
93
|
+
requirement: &2171281160 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *2171281160
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: pry
|
104
|
-
requirement: &
|
104
|
+
requirement: &2171280460 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,8 +109,9 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
113
|
-
description:
|
112
|
+
version_requirements: *2171280460
|
113
|
+
description: Derive DateTime from Time expression with Natural language (STILL ONLY
|
114
|
+
IN JAPANESE)
|
114
115
|
email: aoki@u-ne.co
|
115
116
|
executables: []
|
116
117
|
extensions: []
|
@@ -128,6 +129,8 @@ files:
|
|
128
129
|
- VERSION
|
129
130
|
- horai.gemspec
|
130
131
|
- lib/horai.rb
|
132
|
+
- lib/horai/parser.rb
|
133
|
+
- lib/horai/parser/ja_jp.rb
|
131
134
|
- lib/ja_number.rb
|
132
135
|
- spec/horai_spec.rb
|
133
136
|
- spec/spec_helper.rb
|
@@ -146,7 +149,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
149
|
version: '0'
|
147
150
|
segments:
|
148
151
|
- 0
|
149
|
-
hash:
|
152
|
+
hash: 60693043854403678
|
150
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
154
|
none: false
|
152
155
|
requirements:
|
@@ -158,5 +161,5 @@ rubyforge_project:
|
|
158
161
|
rubygems_version: 1.8.11
|
159
162
|
signing_key:
|
160
163
|
specification_version: 3
|
161
|
-
summary:
|
164
|
+
summary: Derive DateTime from Time expression with Natural language
|
162
165
|
test_files: []
|