pravigo-duration 0.0.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/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +53 -0
- data/Rakefile +7 -0
- data/lib/pravigo/duration.rb +235 -0
- data/lib/pravigo/duration/version.rb +5 -0
- data/pravigo-duration.gemspec +27 -0
- data/spec/duration_spec.rb +455 -0
- data/spec/spec_helper.rb +1 -0
- metadata +124 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Rich Hall
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Pravigo::Duration
|
2
|
+
|
3
|
+
extends ActiveSupport::Duration class to add iso8601 support
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'pravigo-duration'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install pravigo-duration
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
###Example 1: subtract 2 time objects to get a duration
|
22
|
+
|
23
|
+
irb
|
24
|
+
irb(main):001:0> require 'pravigo/duration'
|
25
|
+
=> true
|
26
|
+
irb(main):002:0> t2 = Time.parse("2015-07-09T09:56:33Z")
|
27
|
+
=> 2015-07-09 09:56:33 UTC
|
28
|
+
irb(main):003:0> t = Time.parse("2015-07-09T09:37:33Z")
|
29
|
+
=> 2015-07-09 09:37:33 UTC
|
30
|
+
irb(main):004:0> d = Duration.new(t2-t)
|
31
|
+
=> 19 minutes
|
32
|
+
|
33
|
+
### Running RSPEC tests
|
34
|
+
|
35
|
+
From the root directory:
|
36
|
+
|
37
|
+
rspec ./spec/duration_spec.rb -f documentation
|
38
|
+
|
39
|
+
or
|
40
|
+
|
41
|
+
rake test
|
42
|
+
|
43
|
+
or
|
44
|
+
|
45
|
+
rake spec
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
1. Fork it ( http://github.com/richhall/pravigo-duration/fork )
|
50
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
51
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
52
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
53
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
require "pravigo/duration/version"
|
2
|
+
require 'active_support/time'
|
3
|
+
|
4
|
+
class BasicObject
|
5
|
+
def __realclass__; (class << self; self end).superclass end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Object; alias __realclass__ class end
|
9
|
+
|
10
|
+
class Pravigo
|
11
|
+
#module Duration
|
12
|
+
|
13
|
+
|
14
|
+
#class Duration < ActiveSupport::Duration
|
15
|
+
class ActiveSupport::Duration
|
16
|
+
|
17
|
+
@@MONTHS_IN_A_YEAR = 12
|
18
|
+
@@SECONDS_IN_A_WEEK = 604800
|
19
|
+
@@SECONDS_IN_A_DAY = 86400
|
20
|
+
@@SECONDS_IN_AN_HOUR = 3600
|
21
|
+
@@SECONDS_IN_A_MINUTE = 60
|
22
|
+
#Approximate number of seconds in a month and year
|
23
|
+
@@SECONDS_IN_A_YEAR = @@SECONDS_IN_A_DAY * 365
|
24
|
+
@@SECONDS_IN_A_MONTH = @@SECONDS_IN_A_DAY * 30
|
25
|
+
|
26
|
+
def initialize(*args)
|
27
|
+
case args.size
|
28
|
+
when 1
|
29
|
+
if args[0].is_a? ::ActiveSupport::Duration
|
30
|
+
@value = args[0].value
|
31
|
+
@parts = args[0].parts
|
32
|
+
else
|
33
|
+
if args[0].is_a? ::String
|
34
|
+
iso8601Duration = args[0]
|
35
|
+
iso8601Duration = iso8601Duration.gsub(',','.')
|
36
|
+
|
37
|
+
if /\AP(?:(-?\d+)Y|Y)?
|
38
|
+
(?:(-?\d+)M|M)?
|
39
|
+
(?:(-?\d+)D|D)?
|
40
|
+
(?:T(?:(-?\d+)H|H)?
|
41
|
+
(?:(-?\d+)M|M)?
|
42
|
+
(?:(-?\d+(?:(\.|\,)\d{1,4})?)S|S)?
|
43
|
+
)?
|
44
|
+
\Z/ix =~iso8601Duration
|
45
|
+
|
46
|
+
@years = $1.to_i
|
47
|
+
@months = $2.to_i
|
48
|
+
@days = $3.to_i
|
49
|
+
@hours = $4.to_i
|
50
|
+
@minutes = $5.to_i
|
51
|
+
@seconds = $6.to_f
|
52
|
+
|
53
|
+
else
|
54
|
+
if /\A(?:(\d+):?)?
|
55
|
+
(?:(\d+):?)?
|
56
|
+
(\d+)?
|
57
|
+
\Z/ix =~iso8601Duration
|
58
|
+
|
59
|
+
@years = 0
|
60
|
+
@months = 0
|
61
|
+
@days = 0
|
62
|
+
@hours = $1.to_i
|
63
|
+
@minutes = $2.to_i
|
64
|
+
@seconds = $3.to_f
|
65
|
+
else
|
66
|
+
return ::NilClass
|
67
|
+
@years = 0
|
68
|
+
@months = 0
|
69
|
+
@days = 0
|
70
|
+
@hours = 0
|
71
|
+
@minutes = 0
|
72
|
+
@seconds = 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@value = (@years*@@SECONDS_IN_A_YEAR)+
|
77
|
+
(@months*@@SECONDS_IN_A_MONTH)+
|
78
|
+
(@days*@@SECONDS_IN_A_DAY)+
|
79
|
+
(@hours*@@SECONDS_IN_AN_HOUR)+
|
80
|
+
(@minutes*@@SECONDS_IN_A_MINUTE)+
|
81
|
+
(@seconds)
|
82
|
+
@parts = []
|
83
|
+
|
84
|
+
@parts << [:years, @years] if @years!=0
|
85
|
+
@parts << [:months, @months] if @months!=0
|
86
|
+
@parts << [:days, @days] if @days!=0
|
87
|
+
@parts << [:hours, @hours] if @hours !=0
|
88
|
+
@parts << [:minutes, @minutes] if @minutes !=0
|
89
|
+
@parts << [:seconds,@seconds] if @seconds!=0
|
90
|
+
|
91
|
+
#else raise an error
|
92
|
+
else if args[0].is_a? ::Numeric
|
93
|
+
@value = args[0]
|
94
|
+
days_c = @value.divmod(@@SECONDS_IN_A_DAY)
|
95
|
+
hours_c = days_c[1].divmod(@@SECONDS_IN_AN_HOUR)
|
96
|
+
minutes_c = hours_c[1].divmod(@@SECONDS_IN_A_MINUTE)
|
97
|
+
seconds_c = minutes_c[1]
|
98
|
+
@parts = []
|
99
|
+
@parts << [:days, days_c[0]] if days_c[0]>0
|
100
|
+
@parts << [:hours, hours_c[0]] if hours_c[0] >0
|
101
|
+
@parts << [:minutes, minutes_c[0]] if minutes_c[0] >0
|
102
|
+
@parts << [:seconds,seconds_c] if seconds_c >0
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
when 2
|
108
|
+
@value = args[0]
|
109
|
+
@parts = args[1]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def iso8601
|
114
|
+
grouped_parts = parts.group_by(&:first).map { |k, v| [k, v.map(&:last).inject(:+)] }
|
115
|
+
hash_of_parts = ::Hash[grouped_parts]
|
116
|
+
hash_of_parts.default = 0
|
117
|
+
|
118
|
+
total_months = (hash_of_parts[:years]*@@MONTHS_IN_A_YEAR)+(hash_of_parts[:months])
|
119
|
+
totalSeconds = (hash_of_parts[:days]*@@SECONDS_IN_A_DAY)+(hash_of_parts[:hours]*@@SECONDS_IN_AN_HOUR)+(hash_of_parts[:minutes]*@@SECONDS_IN_A_MINUTE)+(hash_of_parts[:seconds])
|
120
|
+
if (total_months < 0)
|
121
|
+
negative_months = "-"
|
122
|
+
total_months = 0-total_months
|
123
|
+
else
|
124
|
+
negative_months = ""
|
125
|
+
end
|
126
|
+
if (totalSeconds < 0)
|
127
|
+
negative_seconds = "-"
|
128
|
+
totalSeconds = 0-totalSeconds
|
129
|
+
else
|
130
|
+
negative_seconds=""
|
131
|
+
end
|
132
|
+
|
133
|
+
years_c = total_months.divmod(@@MONTHS_IN_A_YEAR)
|
134
|
+
days_c = totalSeconds.divmod(@@SECONDS_IN_A_DAY)
|
135
|
+
hours_c = days_c[1].divmod(@@SECONDS_IN_AN_HOUR)
|
136
|
+
minutes_c = hours_c[1].divmod(@@SECONDS_IN_A_MINUTE)
|
137
|
+
seconds_c = minutes_c[1]
|
138
|
+
|
139
|
+
result = "P"
|
140
|
+
result << (years_c[0] != 0 ? "#{negative_months}#{years_c[0]}Y" : "")
|
141
|
+
result << (years_c[1] != 0 ? "#{negative_months}#{years_c[1]}M" : "")
|
142
|
+
result << (days_c[0] != 0 ? "#{negative_months}#{days_c[0]}D" : "")
|
143
|
+
|
144
|
+
result << (days_c[1] != 0 ? "T" : "")
|
145
|
+
result << (hours_c[0] != 0 ? "#{negative_seconds}#{hours_c[0]}H" : "")
|
146
|
+
result << (minutes_c[0] != 0 ? "#{negative_seconds}#{minutes_c[0]}M" : "")
|
147
|
+
# result << (seconds_c > 0 ? "#{seconds_c}S" : "")
|
148
|
+
result << (seconds_c != 0 ? ((seconds_c % 1 ==0) ? "#{negative_seconds}#{seconds_c.to_i}S" : "#{negative_seconds}#{seconds_c.round(4)}S") : "")
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
##need to DRY this out
|
153
|
+
def as_24h_clock
|
154
|
+
grouped_parts = parts.group_by(&:first).map { |k, v| [k, v.map(&:last).inject(:+)] }
|
155
|
+
hash_of_parts = ::Hash[grouped_parts]
|
156
|
+
hash_of_parts.default = 0
|
157
|
+
|
158
|
+
total_months = (hash_of_parts[:years]*@@MONTHS_IN_A_YEAR)+(hash_of_parts[:months])
|
159
|
+
totalSeconds = (hash_of_parts[:days]*@@SECONDS_IN_A_DAY)+(hash_of_parts[:hours]*@@SECONDS_IN_AN_HOUR)+(hash_of_parts[:minutes]*@@SECONDS_IN_A_MINUTE)+(hash_of_parts[:seconds])
|
160
|
+
if (total_months < 0)
|
161
|
+
negative_months = "-"
|
162
|
+
total_months = 0-total_months
|
163
|
+
else
|
164
|
+
negative_months = ""
|
165
|
+
end
|
166
|
+
if (totalSeconds < 0)
|
167
|
+
negative_seconds = "-"
|
168
|
+
totalSeconds = 0-totalSeconds
|
169
|
+
else
|
170
|
+
negative_seconds=""
|
171
|
+
end
|
172
|
+
|
173
|
+
years_c = total_months.divmod(@@MONTHS_IN_A_YEAR)
|
174
|
+
days_c = totalSeconds.divmod(@@SECONDS_IN_A_DAY)
|
175
|
+
hours_c = days_c[1].divmod(@@SECONDS_IN_AN_HOUR)
|
176
|
+
minutes_c = hours_c[1].divmod(@@SECONDS_IN_A_MINUTE)
|
177
|
+
seconds_c = minutes_c[1]
|
178
|
+
|
179
|
+
result = ""
|
180
|
+
|
181
|
+
result << (hours_c[0] != 0 ? "#{negative_seconds}#{ "%02d" % hours_c[0]}:" : "00:")
|
182
|
+
result << (minutes_c[0] != 0 ? "#{negative_seconds}#{ "%02d" % minutes_c[0]}:" : "00:")
|
183
|
+
result << (seconds_c != 0 ? ((seconds_c % 1 ==0) ? "#{negative_seconds}#{ "%02d" % seconds_c.to_i}" : "#{negative_seconds}#{seconds_c.round(4)}") : "00")
|
184
|
+
result << (years_c[0] != 0 ? "+ #{negative_months}#{years_c[0]} years" : "")
|
185
|
+
result << (years_c[1] != 0 ? "+ #{negative_months}#{years_c[1]} months": "")
|
186
|
+
result << (days_c[0] != 0 ? "+ #{negative_months}#{days_c[0]} days" : "")
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
#include :hours in inspect
|
191
|
+
def inspect #:nodoc:
|
192
|
+
consolidated = parts.inject(::Hash.new(0)) { |h,(l,r)| h[l] += r; h }
|
193
|
+
parts = [:years, :months, :days, :hours, :minutes, :seconds].map do |length|
|
194
|
+
n = consolidated[length]
|
195
|
+
"#{n} #{n == 1 ? length.to_s.singularize : length.to_s}" if n.nonzero?
|
196
|
+
end.compact
|
197
|
+
parts = ["0 seconds"] if parts.empty?
|
198
|
+
parts.to_sentence(:locale => :en)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Adds another Duration or a Numeric to this Duration. Numeric values
|
202
|
+
# are treated as seconds.
|
203
|
+
def +(other)
|
204
|
+
if ::Duration === other
|
205
|
+
::Duration.new(value + other.value, @parts + other.parts)
|
206
|
+
else
|
207
|
+
if ::Time === other
|
208
|
+
other + self
|
209
|
+
else
|
210
|
+
::Duration.new(value + other, @parts + [[:seconds, other]])
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Subtracts another Duration or a Numeric from this Duration. Numeric
|
216
|
+
# values are treated as seconds.
|
217
|
+
def -(other)
|
218
|
+
if ::Duration === other
|
219
|
+
|
220
|
+
::Duration.new(value - other.value, @parts +( other.parts.dup.map! { |k,v| [k,-v] } ))
|
221
|
+
else
|
222
|
+
if ::Time === other
|
223
|
+
# minus operator is not canonical
|
224
|
+
else
|
225
|
+
::Duration.new(value - other, @parts + [[:seconds, -other]])
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
Duration = ActiveSupport::Duration
|
234
|
+
d= (Duration.new("PT0S")+Duration.new("PT3M"))
|
235
|
+
puts d.as_24h_clock
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pravigo/duration/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "pravigo-duration"
|
8
|
+
spec.version = "0.0.1"
|
9
|
+
spec.authors = ["Rich Hall"]
|
10
|
+
spec.email = ["rich@pravigo.org"]
|
11
|
+
spec.summary = %q{manipulate iso8601 durations}
|
12
|
+
spec.description = %q{Pravigo::Duration extends ActiveSupport::Duration class to add iso8601 support}
|
13
|
+
spec.homepage = "https://github.com/pravigo/pravigo-duration"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_runtime_dependency "activesupport"
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,455 @@
|
|
1
|
+
# duration_spec.rb
|
2
|
+
require "spec_helper"
|
3
|
+
#require 'active_support/time'
|
4
|
+
#require File.expand_path(File.dirname(__FILE__) + '/duration')
|
5
|
+
|
6
|
+
Duration = ActiveSupport::Duration
|
7
|
+
|
8
|
+
describe Duration do
|
9
|
+
|
10
|
+
MONTHS_IN_A_YEAR = 12
|
11
|
+
SECONDS_IN_A_WEEK=604800
|
12
|
+
SECONDS_IN_A_DAY=86400
|
13
|
+
SECONDS_IN_AN_HOUR=3600
|
14
|
+
SECONDS_IN_A_MINUTE=60
|
15
|
+
#Approximate number of seconds in a month and year
|
16
|
+
SECONDS_IN_A_YEAR=(SECONDS_IN_A_DAY*365)
|
17
|
+
SECONDS_IN_A_MONTH=(SECONDS_IN_A_DAY * 30)
|
18
|
+
|
19
|
+
let(:duration_of_0_iso8601_string) { Duration.new('PT0s') }
|
20
|
+
let(:duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string) { Duration.new('PT5m30s') }
|
21
|
+
let(:duration_of_5_minutes_and_30_seconds_initialised_from_hhmmss_string) { Duration.new('00:05:30') }
|
22
|
+
let(:duration_of_4_minutes_initialised_by_value_and_parts) { Duration.new(240,[[:minutes, 4]]) }
|
23
|
+
let(:duration_of_4_minutes_initialised_by_numeric) { Duration.new(240) }
|
24
|
+
let(:activeSupport_Duration_of_4_minutes) { ActiveSupport::Duration.new(240,[[:minutes, 4]]) }
|
25
|
+
let(:activeSupport_Duration_of_5_minutes) { ActiveSupport::Duration.new(300,[[:minutes, 5]]) }
|
26
|
+
let(:activeSupport_Duration_of_1_year_3_months_and_3_hours) { ActiveSupport::Duration.new((SECONDS_IN_A_YEAR+(SECONDS_IN_A_MONTH*3)+(SECONDS_IN_AN_HOUR*3)),[[:years, 1],[:months,3],[:hours,3]]) }
|
27
|
+
let(:duration_of_5_minutes_initialised_by_ActiveSupport_Duration) { Duration.new(activeSupport_Duration_of_5_minutes) }
|
28
|
+
let(:time_2014_02_28_1558_28) { Time.new(2014, 02, 28, 15, 58, 28) }
|
29
|
+
let(:duration_of_1_year_5_months_and_3_hours) { Duration.new('P1y5mT3h') }
|
30
|
+
let(:invalid_Duration_missing_T) { Duration.new('P5m30s') }
|
31
|
+
|
32
|
+
#seconds as a float
|
33
|
+
let(:y____s_float) { Duration.new('P1YT1.234S')}
|
34
|
+
let(:ym___s_float) { Duration.new('P1Y1MT1.234S')}
|
35
|
+
let(:ymd__s_float) { Duration.new('P1Y1M1DT1.234S')}
|
36
|
+
let(:ymdh_s_float) { Duration.new('P1Y1M1DT1H1.234S')}
|
37
|
+
let(:ymdhms_float) { Duration.new('P1Y1M1DT1H1M1.234S')}
|
38
|
+
let(:_m___s_float) { Duration.new('P1MT1.234S')}
|
39
|
+
let(:_md__s_float) { Duration.new('P1M1DT1.234S')}
|
40
|
+
let(:_mdh_s_float) { Duration.new('P1M1DT1H1.234S')}
|
41
|
+
let(:_mdhms_float) { Duration.new('P1M1DT1H1M1.234S')}
|
42
|
+
let(:__d__s_float) { Duration.new('P1DT1.234S')}
|
43
|
+
let(:__dh_s_float) { Duration.new('P1DT1H1.234S')}
|
44
|
+
let(:__dhms_float) { Duration.new('P1DT1H1M1.234S')}
|
45
|
+
let(:___h_s_float) { Duration.new('PT1H1.234S')}
|
46
|
+
let(:___hms_float) { Duration.new('PT1H1M1.234S')}
|
47
|
+
let(:____ms_float) { Duration.new('PT1M1.234S')}
|
48
|
+
let(:_____s_float) { Duration.new('PT1.234S')}
|
49
|
+
|
50
|
+
describe '.initialise' do
|
51
|
+
|
52
|
+
context 'given valid iso8601 string' do
|
53
|
+
|
54
|
+
it 'creates an instance of Duration' do
|
55
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string.__realclass__.should eq(Duration)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'creates a new parts array' do
|
59
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string.parts.should eq([[:minutes,5],[:seconds,30.0]])
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'creates a new value' do
|
64
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string.value.should eq(330.0)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'outputs a valid iso8601 representation' do
|
68
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string.iso8601.should eq('PT5M30S')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'creates a subclass of ActiveSupport::Duration' do
|
72
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string.is_a? ActiveSupport::Duration).should eq(true)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'given an invalid iso8601 string' do
|
78
|
+
|
79
|
+
it 'returns a NilClass' do
|
80
|
+
expect(invalid_Duration_missing_T).to be_a NilClass
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'given valid hh:mm:ss string' do
|
86
|
+
|
87
|
+
it 'creates an instance of Duration' do
|
88
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_hhmmss_string.__realclass__.should eq(Duration)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'creates a new parts array' do
|
92
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_hhmmss_string.parts.should eq([[:minutes,5],[:seconds,30.0]])
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'creates a new value' do
|
97
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_hhmmss_string.value.should eq(330.0)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'outputs a valid iso8601 representation' do
|
101
|
+
duration_of_5_minutes_and_30_seconds_initialised_from_hhmmss_string.iso8601.should eq('PT5M30S')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'creates a subclass of ActiveSupport::Duration' do
|
105
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_hhmmss_string.is_a? ActiveSupport::Duration).should eq(true)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
context 'given a value and parts array' do
|
112
|
+
|
113
|
+
it 'creates an instance of Duration' do
|
114
|
+
duration_of_4_minutes_initialised_by_value_and_parts.__realclass__.should eq(Duration)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'creates a new parts array' do
|
118
|
+
duration_of_4_minutes_initialised_by_value_and_parts.parts.should eq([[:minutes,4]])
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'creates a new value' do
|
122
|
+
duration_of_4_minutes_initialised_by_value_and_parts.value.should eq(240)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'outputs a valid iso8601 representation' do
|
126
|
+
duration_of_4_minutes_initialised_by_value_and_parts.iso8601.should eq('PT4M')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'creates a subclass of ActiveSupport::Duration' do
|
130
|
+
(duration_of_4_minutes_initialised_by_value_and_parts.is_a? ActiveSupport::Duration).should eq(true)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'creates a Duration equal to ActiveSupport::Duration initialised the same way' do
|
134
|
+
duration_of_4_minutes_initialised_by_value_and_parts.should eq(activeSupport_Duration_of_4_minutes)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'given a numeric' do
|
140
|
+
|
141
|
+
it 'creates an instance of Duration' do
|
142
|
+
duration_of_4_minutes_initialised_by_numeric.__realclass__.should eq(Duration)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'assumes the numeric to be seconds and creates a new parts array' do
|
146
|
+
duration_of_4_minutes_initialised_by_numeric.parts.should eq([[:minutes,4]])
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'assumes the numeric to be seconds and creates a new value' do
|
150
|
+
duration_of_4_minutes_initialised_by_numeric.value.should eq(240)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'outputs a valid iso8601 representation' do
|
154
|
+
duration_of_4_minutes_initialised_by_numeric.iso8601.should eq('PT4M')
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'creates a subclass of ActiveSupport::Duration' do
|
158
|
+
(duration_of_4_minutes_initialised_by_numeric.is_a? ActiveSupport::Duration).should eq(true)
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'given an ActiveSupport::Duration' do
|
164
|
+
|
165
|
+
it 'creates an instance of Duration' do
|
166
|
+
duration_of_5_minutes_initialised_by_ActiveSupport_Duration.__realclass__.should eq(Duration)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'creates a new parts array' do
|
170
|
+
duration_of_5_minutes_initialised_by_ActiveSupport_Duration.parts.should eq([[:minutes,5]])
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'creates a new value' do
|
174
|
+
duration_of_5_minutes_initialised_by_ActiveSupport_Duration.value.should eq(300.0)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'outputs a valid iso8601 representation' do
|
178
|
+
duration_of_5_minutes_initialised_by_ActiveSupport_Duration.iso8601.should eq('PT5M')
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'creates a subclass of ActiveSupport::Duration' do
|
182
|
+
(duration_of_5_minutes_initialised_by_ActiveSupport_Duration.is_a? ActiveSupport::Duration).should eq(true)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'creates a Duration equal to ActiveSupport::Duration initialised the same way' do
|
186
|
+
duration_of_5_minutes_initialised_by_ActiveSupport_Duration.should eq(activeSupport_Duration_of_5_minutes)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "iso8604 testing" do
|
194
|
+
{"PT0S" => [[],0,"P"],
|
195
|
+
"P1Y" => [[[:years,1]],(SECONDS_IN_A_DAY*365),"P1Y"],
|
196
|
+
"P1Y1M" => [[[:years,1],[:months,1]],(SECONDS_IN_A_DAY*365)+SECONDS_IN_A_MONTH, "P1Y1M"],
|
197
|
+
"P1YT1H" => [[[:years,1],[:hours,1]], (SECONDS_IN_A_DAY*365)+SECONDS_IN_AN_HOUR, "P1YT1H"],
|
198
|
+
"P1YT1M" => [[[:years,1],[:minutes,1]],(SECONDS_IN_A_DAY*365)+60,"P1YT1M"],
|
199
|
+
"P1YT1S" => [[[:years,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*365)+1,"P1YT1S"],
|
200
|
+
"P1Y1M1D" => [[[:years,1],[:months,1],[:days,1]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31),"P1Y1M1D"],
|
201
|
+
"P1Y1MT1H" => [[[:years,1],[:months,1],[:hours,1]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*30)+SECONDS_IN_AN_HOUR,"P1Y1MT1H"],
|
202
|
+
"P1Y1MT1M" => [[[:years,1],[:months,1],[:minutes,1]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*30)+60,"P1Y1MT1M" ],
|
203
|
+
"P1Y1MT1S" => [[[:years,1],[:months,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*30)+1 ,"P1Y1MT1S"],
|
204
|
+
"P1Y1M1DT1H" => [[[:years,1],[:months,1],[:days,1],[:hours,1]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR,"P1Y1M1DT1H"],
|
205
|
+
"P1Y1M1DT1M" => [[[:years,1],[:months,1],[:days,1],[:minutes,1]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31)+60,"P1Y1M1DT1M"],
|
206
|
+
"P1Y1M1DT1S" => [[[:years,1],[:months,1],[:days,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31)+1,"P1Y1M1DT1S"],
|
207
|
+
"P1Y1M1DT1H1M" => [[[:years,1],[:months,1],[:days,1],[:hours,1],[:minutes,1]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR+60,"P1Y1M1DT1H1M"],
|
208
|
+
"P1Y1M1DT1H1S" => [[[:years,1],[:months,1],[:days,1],[:hours,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR+1,"P1Y1M1DT1H1S"],
|
209
|
+
"P1Y1M1DT1H1M1S" => [[[:years,1],[:months,1],[:days,1],[:hours,1],[:minutes,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*365)+(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR+61,"P1Y1M1DT1H1M1S"],
|
210
|
+
"P1M" => [[[:months,1]],(SECONDS_IN_A_DAY*30),"P1M"],
|
211
|
+
"P1M1D" => [[[:months,1],[:days,1]],(SECONDS_IN_A_DAY*31),"P1M1D"],
|
212
|
+
"P1MT1H" => [[[:months,1],[:hours,1]],(SECONDS_IN_A_DAY*30)+SECONDS_IN_AN_HOUR,"P1MT1H"],
|
213
|
+
"P1MT1M" => [[[:months,1],[:minutes,1]],(SECONDS_IN_A_DAY*30)+60,"P1MT1M"],
|
214
|
+
"P1MT1S" => [[[:months,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*30)+1,"P1MT1S"],
|
215
|
+
"P1M1DT1H" => [[[:months,1],[:days,1],[:hours,1]],(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR,"P1M1DT1H"],
|
216
|
+
"P1M1DT1M" => [[[:months,1],[:days,1],[:minutes,1]],(SECONDS_IN_A_DAY*31)+60,"P1M1DT1M"],
|
217
|
+
"P1M1DT1S" => [[[:months,1],[:days,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*31)+1,"P1M1DT1S"],
|
218
|
+
"P1M1DT1H1M" => [[[:months,1],[:days,1],[:hours,1],[:minutes,1]],(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR+60,"P1M1DT1H1M"],
|
219
|
+
"P1M1DT1H1S" => [[[:months,1],[:days,1],[:hours,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR+1,"P1M1DT1H1S"],
|
220
|
+
"P1M1DT1H1M1S" => [[[:months,1],[:days,1],[:hours,1],[:minutes,1],[:seconds,1.0]],(SECONDS_IN_A_DAY*31)+SECONDS_IN_AN_HOUR+61,"P1M1DT1H1M1S"],
|
221
|
+
"P1D" => [[[:days,1]],SECONDS_IN_A_DAY,"P1D"],
|
222
|
+
"P1DT1H" => [[[:days,1],[:hours,1]],SECONDS_IN_A_DAY+SECONDS_IN_AN_HOUR,"P1DT1H"],
|
223
|
+
"P1DT1M" => [[[:days,1],[:minutes,1]],SECONDS_IN_A_DAY+60,"P1DT1M"],
|
224
|
+
"P1DT1S" => [[[:days,1],[:seconds,1.0]],SECONDS_IN_A_DAY+1,"P1DT1S"],
|
225
|
+
"P1DT1H1M" => [[[:days,1],[:hours,1],[:minutes,1]],SECONDS_IN_A_DAY+SECONDS_IN_AN_HOUR+60,"P1DT1H1M"],
|
226
|
+
"P1DT1H1S" => [[[:days,1],[:hours,1],[:seconds,1.0]],SECONDS_IN_A_DAY+SECONDS_IN_AN_HOUR+1,"P1DT1H1S"],
|
227
|
+
"P1DT1H1M1S" => [[[:days,1],[:hours,1],[:minutes,1],[:seconds,1.0]],SECONDS_IN_A_DAY+SECONDS_IN_AN_HOUR+61,"P1DT1H1M1S"],
|
228
|
+
"PT1H" => [[[:hours,1]],SECONDS_IN_AN_HOUR,"PT1H"],
|
229
|
+
"PT1H1M" => [[[:hours,1],[:minutes,1]],SECONDS_IN_AN_HOUR+60,"PT1H1M"],
|
230
|
+
"PT1H1S" => [[[:hours,1],[:seconds,1.0]],SECONDS_IN_AN_HOUR+1,"PT1H1S"],
|
231
|
+
"PT1H1M1S" => [[[:hours,1],[:minutes,1],[:seconds,1.0]],SECONDS_IN_AN_HOUR+61,"PT1H1M1S"],
|
232
|
+
"PT1M" => [[[:minutes,1]],60,"PT1M"],
|
233
|
+
"PT1M1S" => [[[:minutes,1],[:seconds,1.0]],61,"PT1M1S"],
|
234
|
+
"PT1S" => [[[:seconds,1.0]],1,"PT1S"],
|
235
|
+
"PT1.2345S" => [[[:seconds,1.2345]],1.2345,"PT1.2345S"],
|
236
|
+
"PT1.234S" => [[[:seconds,1.234]],1.234,"PT1.234S"],
|
237
|
+
"PT1.23S" => [[[:seconds,1.23]],1.23,"PT1.23S"],
|
238
|
+
"PT1.2S" => [[[:seconds,1.2]],1.2,"PT1.2S"],
|
239
|
+
"PT1,2345S" => [[[:seconds,1.2345]],1.2345,"PT1.2345S"],
|
240
|
+
"PT1,234S" => [[[:seconds,1.234]],1.234,"PT1.234S"],
|
241
|
+
"PT1,23S" => [[[:seconds,1.23]],1.23,"PT1.23S"],
|
242
|
+
"PT1,2S" => [[[:seconds,1.2]],1.2,"PT1.2S"]
|
243
|
+
|
244
|
+
}.each do |input, output|
|
245
|
+
durationToTest = Duration.new(input)
|
246
|
+
context "given a valid iso8601 duration string: #{input}, the initialised Duration" do
|
247
|
+
|
248
|
+
it "has parts = #{output[0].to_s}" do
|
249
|
+
durationToTest.parts.should eq(output[0])
|
250
|
+
end
|
251
|
+
|
252
|
+
it "has value = #{output[1].to_s} seconds" do
|
253
|
+
durationToTest.value.should eq(output[1])
|
254
|
+
end
|
255
|
+
|
256
|
+
it "returns #{output[2]} as iso8601" do
|
257
|
+
durationToTest.iso8601.should eq(output[2])
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe '#+ (add)' do
|
264
|
+
context 'given a Time' do
|
265
|
+
|
266
|
+
it 'returns a time' do
|
267
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+time_2014_02_28_1558_28).should be_an_instance_of Time
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'increases the Time by the Duration' do
|
271
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+time_2014_02_28_1558_28).should eq(Time.new(2014, 02, 28, 16, 03, 58))
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
context 'given a Duration' do
|
278
|
+
|
279
|
+
it 'returns a Duration' do
|
280
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).__realclass__.should eq(Duration)
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'returns the sum of the two Durations' do
|
284
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).should eq(Duration.new('PT11m'))
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
context 'given an ActiveSupport::Duration' do
|
290
|
+
it 'returns a Duration' do
|
291
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+activeSupport_Duration_of_4_minutes).__realclass__.should eq(Duration)
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'returns the sum of the two Durations' do
|
295
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+activeSupport_Duration_of_4_minutes).should eq(Duration.new('PT9m30s'))
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context 'given a Numeric' do
|
300
|
+
it 'returns a Duration' do
|
301
|
+
expect((duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+30).__realclass__).to eq(Duration)
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'assumes the Numeric is seconds and adds to the Duration' do
|
305
|
+
expect(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string+30).to eq(360)
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
describe '#- (subtract)' do
|
313
|
+
|
314
|
+
context 'given a Duration' do
|
315
|
+
|
316
|
+
it 'returns a Duration' do
|
317
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string-duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).__realclass__.should eq(Duration)
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'returns the Duration minus the second duration' do
|
321
|
+
(duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string-duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).should eq(Duration.new('P'))
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'returns the Duration minus the second duration' do
|
325
|
+
(duration_of_4_minutes_initialised_by_value_and_parts-duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).should eq(Duration.new('PT-1M-30S'))
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'returns the Duration minus the second duration' do
|
329
|
+
((Duration.new("PT40M")-Duration.new("PT38M")).should eq(Duration.new('PT2M')))
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'returns the Duration minus the second duration' do
|
333
|
+
((Duration.new("PT40M")-Duration.new("PT38M")).parts.should eq([[:minutes, 40], [:minutes, -38]]))
|
334
|
+
end
|
335
|
+
|
336
|
+
|
337
|
+
end
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
describe '#iso80601' do
|
342
|
+
|
343
|
+
let(:duration_with_15_months) { Duration.new('P15M') }
|
344
|
+
let(:duration_with_75_seconds) { Duration.new('PT75S') }
|
345
|
+
let(:duration_with_70_minutes) { Duration.new('PT70M') }
|
346
|
+
let(:duration_with_27_hours) { Duration.new('PT27H') }
|
347
|
+
let(:duration_with_9_days) { Duration.new('P9D') }
|
348
|
+
let(:duration_with_2_months_and_45_days) { Duration.new('P2M45D') }
|
349
|
+
let(:duration_with_second_to_6_decimal_places) { Duration.new(1.234567,[[:seconds,1.234567]]) }
|
350
|
+
|
351
|
+
|
352
|
+
it 'returns iso8601 representation in years and months when months is 12 or over' do
|
353
|
+
duration_with_15_months.iso8601.should eq('P1Y3M')
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'returns iso8601 representation in minutes and seconds when seconds is 60 or over' do
|
358
|
+
duration_with_75_seconds.iso8601.should eq('PT1M15S')
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'returns iso8601 representation in hours and minutes when minutes is 60 or over' do
|
362
|
+
duration_with_70_minutes.iso8601.should eq('PT1H10M')
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'returns iso8601 representation in days and hours when hours is 24 or over' do
|
366
|
+
duration_with_27_hours.iso8601.should eq('P1DT3H')
|
367
|
+
end
|
368
|
+
|
369
|
+
it 'returns iso8601 representation in days when number of days exceeds 7 (weeks are ignored)' do
|
370
|
+
duration_with_9_days.iso8601.should eq('P9D')
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'returns iso8601 representation in days when days clearly exceeds number of possible days in a month' do
|
374
|
+
duration_with_2_months_and_45_days.iso8601.should eq('P2M45D')
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'returns iso8601 representation with seconds rounded to 4 decimal places' do
|
378
|
+
duration_with_second_to_6_decimal_places.iso8601.should eq('PT1.2346S')
|
379
|
+
end
|
380
|
+
|
381
|
+
end
|
382
|
+
|
383
|
+
describe 'Test adding a Duration to an ActiveSupport::Duration' do
|
384
|
+
it 'returns an ActiveSupport:Duration' do
|
385
|
+
(activeSupport_Duration_of_4_minutes + duration_of_4_minutes_initialised_by_value_and_parts).__realclass__.should eq(ActiveSupport::Duration)
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'returns the sum of the two durations' do
|
389
|
+
expect(activeSupport_Duration_of_4_minutes + duration_of_4_minutes_initialised_by_value_and_parts).to eq(ActiveSupport::Duration.new(480,[[:minutes,4],[:minutes,4]]))
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'confirms ActiveSupport::Duration behaviour combines parts when matching i.e. [[:minutes,4],[:minutes,4]] is equal to [[:minutes,8]]' do
|
393
|
+
expect(activeSupport_Duration_of_4_minutes + duration_of_4_minutes_initialised_by_value_and_parts).to eq(ActiveSupport::Duration.new(480,[[:minutes,8]]))
|
394
|
+
end
|
395
|
+
|
396
|
+
it 'preserves months and years (does not convert to seconds)' do
|
397
|
+
expect(Duration.new(activeSupport_Duration_of_1_year_3_months_and_3_hours+duration_of_1_year_5_months_and_3_hours).iso8601).to eq("P2Y8MT6H")
|
398
|
+
end
|
399
|
+
|
400
|
+
end
|
401
|
+
|
402
|
+
describe 'Test adding a Duration to a Time' do
|
403
|
+
|
404
|
+
it 'returns a time' do
|
405
|
+
(time_2014_02_28_1558_28+duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).should be_an_instance_of Time
|
406
|
+
end
|
407
|
+
|
408
|
+
it 'increases the Time by the Duration' do
|
409
|
+
(time_2014_02_28_1558_28+duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).should eq(Time.new(2014, 02, 28, 16, 03, 58))
|
410
|
+
end
|
411
|
+
|
412
|
+
it 'correctly handles months and years (does not convert to seconds)' do
|
413
|
+
(time_2014_02_28_1558_28+duration_of_1_year_5_months_and_3_hours).should eq(Time.new(2015, 07, 28, 18, 58, 28))
|
414
|
+
end
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
describe 'Test adding a Duration to a Numeric' do
|
419
|
+
it 'returns a Numeric' do
|
420
|
+
expect((100+duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).is_a? Numeric).to eq(true)
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'returns the Numeric plus the Duration in seconds' do
|
424
|
+
(100+duration_of_5_minutes_and_30_seconds_initialised_from_iso8601_string).should eq(430)
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'assumes a year is 365 days and a month is 30 days' do
|
428
|
+
expect(100+duration_of_1_year_5_months_and_3_hours).to eq(SECONDS_IN_A_YEAR+(SECONDS_IN_A_MONTH*5)+(SECONDS_IN_AN_HOUR*3)+100)
|
429
|
+
end
|
430
|
+
|
431
|
+
end
|
432
|
+
|
433
|
+
# TODO
|
434
|
+
# .years
|
435
|
+
# .months
|
436
|
+
# .hours
|
437
|
+
# .minutes
|
438
|
+
# .seconds
|
439
|
+
# .tenths
|
440
|
+
# .hundredths
|
441
|
+
# .thousandths
|
442
|
+
# should return normalised part
|
443
|
+
# .in_years
|
444
|
+
# .in_months
|
445
|
+
# .in_hours
|
446
|
+
# .in_minutes
|
447
|
+
# .in_seconds
|
448
|
+
# .in_tenths
|
449
|
+
# .in_hundredths
|
450
|
+
# .in_thousandths
|
451
|
+
# should return decimal representation
|
452
|
+
#
|
453
|
+
# mathematical operations should normalise the internal representation (as far as days)
|
454
|
+
|
455
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "pravigo/duration"
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pravigo-duration
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rich Hall
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-07-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.5'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.5'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: activesupport
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Pravigo::Duration extends ActiveSupport::Duration class to add iso8601
|
79
|
+
support
|
80
|
+
email:
|
81
|
+
- rich@pravigo.org
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- .rspec
|
88
|
+
- Gemfile
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- lib/pravigo/duration.rb
|
93
|
+
- lib/pravigo/duration/version.rb
|
94
|
+
- pravigo-duration.gemspec
|
95
|
+
- spec/duration_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
homepage: https://github.com/pravigo/pravigo-duration
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.8.28
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: manipulate iso8601 durations
|
122
|
+
test_files:
|
123
|
+
- spec/duration_spec.rb
|
124
|
+
- spec/spec_helper.rb
|