time_frame 0.5.0 → 0.6.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.
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