time_frame 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bff74b0836d124c9e908e78228d6d2d6ce69a5c3
4
- data.tar.gz: 2f508be6ca07c0d76e33c09da5491c69ebceed95
3
+ metadata.gz: f106979451ecad285f797d3da950839ab3f06af0
4
+ data.tar.gz: b1140e0f5bc73bbcf1ec5a8dd467057f7094b57c
5
5
  SHA512:
6
- metadata.gz: e46135147bb82bd9eead8ea48855359068dd1b8788547c57176c46b9791e17b6f7c76bc0ad193947cbfeca41ead41f4f785b598d95b0b4b059f9645084fd0ea5
7
- data.tar.gz: fa004da36e99f6b3c0cba0e00e5f713d405013935a37e4b412f765dbeb7d9e1b630695efbffbacc8865486175f4f3b552ae069c17575159c9f06fdff9b5347a4
6
+ metadata.gz: d632b2b40b133b92c70c259def3d414980ffdf548bfdbf96ed1c767ef73097df4794273268c3455076d3e358ca97641826a6b6b7efd39e04b2f0ce4c3c5d049b
7
+ data.tar.gz: 088b62f79eb26489a6dfdd9d57bc39479f7cbc96e6b54f9b44012a501ef60f97246d695f52d2db7c66d9add7ee84bdb2abbd3f0ea9b20dc30af806c617f0689b
data/README.md CHANGED
@@ -23,66 +23,82 @@ or just by specifying a `min` and `duration`
23
23
  time_frame = TimeFrame.new(min: Time.now, duration: 1.day)
24
24
  ```
25
25
 
26
- Let's play around a bit:
26
+ ###Important:
27
+ TimeFrame doesn't support Date class.
27
28
 
28
- ```ruby
29
- # Using pp in some samples to beautify output:
30
- require 'pp'
31
- # => true
29
+ ## Let's play around a bit...
32
30
 
33
- # Create a time frame instance from today with duration of 1 day
31
+ Create a time frame instance from today with duration of 1 day
32
+ ```ruby
34
33
  time_frame = TimeFrame.new(min: Time.now, duration: 1.day)
35
34
  # => 2014-05-07 14:58:47 +0200..2014-05-08 14:58:47 +0200
35
+ ```
36
36
 
37
- # Get the duration
37
+ Get the duration
38
+ ```ruby
38
39
  time_frame.duration
39
40
  # => 86400.0 seconds
41
+ ```
40
42
 
41
- # Shift the whole time frame by... let's say... 2 days!
43
+ Shift the whole time frame by... let's say... 2 days!
44
+ ```ruby
42
45
  later = time_frame.shift_by(2.days)
43
46
  # => 2014-05-09 14:58:47 +0200..2014-05-10 14:58:47 +0200
47
+ ```
44
48
 
45
- # Shifting can also be done in the other direction...
49
+ Shifting can also be done in the other direction...
50
+ ```ruby
46
51
  earlier = time_frame.shift_by(-2.days)
47
52
  # => 2014-05-05 14:58:47 +0200..2014-05-06 14:58:47 +0200
53
+ ```
48
54
 
49
- # Is another time covered by our time frame?
55
+ Is another time covered by our time frame?
56
+ ```ruby
50
57
  my_time = Time.new(2014, 5, 7, 16)
51
58
  time_frame.cover?(my_time)
52
59
  # => true
60
+ ```
53
61
 
54
- # Shifting to another time... duration remains:
62
+ Shifting to another time... duration remains:
63
+ ```ruby
55
64
  time_frame.shift_to(Time.new(2016, 1, 1))
56
65
  # => 2016-01-01 00:00:00 +0100..2016-01-02 00:00:00 +0100
66
+ ```
57
67
 
58
- # Checking whether another time frame overlaps:
68
+ Checking whether another time frame overlaps:
69
+ ```ruby
59
70
  other_frame = TimeFrame.new(
60
71
  min: time_frame.min - 3.days,
61
72
  max: time_frame.min + 40.minutes
62
73
  )
63
74
  time_frame.overlaps?(other_frame)
64
75
  # => true
76
+ ```
65
77
 
66
- # Time frame without another time frame:
78
+ Time frame without another time frame:
79
+ ```ruby
67
80
  time_frame = TimeFrame.new(min: Time.new(2014, 5, 12), duration: 1.day)
68
81
  other = TimeFrame.new(min: Time.new(2014, 5, 12, 19), duration: 10.minutes)
69
- pp time_frame.without(other)
82
+ time_frame.without(other)
70
83
  # [2014-05-12 00:00:00 +0200..2014-05-12 19:00:00 +0200,
71
84
  # 2014-05-12 19:10:00 +0200..2014-05-13 00:00:00 +0200]
85
+ ```
72
86
 
73
- # You can also use without with many TimeFrame's:
87
+ You can also use without with many TimeFrame's:
88
+ ```ruby
74
89
  another = other.shift_by(15.minutes)
75
- pp time_frame.without(other, another)
90
+ time_frame.without(other, another)
76
91
  # [2014-05-12 00:00:00 +0200..2014-05-12 19:00:00 +0200,
77
92
  # 2014-05-12 19:10:00 +0200..2014-05-12 19:15:00 +0200,
78
93
  # 2014-05-12 19:25:00 +0200..2014-05-13 00:00:00 +0200]
94
+ ```
79
95
 
80
- # Use of the mathematical &. The intersection is returned:
96
+ Use of the mathematical &. The intersection is returned:
97
+ ```ruby
81
98
  time_frame = TimeFrame.new(min: Time.new(2014), duration: 1.day)
82
99
  other_time_frame = time_frame.shift_by(12.hours)
83
100
  time_frame & other_time_frame
84
101
  # => 2014-01-01 12:00:00 +0100..2014-01-02 00:00:00 +0100
85
-
86
102
  ```
