temporal 0.4.0
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 +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +27 -0
- data/README.txt +6 -0
- data/Rakefile +9 -0
- data/lib/temporal/anomaly.rb +4 -0
- data/lib/temporal/helpers.rb +12 -0
- data/lib/temporal/mathematics.rb +92 -0
- data/lib/temporal/parser/afrikaans.rb +24 -0
- data/lib/temporal/parser/english.rb +24 -0
- data/lib/temporal/parser.rb +37 -0
- data/lib/temporal/shift.rb +163 -0
- data/lib/temporal/version.rb +3 -0
- data/lib/temporal.rb +7 -0
- data/temporal.gemspec +24 -0
- data/test/days.rb +56 -0
- data/test/hours.rb +17 -0
- data/test/minutes.rb +17 -0
- data/test/months.rb +19 -0
- data/test/seconds.rb +17 -0
- data/test/weeks.rb +16 -0
- data/test/years.rb +7 -0
- metadata +132 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
temporal (0.4.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
rake (0.8.7)
|
11
|
+
rspec (2.4.0)
|
12
|
+
rspec-core (~> 2.4.0)
|
13
|
+
rspec-expectations (~> 2.4.0)
|
14
|
+
rspec-mocks (~> 2.4.0)
|
15
|
+
rspec-core (2.4.0)
|
16
|
+
rspec-expectations (2.4.0)
|
17
|
+
diff-lcs (~> 1.1.2)
|
18
|
+
rspec-mocks (2.4.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (>= 1.0.0)
|
25
|
+
rake (>= 0.8.7)
|
26
|
+
rspec (>= 1.3.0)
|
27
|
+
temporal!
|
data/README.txt
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
[Numeric,Range].each do |klass|
|
2
|
+
Temporal::Mathematics.units( klass )
|
3
|
+
Temporal::Mathematics.operators( klass )
|
4
|
+
end
|
5
|
+
|
6
|
+
[Time].each do |klass|
|
7
|
+
Temporal::Mathematics.operators( klass )
|
8
|
+
end
|
9
|
+
|
10
|
+
[Range].each do |klass|
|
11
|
+
Temporal::Mathematics.negation( klass )
|
12
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Temporal
|
2
|
+
module Mathematics
|
3
|
+
|
4
|
+
def self.units klass
|
5
|
+
klass.class_eval do
|
6
|
+
Temporal::Shift.units.each do |unit|
|
7
|
+
if klass == Range
|
8
|
+
define_method unit do
|
9
|
+
if exclude_end?
|
10
|
+
return Temporal::Shift.new( first, unit )...Temporal::Shift.new( last, unit )
|
11
|
+
else
|
12
|
+
return Temporal::Shift.new( first, unit )..Temporal::Shift.new( last, unit )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
else
|
16
|
+
define_method unit do
|
17
|
+
Temporal::Shift.new( self, unit )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
define_method "#{unit}s" do
|
21
|
+
send(unit)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.negation klass
|
28
|
+
klass.class_eval do
|
29
|
+
begin
|
30
|
+
alias :temporal_negation :-@
|
31
|
+
rescue
|
32
|
+
def temporal_negation
|
33
|
+
raise NoMethodError.new( "undefined method `-@' for #{self.to_s}:#{self.class.to_s}" )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
def -@
|
37
|
+
return temporal_negation unless self.class == Temporal::Shift or self.class == Range
|
38
|
+
if exclude_end?
|
39
|
+
-first...-last
|
40
|
+
else
|
41
|
+
-first..-last
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.operators klass
|
48
|
+
klass.class_eval do
|
49
|
+
begin
|
50
|
+
alias :temporal_addition :+
|
51
|
+
rescue
|
52
|
+
def temporal_addition target
|
53
|
+
raise NoMethodError.new( "undefined method `+' for #{self.to_s}:#{self.class.to_s}" )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
def + target
|
57
|
+
if target.class == Range
|
58
|
+
if self.class == Range
|
59
|
+
raise Temporal::Anomaly.new( "Missmatched Range end exclusions" ) if exclude_end? != target.exclude_end?
|
60
|
+
if target.exclude_end?
|
61
|
+
return (target.first + first)...(target.last + last)
|
62
|
+
else
|
63
|
+
return (target.first + first)..(target.last + last)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
if target.exclude_end?
|
67
|
+
return (target.first + self)...(target.last + self)
|
68
|
+
else
|
69
|
+
return (target.first + self)..(target.last + self)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
return temporal_addition( target ) unless target.class == Temporal::Shift
|
74
|
+
target + self
|
75
|
+
end
|
76
|
+
|
77
|
+
begin
|
78
|
+
alias :temporal_subtraction :-
|
79
|
+
rescue
|
80
|
+
def temporal_subtraction target
|
81
|
+
raise NoMethodError.new( "undefined method `-' for #{self.to_s}:#{self.class.to_s}" )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def - target
|
85
|
+
return temporal_subtraction( target ) unless target.class == Temporal::Shift or target.class == Range
|
86
|
+
(-target) + self
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Temporal
|
2
|
+
class Parser
|
3
|
+
|
4
|
+
add_literal( /(^|\W)noe(\W|$)/i ) do
|
5
|
+
Time.now
|
6
|
+
end
|
7
|
+
|
8
|
+
add_literal( /(^|\W)vandag(\W|$)/i ) do
|
9
|
+
today_start = Time.parse(Time.now.strftime("%Y-%m-%d"))
|
10
|
+
today_start...today_start+1.day
|
11
|
+
end
|
12
|
+
|
13
|
+
add_literal( /(^|\W)gister(\W|$)/i ) do
|
14
|
+
yesterday_start = Time.parse((Time.now-1.day).strftime("%Y-%m-%d"))
|
15
|
+
yesterday_start...yesterday_start+1.day
|
16
|
+
end
|
17
|
+
|
18
|
+
add_literal( /(^|\W)more(\W|$)/i ) do
|
19
|
+
tomorrow_start = Time.parse((Time.now+1.day).strftime("%Y-%m-%d"))
|
20
|
+
tomorrow_start...tomorrow_start+1.day
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Temporal
|
2
|
+
class Parser
|
3
|
+
|
4
|
+
add_literal( /(^|\W)now(\W|$)/i ) do
|
5
|
+
Time.now
|
6
|
+
end
|
7
|
+
|
8
|
+
add_literal( /(^|\W)today(\W|$)/i ) do
|
9
|
+
today_start = Time.parse(Time.now.strftime("%Y-%m-%d"))
|
10
|
+
today_start...today_start+1.day
|
11
|
+
end
|
12
|
+
|
13
|
+
add_literal( /(^|\W)yesterday(\W|$)/i ) do
|
14
|
+
yesterday_start = Time.parse((Time.now-1.day).strftime("%Y-%m-%d"))
|
15
|
+
yesterday_start...yesterday_start+1.day
|
16
|
+
end
|
17
|
+
|
18
|
+
add_literal( /(^|\W)tomorrow(\W|$)/i ) do
|
19
|
+
tomorrow_start = Time.parse((Time.now+1.day).strftime("%Y-%m-%d"))
|
20
|
+
tomorrow_start...tomorrow_start+1.day
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Temporal
|
2
|
+
class Parser
|
3
|
+
@@literals = {}
|
4
|
+
|
5
|
+
def self.add_literal literal, &block
|
6
|
+
@@literals[ literal ] = block
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.match? string
|
10
|
+
to_match = string.downcase.strip
|
11
|
+
@@literals.keys.each do |key|
|
12
|
+
return true if to_match =~ key
|
13
|
+
end
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse string
|
18
|
+
@@literals.keys.each do |key|
|
19
|
+
match = string.match(key)
|
20
|
+
next unless match
|
21
|
+
result = []
|
22
|
+
result << parse(match.pre_match) if match.pre_match.strip.size > 0
|
23
|
+
result << @@literals[key].call
|
24
|
+
result << parse(match.post_match) if match.post_match.strip.size > 0
|
25
|
+
result.flatten!
|
26
|
+
if result.empty?
|
27
|
+
result = nil
|
28
|
+
else
|
29
|
+
result = result.pop if result.size == 1
|
30
|
+
end
|
31
|
+
return result
|
32
|
+
end
|
33
|
+
string
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Temporal
|
2
|
+
class Shift
|
3
|
+
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
MINUTE = 60
|
7
|
+
HOUR = MINUTE * 60
|
8
|
+
DAY = HOUR * 24
|
9
|
+
WEEK = DAY * 7
|
10
|
+
|
11
|
+
YEAR = 12
|
12
|
+
|
13
|
+
MAX_MONTH_DAY = %w|31 0 31 30 31 30 31 31 30 31 30 31|.map{|n|n.to_i} # Don't worry about February
|
14
|
+
|
15
|
+
attr_accessor :seconds
|
16
|
+
attr_accessor :months
|
17
|
+
|
18
|
+
def initialize amount, unit
|
19
|
+
unless self.class.unit?( unit )
|
20
|
+
raise Temporal::Anomaly.new( "Bad #{self.class}.unit type of `#{unit}' given" )
|
21
|
+
end
|
22
|
+
|
23
|
+
@seconds = 0
|
24
|
+
@months = 0
|
25
|
+
|
26
|
+
unit = unit.to_s.downcase
|
27
|
+
unit.chop! if unit[-1..-1] == 's'
|
28
|
+
unit = unit.to_sym
|
29
|
+
|
30
|
+
case unit
|
31
|
+
when :second
|
32
|
+
@seconds = amount
|
33
|
+
when :minute
|
34
|
+
@seconds = amount * MINUTE
|
35
|
+
when :hour
|
36
|
+
@seconds = amount * HOUR
|
37
|
+
when :day
|
38
|
+
@seconds = amount * DAY
|
39
|
+
when :week
|
40
|
+
@seconds = amount * WEEK
|
41
|
+
when :month
|
42
|
+
@months = amount
|
43
|
+
when :year
|
44
|
+
@months = amount * YEAR
|
45
|
+
else
|
46
|
+
raise Temporal::Anomaly.new( "Internal Error, failed to catch bad #{self.class}.unit type of `#{unit}' given" )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def <=> target
|
51
|
+
return 1 if @months > target.months
|
52
|
+
return -1 if @months < target.months
|
53
|
+
return 1 if @seconds > target.seconds
|
54
|
+
return -1 if @seconds < target.seconds
|
55
|
+
0
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.units
|
59
|
+
%w|second minute hour day week month year|
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.unit? unit
|
63
|
+
(unit.to_s.strip.downcase =~ /^(#{units.join('|')})s?$/) != nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def + to_be_added
|
67
|
+
|
68
|
+
if to_be_added.class == self.class
|
69
|
+
result_instance = self.class.new( @seconds + to_be_added.seconds, :seconds )
|
70
|
+
result_instance.months = @months + to_be_added.months
|
71
|
+
return result_instance
|
72
|
+
end
|
73
|
+
|
74
|
+
if to_be_added.class == Time
|
75
|
+
new_time = (to_be_added + @seconds).localtime
|
76
|
+
new_year = new_time.year+(((new_time.month-1)+months)/12)
|
77
|
+
new_month = (((new_time.month-1)+months)%12)
|
78
|
+
new_day = new_time.day
|
79
|
+
if new_month == 1
|
80
|
+
if (new_year%4 == 0 and new_year%100 != 0) or new_year%400 == 0
|
81
|
+
max_mday = 29
|
82
|
+
else
|
83
|
+
max_mday = 28
|
84
|
+
end
|
85
|
+
else
|
86
|
+
max_mday = MAX_MONTH_DAY[ new_month ];
|
87
|
+
end
|
88
|
+
new_day = max_mday if new_day > max_mday
|
89
|
+
return Time.local( new_year, new_month+1 , new_day, new_time.hour, new_time.min, new_time.sec, new_time.usec )
|
90
|
+
end
|
91
|
+
|
92
|
+
if to_be_added.class == Range
|
93
|
+
new_first = self + to_be_added.first
|
94
|
+
new_last = self + to_be_added.last
|
95
|
+
if to_be_added.exclude_end?
|
96
|
+
return new_first...new_last
|
97
|
+
else
|
98
|
+
return new_first..new_last
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
raise Temporal::Anomaly.new( "Unable to add #{self.class} to instances of `#{to_be_added.class}'" )
|
103
|
+
end
|
104
|
+
|
105
|
+
def -@
|
106
|
+
negated = self.class.new( -@seconds, :seconds )
|
107
|
+
negated.months = -@months
|
108
|
+
return negated
|
109
|
+
end
|
110
|
+
|
111
|
+
def - to_be_subtracted
|
112
|
+
begin
|
113
|
+
self + ( -to_be_subtracted )
|
114
|
+
rescue Exception => e
|
115
|
+
raise Temporal::Anomaly.new( "Unable to subtract an instance of #{to_be_subtracted.class} from #{self.class}" )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def to_s
|
120
|
+
result = {}
|
121
|
+
|
122
|
+
result[:months] = @months
|
123
|
+
|
124
|
+
result[:years] = (result[:months]/12).truncate
|
125
|
+
result[:months] = result[:months] - ( result[:years] * 12 )
|
126
|
+
result[:months] = result[:months].truncate if result[:months].modulo(1) == 0
|
127
|
+
|
128
|
+
result[:seconds] = @seconds
|
129
|
+
|
130
|
+
result[:weeks] = (result[:seconds] / WEEK).truncate
|
131
|
+
result[:seconds] = result[:seconds] - (result[:weeks] * WEEK)
|
132
|
+
result[:days] = (result[:seconds] / DAY).truncate
|
133
|
+
result[:seconds] = result[:seconds] - (result[:days] * DAY)
|
134
|
+
result[:hours] = (result[:seconds] / HOUR).truncate
|
135
|
+
result[:seconds] = result[:seconds] - (result[:hours] * HOUR)
|
136
|
+
result[:minutes] = (result[:seconds] / MINUTE).truncate
|
137
|
+
result[:seconds] = result[:seconds] - (result[:minutes] * MINUTE)
|
138
|
+
result[:seconds] = result[:seconds].truncate if result[:seconds].modulo(1) == 0
|
139
|
+
|
140
|
+
result = Hash[ *result.select{|unit, amount| amount != 0 }.flatten ]
|
141
|
+
|
142
|
+
string = ""
|
143
|
+
|
144
|
+
%w|years months weeks days hours minutes seconds|.each do |unit|
|
145
|
+
unit = unit.to_sym
|
146
|
+
next unless result.has_key?( unit )
|
147
|
+
string += "#{result[ unit ]} #{unit}"
|
148
|
+
string.chop! if result[ unit ].abs == 1
|
149
|
+
result.delete( unit )
|
150
|
+
break if result.size == 0
|
151
|
+
if result.size == 1
|
152
|
+
string += " and "
|
153
|
+
else
|
154
|
+
string += ", "
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
string
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
data/lib/temporal.rb
ADDED
data/temporal.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/temporal/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "temporal"
|
6
|
+
s.version = Temporal::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Clive Crous"]
|
9
|
+
s.email = ["clive@crous.co.za"]
|
10
|
+
s.homepage = "http://www.darkarts.co.za/temporal"
|
11
|
+
s.summary = "A natural language date and time parser"
|
12
|
+
s.description = "This project is still in early development. Only the mathematical side is complete. eg: Time.now + 3.years + 2.months"
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
s.rubyforge_project = "temporal"
|
16
|
+
|
17
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
18
|
+
s.add_development_dependency "rspec", ">= 1.3.0"
|
19
|
+
s.add_development_dependency "rake", ">= 0.8.7"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
23
|
+
s.require_path = 'lib'
|
24
|
+
end
|
data/test/days.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'temporal'
|
2
|
+
|
3
|
+
describe 'Temporal math with days' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@context = Time.local( 1975, 05, 13, 01, 23, 45)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should add a day' do
|
10
|
+
( @context + 1.day ).should == Time.local( 1975, 05, 14, 01, 23, 45)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should subtract a day' do
|
14
|
+
( @context - 1.day ).should == Time.local( 1975, 05, 12, 01, 23, 45)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should add days' do
|
18
|
+
( @context + 2.days ).should == Time.local( 1975, 05, 15, 01, 23, 45)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should subtract days' do
|
22
|
+
( @context - 2.days ).should == Time.local( 1975, 05, 11, 01, 23, 45)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should wrap months while adding' do
|
26
|
+
( Time.local( 1975, 05, 31, 01, 23, 45 ) + 1.day ).should == Time.local( 1975, 06, 1, 01, 23, 45 )
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should wrap months while subtracting' do
|
30
|
+
( Time.local( 1975, 05, 1, 01, 23, 45 ) - 1.day ).should == Time.local( 1975, 04, 30, 01, 23, 45 )
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should wrap years while adding' do
|
34
|
+
( Time.local( 1975, 12, 31, 01, 23, 45 ) + 1.day ).should == Time.local( 1976, 01, 01, 01, 23, 45 )
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should wrap years while subtracting' do
|
38
|
+
( Time.local( 1975, 01, 01, 01, 23, 45 ) - 1.day ).should == Time.local( 1974, 12, 31, 01, 23, 45 )
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'One day in other units' do
|
44
|
+
it 'is 86400 seconds' do
|
45
|
+
1.day.should == 86400.seconds
|
46
|
+
end
|
47
|
+
it 'is 1440 minutes' do
|
48
|
+
1.day.should == 1440.minutes
|
49
|
+
end
|
50
|
+
it 'is 24 hours' do
|
51
|
+
1.day.should == 24.hours
|
52
|
+
end
|
53
|
+
it 'is 1/7th of a week' do
|
54
|
+
1.day.should == (1.0/7).weeks
|
55
|
+
end
|
56
|
+
end
|
data/test/hours.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'temporal'
|
2
|
+
|
3
|
+
describe 'One hour in other units' do
|
4
|
+
it 'is 3600 seconds' do
|
5
|
+
1.hour.should == 3600.seconds
|
6
|
+
end
|
7
|
+
it 'is 60 minutes' do
|
8
|
+
1.hour.should == 60.minutes
|
9
|
+
end
|
10
|
+
it 'is 1/24th of a day' do
|
11
|
+
1.hour.should == (1.0/24).days
|
12
|
+
end
|
13
|
+
it 'is 1/168th of a week' do
|
14
|
+
1.hour.should == (1.0/168).weeks
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/test/minutes.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'temporal'
|
2
|
+
|
3
|
+
describe 'One minute in other units' do
|
4
|
+
it 'is 60 seconds' do
|
5
|
+
1.minute.should == 60.seconds
|
6
|
+
end
|
7
|
+
it 'is 1/60th of an hour' do
|
8
|
+
1.minute.should == (1.0/60).hours
|
9
|
+
end
|
10
|
+
it 'is 1/1440th of a day' do
|
11
|
+
1.minute.should == (1.0/1440).days
|
12
|
+
end
|
13
|
+
it 'is 1/10080th of a week' do
|
14
|
+
1.minute.should == (1.0/10080).weeks
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/test/months.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'temporal'
|
2
|
+
|
3
|
+
describe 'Temporal math with months' do
|
4
|
+
|
5
|
+
it 'should wrap years while adding' do
|
6
|
+
( Time.local( 1975, 8, 1 ) + 5.months ).should == Time.local( 1976, 1, 1 )
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should not wrap years while adding 1 month to november' do
|
10
|
+
( Time.local( 1975, 11, 1 ) + 1.month ).should == Time.local( 1975, 12, 1 )
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'One month in other units' do
|
16
|
+
it 'is 1/12th of a year' do
|
17
|
+
1.month.should == (1.0/12).years
|
18
|
+
end
|
19
|
+
end
|
data/test/seconds.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'temporal'
|
2
|
+
|
3
|
+
describe 'One second in other units' do
|
4
|
+
it 'is 1/60th of a minute' do
|
5
|
+
1.second.should == (1.0/60).minutes
|
6
|
+
end
|
7
|
+
it 'is 1/3600th of a hour' do
|
8
|
+
1.second.should == (1.0/3600).hours
|
9
|
+
end
|
10
|
+
it 'is 1/86400th of a day' do
|
11
|
+
1.second.should == (1.0/86400).days
|
12
|
+
end
|
13
|
+
it 'is 1/604800th of a week' do
|
14
|
+
1.second.should == (1.0/604800).weeks
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/test/weeks.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'temporal'
|
2
|
+
|
3
|
+
describe 'One week in other units' do
|
4
|
+
it 'is 604800 seconds' do
|
5
|
+
1.week.should == 604800.seconds
|
6
|
+
end
|
7
|
+
it 'is 10080 minutes' do
|
8
|
+
1.week.should == 10080.minutes
|
9
|
+
end
|
10
|
+
it 'is 168 hours' do
|
11
|
+
1.week.should == 168.hours
|
12
|
+
end
|
13
|
+
it 'is 7 days' do
|
14
|
+
1.week.should == 7.days
|
15
|
+
end
|
16
|
+
end
|
data/test/years.rb
ADDED
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: temporal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Clive Crous
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-18 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: bundler
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
version: 1.0.0
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rspec
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 1
|
45
|
+
- 3
|
46
|
+
- 0
|
47
|
+
version: 1.3.0
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rake
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
- 8
|
61
|
+
- 7
|
62
|
+
version: 0.8.7
|
63
|
+
type: :development
|
64
|
+
version_requirements: *id003
|
65
|
+
description: "This project is still in early development. Only the mathematical side is complete. eg: Time.now + 3.years + 2.months"
|
66
|
+
email:
|
67
|
+
- clive@crous.co.za
|
68
|
+
executables: []
|
69
|
+
|
70
|
+
extensions: []
|
71
|
+
|
72
|
+
extra_rdoc_files: []
|
73
|
+
|
74
|
+
files:
|
75
|
+
- .gitignore
|
76
|
+
- Gemfile
|
77
|
+
- Gemfile.lock
|
78
|
+
- README.txt
|
79
|
+
- Rakefile
|
80
|
+
- lib/temporal.rb
|
81
|
+
- lib/temporal/anomaly.rb
|
82
|
+
- lib/temporal/helpers.rb
|
83
|
+
- lib/temporal/mathematics.rb
|
84
|
+
- lib/temporal/parser.rb
|
85
|
+
- lib/temporal/parser/afrikaans.rb
|
86
|
+
- lib/temporal/parser/english.rb
|
87
|
+
- lib/temporal/shift.rb
|
88
|
+
- lib/temporal/version.rb
|
89
|
+
- temporal.gemspec
|
90
|
+
- test/days.rb
|
91
|
+
- test/hours.rb
|
92
|
+
- test/minutes.rb
|
93
|
+
- test/months.rb
|
94
|
+
- test/seconds.rb
|
95
|
+
- test/weeks.rb
|
96
|
+
- test/years.rb
|
97
|
+
has_rdoc: true
|
98
|
+
homepage: http://www.darkarts.co.za/temporal
|
99
|
+
licenses: []
|
100
|
+
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
segments:
|
120
|
+
- 1
|
121
|
+
- 3
|
122
|
+
- 6
|
123
|
+
version: 1.3.6
|
124
|
+
requirements: []
|
125
|
+
|
126
|
+
rubyforge_project: temporal
|
127
|
+
rubygems_version: 1.3.7
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: A natural language date and time parser
|
131
|
+
test_files: []
|
132
|
+
|