ice_cube 0.13.2 → 0.13.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ice_cube.rb +1 -1
- data/lib/ice_cube/enumerator.rb +69 -0
- data/lib/ice_cube/hash_input.rb +71 -0
- data/lib/ice_cube/time_step.rb +30 -0
- data/lib/ice_cube/time_util.rb +2 -2
- data/lib/ice_cube/validated_rule.rb +8 -10
- data/lib/ice_cube/validations/interval.rb +19 -0
- data/lib/ice_cube/version.rb +1 -1
- data/spec/manual_regression.rb +50 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1cd6fca3c4607f135ad7b4628cc08c627cb437c9
|
4
|
+
data.tar.gz: 5018a7cf1feb4910571ac5695dcb3b051cad71d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c5446069c5e5c45819e7247114661aec92cdb0dff6a5dd2a8259aa12f7423df9bdc9dae671d9fad21180d478528ce08a846762742154f334f8b2791af34d85b
|
7
|
+
data.tar.gz: 7bbb442e21950216fb329699446ab0466848c97e50d4765623a5888d6c66f5e601d6166932df62d55e4cfe14c27cef759fafa835f7761ba31f82bb6b16011327
|
data/lib/ice_cube.rb
CHANGED
@@ -83,7 +83,7 @@ module IceCube
|
|
83
83
|
# Retain backwards compatibility for schedules exported from older versions
|
84
84
|
# This represents the version number, 11 = 0.11, 1.0 will be 100
|
85
85
|
def self.compatibility
|
86
|
-
@compatibility ||=
|
86
|
+
@compatibility ||= IceCube::VERSION.scan(/\d+/)[0..1].join.to_i
|
87
87
|
end
|
88
88
|
|
89
89
|
def self.compatibility=(version)
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module IceCube
|
2
|
+
class Enumerator < ::Enumerator
|
3
|
+
|
4
|
+
def initialize(schedule, opening_time, closing_time)
|
5
|
+
@schedule = schedule
|
6
|
+
@opening_time = TimeUtil.ensure_time(opening_time)
|
7
|
+
@closing_time = TimeUtil.ensure_time(closing_time)
|
8
|
+
align_opening_time
|
9
|
+
@cursor = @opening_time
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
return to_enum unless block_given?
|
14
|
+
while res = self.next && @closing_time.nil? || res <= @closing_time
|
15
|
+
yield Occurrence.new(res, res + schedule.duration)
|
16
|
+
end
|
17
|
+
raise StopIteration
|
18
|
+
end
|
19
|
+
|
20
|
+
def next
|
21
|
+
t1 = full_required? ? schedule.start_time : opening_time
|
22
|
+
Enumerator.new do |yielder|
|
23
|
+
loop do
|
24
|
+
t1.tap { |t| puts "LDA #{t}" + " #{File.basename(__FILE__)}:#{__LINE__}" }
|
25
|
+
break unless (t0 = next_time(t1, closing_time).tap { |t| puts "LDB #{t}" + " #{File.basename(__FILE__)}:#{__LINE__}" })
|
26
|
+
break if closing_time && t0 > closing_time
|
27
|
+
yielder << (block_given? ? block.call(t0) : t0) if t0 >= opening_time
|
28
|
+
break unless (t1 = next_time(t0 + 1, closing_time))
|
29
|
+
break if closing_time && t1 > closing_time
|
30
|
+
if TimeUtil.same_clock?(t0, t1) && recurrence_rules.any?(&:dst_adjust?)
|
31
|
+
wind_back_dst
|
32
|
+
next (t1 += 1)
|
33
|
+
end
|
34
|
+
yielder << (block_given? ? block.call(t1) : t1) if t1 >= opening_time
|
35
|
+
next (t1 += 1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def align_start_time
|
43
|
+
if @opening_time <= schedule.start_time || full_required?
|
44
|
+
@opening_time = schedule.start_time
|
45
|
+
else
|
46
|
+
@opening_time += @schedule.start_time.subsec - @opening_time.subsec rescue 0
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return a boolean indicating if any rule needs to be run from the start of time
|
51
|
+
def full_required?
|
52
|
+
recurrence_rules.any?(&:full_required?) ||
|
53
|
+
exception_rules.any?(&:full_required?)
|
54
|
+
end
|
55
|
+
|
56
|
+
def exception_rules
|
57
|
+
schedule.instance_variable_get(:@all_exception_rules)
|
58
|
+
end
|
59
|
+
|
60
|
+
def recurrence_rules
|
61
|
+
@recurrence_rules ||= if recurrence_rules.empty?
|
62
|
+
[SingleOccurrenceRule.new(schedule.start_time)].concat schedule.instance_variable_get(:@all_recurrence_rules)
|
63
|
+
else
|
64
|
+
schedule.instance_variable_get(:@all_recurrence_rules)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module IceCube
|
2
|
+
class HashInput
|
3
|
+
|
4
|
+
class Mash
|
5
|
+
def initialize(hash)
|
6
|
+
@hash = hash
|
7
|
+
end
|
8
|
+
|
9
|
+
# Fetch values indifferently by symbol or string key without symbolizing
|
10
|
+
# arbitrary string input
|
11
|
+
#
|
12
|
+
def [](key)
|
13
|
+
@hash.fetch(key) do |key|
|
14
|
+
str_key = key.to_s
|
15
|
+
@hash.each_pair.detect do |sym_key, value|
|
16
|
+
return value if sym_key.to_s == str_key
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(hash)
|
23
|
+
@input = Mash.new(hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](key)
|
27
|
+
@input[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_rule
|
31
|
+
return nil unless rule_class
|
32
|
+
rule = rule_class.new(interval, week_start)
|
33
|
+
rule.until(limit_time) if limit_time
|
34
|
+
rule.count(limit_count) if limit_count
|
35
|
+
validations.each do |validation, args|
|
36
|
+
rule.send(validation, *args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def rule_class
|
41
|
+
return @rule_class if @rule_class
|
42
|
+
match = @input[:rule_type].match(/::(\w+Rule)$/)
|
43
|
+
@rule_class = IceCube.const_get(match[1]) if match
|
44
|
+
end
|
45
|
+
|
46
|
+
def interval
|
47
|
+
@input[:interval] || 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def week_start
|
51
|
+
@input[:week_start] || :sunday
|
52
|
+
end
|
53
|
+
|
54
|
+
def limit_time
|
55
|
+
@limit_time ||= TimeUtil.deserialize_time(@input[:until])
|
56
|
+
end
|
57
|
+
|
58
|
+
def limit_count
|
59
|
+
@input[:count]
|
60
|
+
end
|
61
|
+
|
62
|
+
def validations
|
63
|
+
input_validations = Mash.new(@input[:validations] || {})
|
64
|
+
ValidatedRule::VALIDATION_ORDER.each_with_object({}) do |key, output_validations|
|
65
|
+
args = input_validations[key]
|
66
|
+
output_validations[key] = Array(args) if args
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module IceCube
|
2
|
+
class TimeStep
|
3
|
+
SECS = 1
|
4
|
+
MINS = 60
|
5
|
+
HOURS = MINS * 60
|
6
|
+
DAYS = HOURS * 24
|
7
|
+
WEEKS = DAYS * 7
|
8
|
+
MONTHS = {
|
9
|
+
1 => [ 28, 29, 30, 31].map { |m| m * DAYS },
|
10
|
+
2 => [ 59, 60, 61, 62].map { |m| m * DAYS },
|
11
|
+
3 => [ 89, 90, 91, 92].map { |m| m * DAYS },
|
12
|
+
4 => [120, 121, 122, 123].map { |m| m * DAYS },
|
13
|
+
5 => [150, 151, 152, 153].map { |m| m * DAYS },
|
14
|
+
6 => [181, 182, 183, 184].map { |m| m * DAYS },
|
15
|
+
7 => [212, 213, 214, 215].map { |m| m * DAYS },
|
16
|
+
8 => [242, 243, 244, 245].map { |m| m * DAYS },
|
17
|
+
9 => [273, 274, 275, 276].map { |m| m * DAYS },
|
18
|
+
10 => [303, 304, 305, 306].map { |m| m * DAYS },
|
19
|
+
11 => [334, 335, 336, 337].map { |m| m * DAYS },
|
20
|
+
12 => [365, 366] .map { |m| m * DAYS }
|
21
|
+
}
|
22
|
+
YEARS = [365, 366]
|
23
|
+
|
24
|
+
def next(base, validations)
|
25
|
+
end
|
26
|
+
|
27
|
+
def prev(base, validations)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/ice_cube/time_util.rb
CHANGED
@@ -126,7 +126,7 @@ module IceCube
|
|
126
126
|
# Convert a symbol to a numeric month
|
127
127
|
def self.sym_to_month(sym)
|
128
128
|
MONTHS.fetch(sym) do |k|
|
129
|
-
|
129
|
+
MONTHS.values.detect { |i| i.to_s == k.to_s } or
|
130
130
|
raise ArgumentError, "Expecting Fixnum or Symbol value for month. " \
|
131
131
|
"No such month: #{k.inspect}"
|
132
132
|
end
|
@@ -136,7 +136,7 @@ module IceCube
|
|
136
136
|
# Convert a symbol to a wday number
|
137
137
|
def self.sym_to_wday(sym)
|
138
138
|
DAYS.fetch(sym) do |k|
|
139
|
-
|
139
|
+
DAYS.values.detect { |i| i.to_s == k.to_s } or
|
140
140
|
raise ArgumentError, "Expecting Fixnum or Symbol value for weekday. " \
|
141
141
|
"No such weekday: #{k.inspect}"
|
142
142
|
end
|
@@ -140,21 +140,19 @@ module IceCube
|
|
140
140
|
true
|
141
141
|
end
|
142
142
|
|
143
|
+
# Returns true if all validations for the current rule match
|
144
|
+
# otherwise false and shifts to the first (largest) unmatched offset
|
145
|
+
#
|
143
146
|
def validation_accepts_or_updates_time?(validations_for_type)
|
144
|
-
res =
|
145
|
-
|
146
|
-
|
147
|
-
|
147
|
+
res = validations_for_type.each_with_object([]) do |validation, offsets|
|
148
|
+
r = validation.validate(@time, @schedule)
|
149
|
+
return true if r.nil? || r == 0
|
150
|
+
offsets << r
|
151
|
+
end
|
148
152
|
shift_time_by_validation(res, validations_for_type.first)
|
149
153
|
false
|
150
154
|
end
|
151
155
|
|
152
|
-
def validated_results(validations_for_type)
|
153
|
-
validations_for_type.map do |validation|
|
154
|
-
validation.validate(@time, @schedule)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
156
|
def shift_time_by_validation(res, validation)
|
159
157
|
return unless (interval = res.min)
|
160
158
|
wrapper = TimeUtil::TimeWrapper.new(@time, validation.dst_adjust?)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module IceCube
|
2
|
+
class Validations::Interval
|
3
|
+
|
4
|
+
def initialize(interval)
|
5
|
+
self.interval = interval
|
6
|
+
end
|
7
|
+
|
8
|
+
def interval=(number)
|
9
|
+
i = number.to_i
|
10
|
+
raise unless i > 0
|
11
|
+
@interval = i
|
12
|
+
rescue
|
13
|
+
raise ArgumentError.new "#{number.inspect} is not a valid input for interval, expecting positive integer"
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :interval
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/ice_cube/version.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rbkit'
|
2
|
+
Rbkit.start_profiling
|
3
|
+
require 'ice_cube'
|
4
|
+
|
5
|
+
module Kwip
|
6
|
+
def self.womp
|
7
|
+
threads = []
|
8
|
+
start = Time.new(2104,1,1)
|
9
|
+
daily = IceCube::Rule.daily.hour_of_day(6, 12, 18, 23)
|
10
|
+
|
11
|
+
# ObjectSpace.dump_all(output: File.open('heap1.json','w'))
|
12
|
+
3.times do
|
13
|
+
threads << Thread.new do
|
14
|
+
schedule = IceCube::Schedule.new(start)
|
15
|
+
schedule.add_recurrence_rule(daily)
|
16
|
+
schedule.next_occurrence
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
threads.each &:join
|
21
|
+
threads.clear
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# GC::Tracer.start_logging('gc.log') do
|
27
|
+
# GC.disable
|
28
|
+
10000.times do
|
29
|
+
Kwip.womp
|
30
|
+
Kwip.womp
|
31
|
+
Kwip.womp
|
32
|
+
end
|
33
|
+
# GC.enable
|
34
|
+
# GC.start
|
35
|
+
|
36
|
+
# str = 'asdf'
|
37
|
+
# str = nil
|
38
|
+
# GC.start
|
39
|
+
# end
|
40
|
+
|
41
|
+
# ObjectSpace.each_object do |o|
|
42
|
+
# if o.is_a?(IceCube::Occurrence) || o.is_a?(IceCube::Schedule) || o.is_a?(IceCube::Rule)
|
43
|
+
# puts "#{o.object_id} => #{o.class} (#{ObjectSpace.memsize_of(o)})"
|
44
|
+
# # puts ObjectSpace.allocation_sourcefile(o), #=> "example.rb"
|
45
|
+
# # ObjectSpace.allocation_sourceline(o), #=> 6
|
46
|
+
# # ObjectSpace.allocation_generation(o), #=> 1
|
47
|
+
# # ObjectSpace.allocation_class_path(o), #=> "MyApp"
|
48
|
+
# # ObjectSpace.allocation_method_id(o) #=> :perform
|
49
|
+
# end
|
50
|
+
# end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ice_cube
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.13.
|
4
|
+
version: 0.13.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Crepezzi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -95,9 +95,11 @@ files:
|
|
95
95
|
- lib/ice_cube/builders/ical_builder.rb
|
96
96
|
- lib/ice_cube/builders/string_builder.rb
|
97
97
|
- lib/ice_cube/deprecated.rb
|
98
|
+
- lib/ice_cube/enumerator.rb
|
98
99
|
- lib/ice_cube/errors/count_exceeded.rb
|
99
100
|
- lib/ice_cube/errors/until_exceeded.rb
|
100
101
|
- lib/ice_cube/flexible_hash.rb
|
102
|
+
- lib/ice_cube/hash_input.rb
|
101
103
|
- lib/ice_cube/i18n.rb
|
102
104
|
- lib/ice_cube/null_i18n.rb
|
103
105
|
- lib/ice_cube/occurrence.rb
|
@@ -114,6 +116,7 @@ files:
|
|
114
116
|
- lib/ice_cube/rules/yearly_rule.rb
|
115
117
|
- lib/ice_cube/schedule.rb
|
116
118
|
- lib/ice_cube/single_occurrence_rule.rb
|
119
|
+
- lib/ice_cube/time_step.rb
|
117
120
|
- lib/ice_cube/time_util.rb
|
118
121
|
- lib/ice_cube/validated_rule.rb
|
119
122
|
- lib/ice_cube/validations/count.rb
|
@@ -125,6 +128,7 @@ files:
|
|
125
128
|
- lib/ice_cube/validations/fixed_value.rb
|
126
129
|
- lib/ice_cube/validations/hour_of_day.rb
|
127
130
|
- lib/ice_cube/validations/hourly_interval.rb
|
131
|
+
- lib/ice_cube/validations/interval.rb
|
128
132
|
- lib/ice_cube/validations/lock.rb
|
129
133
|
- lib/ice_cube/validations/minute_of_hour.rb
|
130
134
|
- lib/ice_cube/validations/minutely_interval.rb
|
@@ -137,6 +141,7 @@ files:
|
|
137
141
|
- lib/ice_cube/validations/weekly_interval.rb
|
138
142
|
- lib/ice_cube/validations/yearly_interval.rb
|
139
143
|
- lib/ice_cube/version.rb
|
144
|
+
- spec/manual_regression.rb
|
140
145
|
- spec/spec_helper.rb
|
141
146
|
homepage: http://seejohnrun.github.com/ice_cube/
|
142
147
|
licenses:
|
@@ -158,9 +163,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
163
|
version: '0'
|
159
164
|
requirements: []
|
160
165
|
rubyforge_project: ice-cube
|
161
|
-
rubygems_version: 2.
|
166
|
+
rubygems_version: 2.2.2
|
162
167
|
signing_key:
|
163
168
|
specification_version: 4
|
164
169
|
summary: Ruby Date Recurrence Library
|
165
170
|
test_files:
|
171
|
+
- spec/manual_regression.rb
|
166
172
|
- spec/spec_helper.rb
|