87
103
 
88
104
  These are the most common functionalities of the `TimeFrame` class, but there is quite more to discover. If you have an array of time frames, you can compute their union and pairwise intersection using `TimeFrame.union` and `TimeFrame.intersection`. For two sorted arrays of time frames, you can traverse all overlaps of time frames in the first array with time frames in the second array in **linear time** using `TimeFrame.each_overlap`.
@@ -11,20 +11,20 @@ class TimeFrame
11
11
  EMPTY = Empty.instance
12
12
 
13
13
  def initialize(args)
14
- min = args.fetch(:min)
15
- max = args.fetch(:max) { min + args.fetch(:duration) }
16
- check_bounds(max, min)
17
- @max = max
18
- @min = min
14
+ @min = args.fetch(:min)
15
+ @max = args.fetch(:max) { @min + args.fetch(:duration) }
16
+ check_bounds
17
+ @max_float = @max.to_f
18
+ @min_float = @min.to_f
19
19
  end
20
20
 
21
21
  def duration
22
- (max - min).seconds
22
+ @duration ||= (@max_float - @min_float)
23
23
  end
24
24
 
25
25
  def ==(other)
26
- min == other.min &&
27
- max == other.max
26
+ @min_float == other.min_float &&
27
+ @max_float == other.max_float
28
28
  end
29
29
 
30
30
  alias_method :eql?, :==
@@ -34,42 +34,44 @@ class TimeFrame
34
34
  end
35
35
 
36
36
  def cover?(element)
37
- if rangy?(element)
38
- element.empty? || min <= element.min && element.max <= max
37
+ if element.is_a?(TimeFrame)
38
+ element.empty? ||
39
+ @min_float <= element.min_float && element.max_float <= max_float
39
40
  else
40
- min <= element && element <= max
41
+ min_float <= element.to_f && element.to_f <= max_float
41
42
  end
42
43
  end
43
44
 
44
45
  def before?(item)
45
46
  case
46
- when rangy?(item)
47
+ when item.is_a?(TimeFrame)
47
48
  fail_if_empty item
48
- item.min > max
49
+ item.min.to_f > max_float
49
50
  else
50
- item > max
51
+ item.to_f > max_float
51
52
  end
52
53
  end
53
54
 
54
55
  def after?(item)
55
56
  case
56
- when rangy?(item)
57
+ when item.is_a?(TimeFrame)
57
58
  fail_if_empty item
58
- item.max < min
59
+ item.max.to_f < min_float
59
60
  else
60
- item < min
61
+ item.to_f < min_float
61
62
  end
62
63
  end
63
64
 
64
65
  def time_between(item)
65
66
  case
66
- when rangy?(item)
67
+ when item.is_a?(TimeFrame)
67
68
  fail_if_empty item
68
69
  [time_between(item.min), time_between(item.max)].min_by(&:abs)
69
70
  when cover?(item)
70
71
  0
71
72
  else
72
- [(item - min).abs, (item - max).abs].min
73
+ float_value = item.to_f
74
+ [(float_value - min_float).abs, (float_value - max_float).abs].min
73
75
  end
74
76
  end
75
77
 
@@ -90,7 +92,7 @@ class TimeFrame
90
92
  # Returns true if the interior intersect.
91
93
  def overlaps?(other)
92
94
  return false if other.duration == 0
93
- other.max > min && other.min < max
95
+ other.max_float > min_float && other.min_float < max_float
94
96
  end
95
97
 
96
98
  def &(other)
@@ -142,27 +144,25 @@ class TimeFrame
142
144
  intersection = self & other
143
145
 
144
146
  result = []
145
- if intersection.min > min
147
+ if intersection.min_float > min_float
146
148
  result << TimeFrame.new(min: min, max: intersection.min)
147
149
  end
148
- if intersection.max < max
150
+ if intersection.max_float < max_float
149
151
  result << TimeFrame.new(min: intersection.max, max: max)
150
152
  end
151
153
  result
152
154
  end
153
155
 
156
+ attr_reader :min_float, :max_float
157
+
154
158
  private
155
159
 
156
160
  def fail_if_empty(item)
157
- fail ArgumentError, 'time frame is empty' if item.respond_to?(:empty) &&
161
+ fail ArgumentError, 'time frame is empty' if item.respond_to?(:empty?) &&
158
162
  item.empty?
159
163
  end
160
164
 
161
- def rangy?(item)
162
- item.respond_to?(:min) && item.respond_to?(:max)
163
- end
164
-
165
- def check_bounds(max, min)
165
+ def check_bounds
166
166
  fail ArgumentError, 'min is greater than max.' if min > max
167
167
  end
168
168
  end
@@ -1,5 +1,5 @@
1
1
  # Encoding: utf-8
2
2
  # gem version
3
3
  class TimeFrame
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,8 @@ RSpec.configure do |config|
13
13
  config.order = 'random'
14
14
  end
15
15
 
16
+ require 'byebug'
17
+
16
18
  # active_record setup for active_record handler specs
17
19
  ActiveRecord::Base.establish_connection(
18
20
  adapter: 'sqlite3', database: ':memory:'
@@ -94,7 +94,7 @@ describe TimeFrame do
94
94
  context 'and duration is 0' do
95
95
  it 'should be valid' do
96
96
  expect do
97
- TimeFrame.new(min: Date.new(2012), duration: 0.seconds)
97
+ TimeFrame.new(min: Time.utc(2012), duration: 0.seconds)
98
98
  end.not_to raise_error
99
99
  end
100
100
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: time_frame
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Derichs
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-10-22 00:00:00.000000000 Z
13
+ date: 2014-10-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake