chronic-l10n 0.0.1.pre
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 +18 -0
- data/HISTORY.md +3 -0
- data/LICENSE +21 -0
- data/README.md +76 -0
- data/Rakefile +46 -0
- data/chronic-l10n.gemspec +21 -0
- data/lib/chronic-l10n/pt_br.rb +213 -0
- data/lib/chronic-l10n.rb +13 -0
- data/test/helper.rb +13 -0
- data/test/test_parsing_pt_br.rb +997 -0
- metadata +110 -0
data/.gitignore
ADDED
data/HISTORY.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) Luan Santos
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all 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,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
Chronic
|
2
|
+
=======
|
3
|
+
|
4
|
+
## DESCRIPTION
|
5
|
+
|
6
|
+
Chronic is a natural language date/time parser written in pure Ruby. See below
|
7
|
+
for the wide variety of formats Chronic-L10n will parse.
|
8
|
+
|
9
|
+
|
10
|
+
## INSTALLATION
|
11
|
+
|
12
|
+
### RubyGems
|
13
|
+
|
14
|
+
$ [sudo] gem install chronic-l10n
|
15
|
+
|
16
|
+
### GitHub
|
17
|
+
|
18
|
+
$ git clone git://github.com/luan/chronic-l10n.git
|
19
|
+
$ cd chronic-l10n && gem build chronic-l10n.gemspec
|
20
|
+
$ gem install chronic-l10n-<version>.gem
|
21
|
+
|
22
|
+
|
23
|
+
## USAGE
|
24
|
+
|
25
|
+
You can parse strings containing a natural language date using the
|
26
|
+
`Chronic.parse` method.
|
27
|
+
|
28
|
+
require 'chronic'
|
29
|
+
require 'chronic-l10n'
|
30
|
+
|
31
|
+
Time.now #=> Sun Aug 27 23:18:25 PDT 2006
|
32
|
+
|
33
|
+
Chronic.locale = :'pt-BR'
|
34
|
+
|
35
|
+
Chronic.parse('amanhã')
|
36
|
+
#=> Mon Aug 28 12:00:00 PDT 2006
|
37
|
+
|
38
|
+
Chronic.parse('segunda', :context => :past)
|
39
|
+
#=> Mon Aug 21 12:00:00 PDT 2006
|
40
|
+
|
41
|
+
Chronic.parse('essa terça 5:00')
|
42
|
+
#=> Tue Aug 29 17:00:00 PDT 2006
|
43
|
+
|
44
|
+
Chronic.parse('essa terça 5:00', :ambiguous_time_range => :none)
|
45
|
+
#=> Tue Aug 29 05:00:00 PDT 2006
|
46
|
+
|
47
|
+
Chronic.parse('27 de maio', :now => Time.local(2000, 1, 1))
|
48
|
+
#=> Sat May 27 12:00:00 PDT 2000
|
49
|
+
|
50
|
+
Chronic.parse('27 de maio', :guess => false)
|
51
|
+
#=> Sun May 27 00:00:00 PDT 2007..Mon May 28 00:00:00 PDT 2007
|
52
|
+
|
53
|
+
Chronic.parse('6/4/2012', :endian_precedence => :little)
|
54
|
+
#=> Fri Apr 06 00:00:00 PDT 2012
|
55
|
+
|
56
|
+
|
57
|
+
See `Chronic.parse` for detailed usage instructions.
|
58
|
+
|
59
|
+
## CONTRIBUTE
|
60
|
+
|
61
|
+
You might like to add your language or improve some already available language, start by forking the repo on GitHub:
|
62
|
+
|
63
|
+
https://github.com/luan/chronic-l10n
|
64
|
+
|
65
|
+
The best way to get your changes merged back into core is as follows:
|
66
|
+
|
67
|
+
1. Clone down your fork
|
68
|
+
1. Create a thoughtfully named topic branch to contain your change
|
69
|
+
1. Hack away
|
70
|
+
1. Add tests and make sure everything still passes by running `rake`
|
71
|
+
1. Ensure your tests pass in multiple timezones. ie `TZ=utc rake` `TZ=BST rake`
|
72
|
+
1. If you are adding new functionality, document it in the README
|
73
|
+
1. Do not change the version number, we will do that on our end
|
74
|
+
1. If necessary, rebase your commits into logical chunks, without errors
|
75
|
+
1. Push the branch up to GitHub
|
76
|
+
1. Send a pull request for your branch
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
def version
|
4
|
+
contents = File.read File.expand_path('../lib/chronic-l10n.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-l10n"
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Release Chronic-L10n 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-l10n-#{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-l10n.gemspec"
|
43
|
+
sh "mv chronic-l10n-#{version}.gem pkg"
|
44
|
+
end
|
45
|
+
|
46
|
+
task :default => :test
|
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'chronic'
|
3
|
+
require 'chronic-l10n'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'chronic-l10n'
|
7
|
+
s.version = Chronic::L10n::VERSION
|
8
|
+
s.summary = 'Localization for Chronic'
|
9
|
+
s.description = 'Localization for Chronic'
|
10
|
+
s.authors = ['Luan Santos']
|
11
|
+
s.email = ['luan@luansantos.com']
|
12
|
+
s.homepage = 'http://github.com/luan/chronic-l10n'
|
13
|
+
s.rdoc_options = ['--charset=UTF-8']
|
14
|
+
s.extra_rdoc_files = %w[README.md HISTORY.md LICENSE]
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- test`.split("\n")
|
17
|
+
|
18
|
+
s.add_development_dependency 'rake'
|
19
|
+
s.add_development_dependency 'chronic'
|
20
|
+
s.add_development_dependency 'minitest'
|
21
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
def removeaccents(string)
|
2
|
+
accents = {
|
3
|
+
'E' => [200,201,202,203],
|
4
|
+
'e' => [232,233,234,235],
|
5
|
+
'A' => [192,193,194,195,196,197],
|
6
|
+
'a' => [224,225,226,227,228,229,230],
|
7
|
+
'C' => [199],
|
8
|
+
'c' => [231],
|
9
|
+
'O' => [210,211,212,213,214,216],
|
10
|
+
'o' => [242,243,244,245,246,248],
|
11
|
+
'I' => [204,205,206,207],
|
12
|
+
'i' => [236,237,238,239],
|
13
|
+
'U' => [217,218,219,220],
|
14
|
+
'u' => [249,250,251,252],
|
15
|
+
'N' => [209],
|
16
|
+
'n' => [241],
|
17
|
+
'Y' => [221],
|
18
|
+
'y' => [253,255],
|
19
|
+
'AE' => [306],
|
20
|
+
'ae' => [346],
|
21
|
+
'OE' => [188],
|
22
|
+
'oe' => [189]
|
23
|
+
}
|
24
|
+
|
25
|
+
str = String.new(string)
|
26
|
+
accents.each do |letter,accents|
|
27
|
+
packed = accents.pack('U*')
|
28
|
+
rxp = Regexp.new("[#{packed}]", nil)
|
29
|
+
str.gsub!(rxp, letter)
|
30
|
+
end
|
31
|
+
|
32
|
+
str
|
33
|
+
end
|
34
|
+
|
35
|
+
module Chronic
|
36
|
+
module L10n
|
37
|
+
PT_BR = {
|
38
|
+
:pointer => {
|
39
|
+
/\bpassado\b/ => :past,
|
40
|
+
/\b(?:futuro|em)\b/ => :future,
|
41
|
+
},
|
42
|
+
:ordinal_regex => /^(\d*)[oa]$/,
|
43
|
+
:numerizer => {
|
44
|
+
:and => 'e',
|
45
|
+
:preprocess => [
|
46
|
+
[/ +|([^\d])-([^\d])/, '\1 \2'], # will mutilate hyphenated-words but shouldn't matter for date extraction
|
47
|
+
[/e mei[ao]/, 'meia'] # take the 'a' out so it doesn't turn into a 1, save the half for the end
|
48
|
+
],
|
49
|
+
:fractional => [
|
50
|
+
[/(\d+)(?: |-)*mei[ao]/i, proc { ($1.to_f + 0.5).to_s }]
|
51
|
+
],
|
52
|
+
:direct_nums => [
|
53
|
+
['onze', '11'],
|
54
|
+
['doze', '12'],
|
55
|
+
['treze', '13'],
|
56
|
+
['quartorze', '14'],
|
57
|
+
['catorze', '14'],
|
58
|
+
['quinze', '15'],
|
59
|
+
['dezesseis', '16'],
|
60
|
+
['dezeseis', '16'],
|
61
|
+
['dezessete', '17'],
|
62
|
+
['dezesete', '17'],
|
63
|
+
['dezoito', '18'],
|
64
|
+
['dezenove', '19'],
|
65
|
+
['zero', '0'],
|
66
|
+
['um', '1'],
|
67
|
+
['uma', '1'],
|
68
|
+
['dois', '2'],
|
69
|
+
['duas', '2'],
|
70
|
+
['tres', '3'],
|
71
|
+
['quatro', '4'], # The weird regex is so that it matches four but not fourty
|
72
|
+
['cinco', '5'],
|
73
|
+
['seis', '6'],
|
74
|
+
['sete', '7'],
|
75
|
+
['oito', '8'],
|
76
|
+
['nove', '9'],
|
77
|
+
['dez(\W|$)', '10\1']
|
78
|
+
],
|
79
|
+
:ordinals => [
|
80
|
+
['primeiro', '1'],
|
81
|
+
['terceiro', '3'],
|
82
|
+
['quarto', '4'],
|
83
|
+
['quinto', '5'],
|
84
|
+
['sexto', '6'],
|
85
|
+
['setimo', '7'],
|
86
|
+
['oitavo', '8'],
|
87
|
+
['nono', '9'],
|
88
|
+
['decimo', '10']
|
89
|
+
],
|
90
|
+
:ten_prefixes => [
|
91
|
+
['vinte', 20],
|
92
|
+
['trinta', 30],
|
93
|
+
['quarenta', 40],
|
94
|
+
['cinquenta', 50],
|
95
|
+
['cincuenta', 50],
|
96
|
+
['sessenta', 60],
|
97
|
+
['setenta', 70],
|
98
|
+
['oitenta', 80],
|
99
|
+
['noventa', 90]
|
100
|
+
],
|
101
|
+
:big_prefixes => [
|
102
|
+
['cem', 100],
|
103
|
+
['mil', 1000],
|
104
|
+
['milhao', 1_000_000],
|
105
|
+
['bilhao', 1_000_000_000],
|
106
|
+
['trilhao', 1_000_000_000_000],
|
107
|
+
],
|
108
|
+
},
|
109
|
+
|
110
|
+
:repeater => {
|
111
|
+
:season_names => {
|
112
|
+
/^primaveras?$/ => :spring,
|
113
|
+
/^ver(ao|oes)$/ => :summer,
|
114
|
+
/^outonos?$/ => :autumn,
|
115
|
+
/^invernos?$/ => :winter
|
116
|
+
},
|
117
|
+
:month_names => {
|
118
|
+
/^jan\.?(eiro)?$/ => :january,
|
119
|
+
/^fev\.?(ereiro)?$/ => :february,
|
120
|
+
/^mar\.?(co)?$/ => :march,
|
121
|
+
/^abr\.?(il)?$/ => :april,
|
122
|
+
/^mai\.?o?$/ => :may,
|
123
|
+
/^jun\.?(ho)?$/ => :june,
|
124
|
+
/^jul\.?(ho)?$/ => :july,
|
125
|
+
/^ago\.?(sto)?$/ => :august,
|
126
|
+
/^set\.?(embro)?$/ => :september,
|
127
|
+
/^out\.?(ubro)?$/ => :october,
|
128
|
+
/^nov\.?(embro)?$/ => :november,
|
129
|
+
/^dez\.?(embro)?$/ => :december
|
130
|
+
},
|
131
|
+
:day_names => {
|
132
|
+
/^seg(unda)?(-feira)?$/ => :monday,
|
133
|
+
/^ter(ca)?(-feira)?$/ => :tuesday,
|
134
|
+
/^qua(rta)?(-feira)?$/ => :wednesday,
|
135
|
+
/^qui(nta)?(-feira)?$/ => :thursday,
|
136
|
+
/^sex(ta)?(-feira)?$/ => :friday,
|
137
|
+
/^sab(ado)?$/ => :saturday,
|
138
|
+
/^dom(ingo)?$/ => :sunday
|
139
|
+
},
|
140
|
+
:day_portions => {
|
141
|
+
/^ams?$/ => :am,
|
142
|
+
/^pms?$/ => :pm,
|
143
|
+
/^(madrugada|manha)s?$/ => :morning,
|
144
|
+
/^tardes?$/ => :afternoon,
|
145
|
+
/^noites?$/ => :evening,
|
146
|
+
/^noites?$/ => :night
|
147
|
+
},
|
148
|
+
:units => {
|
149
|
+
/^anos?$/ => :year,
|
150
|
+
/^estacoes?$/ => :season,
|
151
|
+
/^meses?$/ => :month,
|
152
|
+
/^quinzenas?$/ => :fortnight,
|
153
|
+
/^semanas?$/ => :week,
|
154
|
+
/^fi(m|ns) de semanas?$/ => :weekend,
|
155
|
+
/^dias? uteis?$/ => :weekday,
|
156
|
+
/^dias?$/ => :day,
|
157
|
+
/^hrs?$/ => :hour,
|
158
|
+
/^horas?$/ => :hour,
|
159
|
+
/^mins?$/ => :minute,
|
160
|
+
/^minutos?$/ => :minute,
|
161
|
+
/^secs?$/ => :second,
|
162
|
+
/^segundos?$/ => :second
|
163
|
+
}
|
164
|
+
},
|
165
|
+
|
166
|
+
:pre_normalize => {
|
167
|
+
:preprocess => proc {|str| removeaccents(str)},
|
168
|
+
:pre_numerize => [
|
169
|
+
[/\./, ':'],
|
170
|
+
[/['"]/, ''],
|
171
|
+
[/(.*),(.*)/, '\2 \1'],
|
172
|
+
[/^segundo /, '2nd '],
|
173
|
+
[/\bsegundo (de|dia|mes|hora|ninuto|segundo)\b/, '2nd \1']
|
174
|
+
],
|
175
|
+
:pos_numerize => [
|
176
|
+
[/ \-(\d{4})\b/, ' tzminus\1'],
|
177
|
+
[/([\/\-\,\@])/, ' \1 '],
|
178
|
+
[/(?:^|\s)0(\d+:\d+\s*pm?\b)/, ' \1'],
|
179
|
+
[/\bhoje\b/, 'este dia'],
|
180
|
+
[/\bamanha\b/, 'proximo dia'],
|
181
|
+
[/\bontem\b/, 'ultimo dia'],
|
182
|
+
[/\bmeio[- ]dia\b/, '12:00pm'],
|
183
|
+
[/\bmeia[- ]noite\b/, '24:00'],
|
184
|
+
[/\bagora\b/, 'este segundo'],
|
185
|
+
[/\b(?:atras)\b/, 'passado'],
|
186
|
+
[/\beste (?:ultimo|passado)\b/, 'ultimo'],
|
187
|
+
[/\b(?:da|de) (madrugada|manha)\b/, '\1'],
|
188
|
+
[/\b(?:da|de|a) (tarde|noite)\b/, '\1'],
|
189
|
+
[/\bhoje a noite\b/, 'esta noite'],
|
190
|
+
[/\b\d+:?\d*[ap]\b/,'\0m'],
|
191
|
+
[/(\d)([ap]m)\b/, '\1 \2'],
|
192
|
+
[/(\d)(?:h|em ponto)\b/, '\1:00'],
|
193
|
+
[/\b(depois|de agora)\b/, 'futuro'],
|
194
|
+
[/^\s?an? /i, '1 '],
|
195
|
+
[/\b(\d+) de (\w)\b/, '\2 \1']
|
196
|
+
]
|
197
|
+
},
|
198
|
+
|
199
|
+
:grabber => {
|
200
|
+
/ultim[ao]/ => :last,
|
201
|
+
/est[ae]/ => :this,
|
202
|
+
/proxim[ao]/ => :next
|
203
|
+
},
|
204
|
+
|
205
|
+
:token => {
|
206
|
+
:comma => /^,$/,
|
207
|
+
:at => /^(as|@)$/,
|
208
|
+
:in => /^em$/,
|
209
|
+
:on => /^em$/
|
210
|
+
}
|
211
|
+
}
|
212
|
+
end
|
213
|
+
end
|
data/lib/chronic-l10n.rb
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'chronic'
|
2
|
+
unless defined? Chronic::L10n
|
3
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
4
|
+
require 'chronic-l10n'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
class TestCase < MiniTest::Unit::TestCase
|
10
|
+
def self.test(name, &block)
|
11
|
+
define_method("test_#{name.gsub(/\W/, '_')}", &block) if block
|
12
|
+
end
|
13
|
+
end
|