ice_cube_model 0.0.1 → 0.0.2

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: cefa6dfe8e2c38fdf4d6440fc779013c3b983133
4
- data.tar.gz: e0ffa905699ef4e8de88e4859a106874864b76de
3
+ metadata.gz: 1128479e22af71166bf026bf19398f9f26de440f
4
+ data.tar.gz: dbb48be74fe828c79b005855278c7699e83f534f
5
5
  SHA512:
6
- metadata.gz: 24235214a4c1a1296c4b39f4fd331e1e214fc2ac312aab69fb9b6153977a555bf8022706729406cbff0fa35fc8de8e667f6022cca82c1c26b045669e3a0c466e
7
- data.tar.gz: a4b9fad410e469dcb850ec87953444e956b3db1f11b3335742fadd824fb6616bddd6c2b9ce816256875b5b4d4d3b98993b70c0a311f4c57e280e19c3a5b6b851
6
+ metadata.gz: ceec5f3cba596bf356dd19ce106dbd1910e24d53f1a78cb400b28160d7c680d3df28c1fae2eb32621054a282d51b97620dae13d3479832c5c2654a521ac06237
7
+ data.tar.gz: 865e4a6b94862468c5075803c120d928ef990cb8569fb676ecf2dbef7a0ecac836ad95c9f33da8ba5709e2cacb57a2d08d3c85089d75325f0467953ecbf01528
data/.gitignore CHANGED
@@ -34,3 +34,4 @@ Gemfile.lock
34
34
 
35
35
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
36
  .rvmrc
37
+ Guardfile
@@ -12,3 +12,6 @@ Style/Documentation:
12
12
 
13
13
  Metrics/LineLength:
14
14
  Enabled: false
15
+
16
+ Metrics/MethodLength:
17
+ Max: 15
data/README.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # ice_cube_model
2
- Extend any object with [ice_cube](https://github.com/seejohnrun/ice_cube) (calendar repeating event) capabilities.
2
+ Extend any "cron-expression" object with [ice_cube](https://github.com/seejohnrun/ice_cube) (calendar repeating event) capabilities.
3
3
 
4
- Add ice_cube methods to classes (e.g. active_record, active_model).
4
+ Add ice_cube methods to a class (e.g. active_record, active_model) that has cron expression fields.
5
+
6
+ ## description
7
+
8
+ **ice_cube** is a sold library for projecting and querying recurrence rules. **Cron** is _the_ standard for expressing recurrence rules. If you have a model that stores cron fields in separate attributes, then this gem will allow you to map those attributes into ice_cube and execute projection and queries against it.
9
+
10
+ The fields in the model can use standard cron expression syntax [explained here](https://en.wikipedia.org/wiki/Cron). This includes range expressions, series expressions, "last" day of month, Nth weekday of month, etc.
11
+
12
+ PLEASE NOTE:
13
+ This gem is a work-in-progress. Many features have yet to be implemented.
5
14
 
6
15
  ## installation
7
16
 
@@ -89,12 +98,28 @@ class Appointment
89
98
  end
90
99
  ```
91
100
 
101
+ ## recurrence rule examples (date)
102
+
103
+ |desc|interval|year|month|day|weekday|
104
+ |----|-------:|---:|----:|--:|------:|
105
+ |1st of every month||||1||
106
+ |1st and 15th of every month||||1,15||
107
+ |every monday|||||1|
108
+ |1st monday of every month|||||1#1|
109
+ |ever other friday|2||||5|
110
+ |every 6 months on the 5th|6|||5||
111
+ |last friday of every month|||||5L|
112
+ |last day every month||||L||
113
+
92
114
  ## notes
93
115
  - This gem is a work-in-progress.
94
116
  - `occurrences_between` is the only method currently supported.
95
117
  - Does not yet support all recurrence options. More coming.
118
+ - Does not support inheritance. with_repeat_params called on child classes will mess with parent class' mappings.
96
119
 
97
120
  ## todo
98
- - Add more examples to specs and README
99
- - Add ability to do Nth types of repeats (e.g. last friday of the month, first and third tuesday of every month). These are supported by ice_cube.
121
+ - Add support for repeat_end_date
122
+ - Add support for inheritance
123
+ - Add support for time
124
+ - Allow mapping of a single cron expression (string) field, rather than individual fields.
100
125
 
@@ -18,8 +18,7 @@ Gem::Specification.new do |s|
18
18
  ##
19
19
  # Dependencies
20
20
  #
21
- s.add_dependency 'ice_cube', '= 0.13.0'
22
- s.add_dependency 'activesupport', '>= 3.0.0'
21
+ s.add_dependency 'ice_cube_cron', '>= 0.0.2'
23
22
 
24
23
  ##
25
24
  # Development Dependencies
@@ -27,11 +26,5 @@ Gem::Specification.new do |s|
27
26
  s.add_development_dependency 'rake'
28
27
  s.add_development_dependency 'pry'
29
28
  s.add_development_dependency 'rspec'
30
- s.add_development_dependency 'simplecov'
31
29
  s.add_development_dependency 'rubocop'
32
- s.add_development_dependency 'guard'
33
- s.add_development_dependency 'guard-rspec'
34
- s.add_development_dependency 'guard-rubocop'
35
- s.add_development_dependency 'spring'
36
- s.add_development_dependency 'spring-commands-rspec'
37
30
  end
@@ -1,4 +1,5 @@
1
1
  require 'ice_cube'
2
+ require 'ice_cube_cron'
2
3
 
3
4
  require 'active_support/core_ext/date'
4
5
  require 'active_support/core_ext/integer'
@@ -5,10 +5,12 @@ module IceCubeModel
5
5
  end
6
6
 
7
7
  def events_between(start, through)
8
- params = read_cyclical_params
9
- schedule = ::IceCubeModel::Util.build_schedule(params)
10
- schedule.occurrences_between(::IceCubeModel::Util.sanitize_date_param(start), ::IceCubeModel::Util.sanitize_date_param(through)).map(&:to_date)
8
+ params = read_repeat_params
9
+ schedule = ::IceCube::Schedule.from_cron(read_repeat_parameter(:repeat_start_date), params)
10
+
11
+ schedule.occurrences_between(::IceCubeModel::Util.sanitize_date_param(start), ::IceCubeModel::Util.sanitize_date_param(through))
11
12
  end
13
+ alias_method :occurrences_between, :events_between
12
14
 
13
15
  private
14
16
 
@@ -16,14 +18,13 @@ module IceCubeModel
16
18
  send(self.class.repeat_parameter_mappings[param_name])
17
19
  end
18
20
 
19
- def read_cyclical_params
21
+ def read_repeat_params
20
22
  {
21
- :repeat_start_date => ::IceCubeModel::Util.sanitize_date_param(read_repeat_parameter(:repeat_start_date)),
22
- :repeat_interval => ::IceCubeModel::Util.sanitize_integer_param(read_repeat_parameter(:repeat_interval)),
23
- :repeat_year => ::IceCubeModel::Util.sanitize_integer_array_param(read_repeat_parameter(:repeat_year)),
24
- :repeat_month => ::IceCubeModel::Util.sanitize_integer_array_param(read_repeat_parameter(:repeat_month)),
25
- :repeat_day => ::IceCubeModel::Util.sanitize_integer_array_param(read_repeat_parameter(:repeat_day)),
26
- :repeat_weekday => ::IceCubeModel::Util.sanitize_integer_array_param(read_repeat_parameter(:repeat_weekday))
23
+ :repeat_interval => read_repeat_parameter(:repeat_interval),
24
+ :repeat_year => read_repeat_parameter(:repeat_year),
25
+ :repeat_month => read_repeat_parameter(:repeat_month),
26
+ :repeat_day => read_repeat_parameter(:repeat_day),
27
+ :repeat_weekday => read_repeat_parameter(:repeat_weekday)
27
28
  }
28
29
  end
29
30
 
@@ -1,30 +1,5 @@
1
1
  module IceCubeModel
2
2
  module Util
3
- def self.build_schedule(params)
4
- schedule = ::IceCube::Schedule.new(::IceCubeModel::Util.sanitize_date_param(params[:repeat_start_date]))
5
- schedule.add_recurrence_rule ::IceCubeModel::Util.build_cyclical_repeat_rules(params)
6
-
7
- schedule
8
- end
9
-
10
- def self.build_cyclical_repeat_rules(params)
11
- rule = ::IceCubeModel::Util.build_root_recurrence_rule(params)
12
-
13
- rule = rule.month_of_year(*params[:repeat_month]) unless params[:repeat_month].blank?
14
- rule = rule.day_of_month(*params[:repeat_day]) unless params[:repeat_day].blank?
15
- rule = rule.day(*params[:repeat_weekday]) unless params[:repeat_weekday].blank?
16
-
17
- rule
18
- end
19
-
20
- def self.build_root_recurrence_rule(params)
21
- interval = params[:repeat_interval]
22
- return ::IceCube::Rule.yearly(interval) unless params[:repeat_month].blank?
23
- return ::IceCube::Rule.weekly(interval) unless params[:repeat_weekday].blank?
24
-
25
- ::IceCube::Rule.monthly(interval)
26
- end
27
-
28
3
  def self.sanitize_date_param(date)
29
4
  date = date.to_time(:utc) if date.is_a?(::Date) && !date.is_a?(::DateTime)
30
5
  date = date.to_time.utc if date.is_a?(::DateTime)
@@ -32,19 +7,5 @@ module IceCubeModel
32
7
 
33
8
  date
34
9
  end
35
-
36
- def self.sanitize_integer_array_param(param)
37
- return nil if param.blank?
38
- return param if param.is_a?(::Array)
39
- return [param] if param.is_a?(::Integer)
40
-
41
- param.split(',').map(&:to_i)
42
- end
43
-
44
- def self.sanitize_integer_param(param)
45
- return 1 if param.blank?
46
-
47
- param.to_i
48
- end
49
10
  end
50
11
  end
@@ -1,3 +1,3 @@
1
1
  module IceCubeModel
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -0,0 +1,348 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::IceCubeModel do
4
+ class HashAttrs
5
+ def initialize(attributes = {})
6
+ @attributes = {
7
+ :repeat_start_date => nil,
8
+ :repeat_interval => nil,
9
+ :repeat_year => nil,
10
+ :repeat_month => nil,
11
+ :repeat_day => nil,
12
+ :repeat_weekday => nil,
13
+ :repeat_week => nil
14
+ }.merge(attributes)
15
+ end
16
+
17
+ def method_missing(m, *args, &_block)
18
+ if m =~ /[a-z_]+=/
19
+ attribute = m.to_s.strip.chop.to_sym
20
+ return @attributes[attribute] = args[0] if @attributes.key?(attribute)
21
+ else
22
+ return @attributes[m] if @attributes.key?(m)
23
+ end
24
+
25
+ fail ArgumentError, "Method `#{m}` doesn't exist."
26
+ end
27
+ end
28
+
29
+ class IceCubeObj < HashAttrs
30
+ include ::IceCubeModel::Base
31
+ end
32
+
33
+ let(:ice_cube_model) do
34
+ ::IceCubeObj.new(
35
+ :repeat_start_date => ::Date.new(2015, 6, 1)
36
+ )
37
+ end
38
+
39
+ context 'repeat options' do
40
+ describe 'monthly' do
41
+ before { ice_cube_model.repeat_day = '1' }
42
+
43
+ it 'for same day' do
44
+ expect(ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 1))).to eq([::Date.new(2015, 7, 1)])
45
+ end
46
+
47
+ it 'for multiple months' do
48
+ expect(ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 9, 1))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 8, 1), ::Date.new(2015, 9, 1)])
49
+ end
50
+ end
51
+
52
+ describe 'twice monthly' do
53
+ before { ice_cube_model.repeat_day = '1,15' }
54
+
55
+ it 'for one month' do
56
+ expect(ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 31))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 7, 15)])
57
+ end
58
+
59
+ it 'for two months' do
60
+ expect(ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 8, 31))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 7, 15), ::Date.new(2015, 8, 1), ::Date.new(2015, 8, 15)])
61
+ end
62
+ end
63
+
64
+ describe 'bi-monthly' do
65
+ let(:ice_cube_model) do
66
+ ::IceCubeObj.new(
67
+ :repeat_start_date => ::Date.new(2015, 5, 1),
68
+ :repeat_day => '1',
69
+ :repeat_interval => '2'
70
+ )
71
+ end
72
+
73
+ it 'for one month' do
74
+ expect(ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 31))).to eq([::Date.new(2015, 7, 1)])
75
+ end
76
+
77
+ it 'for multiple months' do
78
+ expect(ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 10, 31))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 9, 1)])
79
+ end
80
+ end
81
+
82
+ describe 'every week' do
83
+ let(:ice_cube_model) do
84
+ ::IceCubeObj.new(
85
+ :repeat_start_date => ::Date.new(2015, 7, 6),
86
+ :repeat_weekday => '1',
87
+ :repeat_day => nil
88
+ )
89
+ end
90
+
91
+ it 'for one week' do
92
+ expect(
93
+ ice_cube_model.events_between(
94
+ ::Date.new(2015, 7, 1),
95
+ ::Date.new(2015, 7, 7)
96
+ )
97
+ ).to eq([::Date.new(2015, 7, 6)])
98
+ end
99
+
100
+ it 'for one month' do
101
+ expect(
102
+ ice_cube_model.events_between(
103
+ ::Date.new(2015, 7, 1),
104
+ ::Date.new(2015, 8, 31)
105
+ )
106
+ ).to eq(
107
+ [
108
+ ::Date.new(2015, 7, 6),
109
+ ::Date.new(2015, 7, 13),
110
+ ::Date.new(2015, 7, 20),
111
+ ::Date.new(2015, 7, 27),
112
+ ::Date.new(2015, 8, 3),
113
+ ::Date.new(2015, 8, 10),
114
+ ::Date.new(2015, 8, 17),
115
+ ::Date.new(2015, 8, 24),
116
+ ::Date.new(2015, 8, 31)
117
+ ]
118
+ )
119
+ end
120
+ end
121
+
122
+ describe 'bi-weekly' do
123
+ let(:ice_cube_model) do
124
+ ::IceCubeObj.new(
125
+ :repeat_start_date => ::Date.new(2015, 7, 6),
126
+ :repeat_weekday => '1',
127
+ :repeat_day => nil,
128
+ :repeat_interval => '2'
129
+ )
130
+ end
131
+
132
+ it 'for one week' do
133
+ expect(
134
+ ice_cube_model.events_between(
135
+ ::Date.new(2015, 7, 1),
136
+ ::Date.new(2015, 7, 7)
137
+ )
138
+ ).to eq([::Date.new(2015, 7, 6)])
139
+ end
140
+
141
+ it 'for two months' do
142
+ expect(
143
+ ice_cube_model.events_between(
144
+ ::Date.new(2015, 7, 1),
145
+ ::Date.new(2015, 8, 31)
146
+ )
147
+ ).to eq(
148
+ [
149
+ ::Date.new(2015, 7, 6),
150
+ # ::Date.new(2015, 7, 13),
151
+ ::Date.new(2015, 7, 20),
152
+ # ::Date.new(2015, 7, 27),
153
+ ::Date.new(2015, 8, 3),
154
+ # ::Date.new(2015, 8, 10),
155
+ ::Date.new(2015, 8, 17),
156
+ # ::Date.new(2015, 8, 24),
157
+ ::Date.new(2015, 8, 31)
158
+ ]
159
+ )
160
+ end
161
+ end
162
+
163
+ describe 'annually' do
164
+ let(:ice_cube_model) do
165
+ ::IceCubeObj.new(
166
+ :repeat_start_date => ::Date.new(2015, 1, 1),
167
+ :repeat_month => 2,
168
+ :repeat_day => 1
169
+ )
170
+ end
171
+
172
+ it 'for one year' do
173
+ expect(ice_cube_model.events_between(::Date.new(2015, 1, 1), ::Date.new(2015, 12, 31))).to eq([::Date.new(2015, 2, 1)])
174
+ end
175
+
176
+ it 'for two years' do
177
+ expect(ice_cube_model.events_between(::Date.new(2015, 1, 1), ::Date.new(2016, 12, 31))).to eq([::Date.new(2015, 2, 1), ::Date.new(2016, 2, 1)])
178
+ end
179
+ end
180
+
181
+ describe 'bi-annually' do
182
+ let(:ice_cube_model) do
183
+ ::IceCubeObj.new(
184
+ :repeat_start_date => ::Date.new(2015, 1, 1),
185
+ :repeat_interval => 2,
186
+ :repeat_month => 2,
187
+ :repeat_day => 1
188
+ )
189
+ end
190
+
191
+ it 'for two years' do
192
+ expect(ice_cube_model.events_between(::Date.new(2015, 1, 1), ::Date.new(2016, 12, 31))).to eq([::Date.new(2015, 2, 1)])
193
+ end
194
+ end
195
+
196
+ describe 'last weekday of month' do
197
+ context '31 day month' do
198
+ let(:ice_cube_model) do
199
+ ::IceCubeObj.new(
200
+ :repeat_start_date => ::Date.new(2015, 1, 1),
201
+ :repeat_weekday => '5L'
202
+ )
203
+ end
204
+
205
+ it 'for one month' do
206
+ expect(ice_cube_model.events_between(::Date.new(2015, 12, 1), ::Date.new(2015, 12, 31))).to eq([::Date.new(2015, 12, 25)])
207
+ end
208
+ end
209
+
210
+ context '29 day month' do
211
+ let(:ice_cube_model) do
212
+ ::IceCubeObj.new(
213
+ :repeat_start_date => ::Date.new(2015, 1, 1),
214
+ :repeat_weekday => '3L'
215
+ )
216
+ end
217
+
218
+ it 'for one month' do
219
+ expect(ice_cube_model.events_between(::Date.new(2016, 2, 1), ::Date.new(2016, 2, 29))).to eq([::Date.new(2016, 2, 24)])
220
+ end
221
+ end
222
+ end
223
+
224
+ describe 'last day of month' do
225
+ context '31 day month' do
226
+ let(:ice_cube_model) do
227
+ ::IceCubeObj.new(
228
+ :repeat_start_date => ::Date.new(2015, 1, 1),
229
+ :repeat_day => 'L'
230
+ )
231
+ end
232
+
233
+ it 'for one multiple months' do
234
+ expect(ice_cube_model.events_between(::Date.new(2015, 12, 1), ::Date.new(2016, 3, 1))).to eq([::Date.new(2015, 12, 31), ::Date.new(2016, 1, 31), ::Date.new(2016, 2, 29)])
235
+ end
236
+ end
237
+ end
238
+
239
+ describe 'Nth day of week of month' do
240
+ let(:ice_cube_model) do
241
+ ::IceCubeObj.new(
242
+ :repeat_start_date => ::Date.new(2015, 1, 1),
243
+ :repeat_weekday => '1#2'
244
+ )
245
+ end
246
+
247
+ it 'for one month' do
248
+ expect(ice_cube_model.events_between(::Date.new(2016, 2, 1), ::Date.new(2016, 2, 29))).to eq([::Date.new(2016, 2, 8)])
249
+ end
250
+
251
+ it 'for mutiple months' do
252
+ expect(ice_cube_model.events_between(::Date.new(2016, 2, 1), ::Date.new(2016, 4, 30))).to eq([::Date.new(2016, 2, 8), ::Date.new(2016, 3, 14), ::Date.new(2016, 4, 11)])
253
+ end
254
+ end
255
+ end
256
+
257
+ context 'input types' do
258
+ let(:ice_cube_model) do
259
+ ::IceCubeObj.new(
260
+ :repeat_start_date => ::DateTime.new(2015, 5, 1),
261
+ :repeat_day => '1',
262
+ :repeat_interval => '2'
263
+ )
264
+ end
265
+
266
+ it 'handles ::DateTime as input' do
267
+ expect(ice_cube_model.events_between(::DateTime.new(2015, 7, 1), ::DateTime.new(2015, 7, 31))).to eq([::DateTime.new(2015, 7, 1)])
268
+ end
269
+
270
+ it 'handles integer (epoch) as input' do
271
+ ice_cube_model.repeat_start_date = 1_430_438_400 # Fri, 01 May 2015 00:00:00 GMT
272
+ expect(ice_cube_model.events_between(::DateTime.new(2015, 7, 1), ::DateTime.new(2015, 7, 31))).to eq([::DateTime.new(2015, 7, 1)])
273
+ end
274
+ end
275
+
276
+ context '::IceCubeModel::Base' do
277
+ describe '#events_between' do
278
+ it 'should emit [::Time]' do
279
+ results = ice_cube_model.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 31))
280
+ expect(results).to eq([::Date.new(2015, 7, 1)])
281
+ expect(results[0]).to be_a(::Time)
282
+ end
283
+ end
284
+ end
285
+
286
+ context '::ClassMethods' do
287
+ describe '#with_repeat_param' do
288
+ class IceCubeObjWithParameterMappings < HashAttrs
289
+ include ::IceCubeModel::Base
290
+
291
+ with_repeat_param(:repeat_start_date, :start_date) # remap attribute to another
292
+ with_repeat_param(:repeat_interval, :interval) # remap attribute to a method
293
+ with_repeat_param(:repeat_day, -> { 1 }) # map parameter to lambda
294
+
295
+ def initialize(options = {})
296
+ super(
297
+ {
298
+ :start_date => nil
299
+ }.merge(options)
300
+ )
301
+ end
302
+
303
+ def interval
304
+ 1
305
+ end
306
+ end
307
+
308
+ let(:ice_cube_model) do
309
+ ::IceCubeObjWithParameterMappings.new(
310
+ :start_date => ::Date.new(2015, 1, 1),
311
+ :repeat_month => 2
312
+ )
313
+ end
314
+
315
+ it 'should use class mappings' do
316
+ expect(ice_cube_model.events_between(::Date.new(2015, 1, 1), ::Date.new(2015, 12, 31))).to eq([::Date.new(2015, 2, 1)])
317
+ end
318
+
319
+ class IceCubeObjWithParameterMappingsChild < IceCubeObjWithParameterMappings
320
+ # Adding these currently mess up parent class mappings
321
+ # with_repeat_param(:repeat_start_date, :starting) # remap attribute to another
322
+ # with_repeat_param(:repeat_interval, :interval) # remap attribute to a method
323
+
324
+ def initialize(options = {})
325
+ super(
326
+ {
327
+ :starting => nil
328
+ }.merge(options)
329
+ )
330
+ end
331
+
332
+ def interval
333
+ 2
334
+ end
335
+ end
336
+
337
+ it 'should support inheritance' do
338
+ ice_cube_model = ::IceCubeObjWithParameterMappingsChild.new(
339
+ :starting => ::Date.new(2015, 1, 1),
340
+ :repeat_day => 2
341
+ )
342
+
343
+ skip 'Not supported yet'
344
+ expect(ice_cube_model.events_between(::Date.new(2015, 1, 1), ::Date.new(2015, 4, 30))).to eq([::Date.new(2015, 1, 2), ::Date.new(2015, 3, 2)])
345
+ end
346
+ end
347
+ end
348
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe ::IceCubeModel::Util do
4
+ describe '#sanitize_date_param' do
5
+ it 'should handle epoch time' do
6
+ expect(described_class.sanitize_date_param(1_430_438_400)).to eq(DateTime.new(2015, 5, 1, 0, 0, 0))
7
+ end
8
+
9
+ it 'should handle date' do
10
+ expect(described_class.sanitize_date_param(Date.new(2015, 5, 1))).to eq(DateTime.new(2015, 5, 1, 0, 0, 0))
11
+ end
12
+
13
+ it 'should handle datetime' do
14
+ expect(described_class.sanitize_date_param(DateTime.new(2015, 5, 1, 0, 0, 0))).to eq(DateTime.new(2015, 5, 1, 0, 0, 0))
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,43 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ice_cube_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Nichols
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-13 00:00:00.000000000 Z
11
+ date: 2015-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ice_cube
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '='
18
- - !ruby/object:Gem::Version
19
- version: 0.13.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - '='
25
- - !ruby/object:Gem::Version
26
- version: 0.13.0
27
- - !ruby/object:Gem::Dependency
28
- name: activesupport
14
+ name: ice_cube_cron
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - ">="
32
18
  - !ruby/object:Gem::Version
33
- version: 3.0.0
19
+ version: 0.0.2
34
20
  type: :runtime
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
24
  - - ">="
39
25
  - !ruby/object:Gem::Version
40
- version: 3.0.0
26
+ version: 0.0.2
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +66,6 @@ dependencies:
80
66
  - - ">="
81
67
  - !ruby/object:Gem::Version
82
68
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: simplecov
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
69
  - !ruby/object:Gem::Dependency
98
70
  name: rubocop
99
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,76 +80,6 @@ dependencies:
108
80
  - - ">="
109
81
  - !ruby/object:Gem::Version
110
82
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: guard
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: guard-rspec
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: guard-rubocop
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: spring
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
- - !ruby/object:Gem::Dependency
168
- name: spring-commands-rspec
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: '0'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ">="
179
- - !ruby/object:Gem::Version
180
- version: '0'
181
83
  description: Add ice_cube methods to classes (e.g. active_record, active_model).
182
84
  email:
183
85
  - matt@nichols.name
@@ -196,8 +98,8 @@ files:
196
98
  - lib/ice_cube_model/base.rb
197
99
  - lib/ice_cube_model/util.rb
198
100
  - lib/ice_cube_model/version.rb
199
- - spec/lib/ice_cube_model_spec.rb
200
- - spec/lib/util_spec.rb
101
+ - spec/lib/ice_cube_model/base_spec.rb
102
+ - spec/lib/ice_cube_model/util_spec.rb
201
103
  - spec/spec_helper.rb
202
104
  homepage: https://github.com/mattnichols/ice_cube_model
203
105
  licenses: []
@@ -223,6 +125,6 @@ signing_key:
223
125
  specification_version: 4
224
126
  summary: Extend any class with ice_cube (calendar repeating events) capabilities.
225
127
  test_files:
226
- - spec/lib/ice_cube_model_spec.rb
227
- - spec/lib/util_spec.rb
128
+ - spec/lib/ice_cube_model/base_spec.rb
129
+ - spec/lib/ice_cube_model/util_spec.rb
228
130
  - spec/spec_helper.rb
@@ -1,292 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ::IceCubeModel do
4
- class IceCubeObj
5
- include ::IceCubeModel::Base
6
-
7
- def initialize(options = {})
8
- @options = {
9
- :repeat_start_date => nil,
10
- :repeat_interval => nil,
11
- :repeat_year => nil,
12
- :repeat_month => nil,
13
- :repeat_day => nil,
14
- :repeat_weekday => nil,
15
- :repeat_week => nil
16
- }.merge(options)
17
- end
18
-
19
- def method_missing(m, *_args, &_block)
20
- return @options[m] if @options.key?(m)
21
- fail ArgumentError, "Method `#{m}` doesn't exist."
22
- end
23
- end
24
-
25
- describe 'monthly' do
26
- let(:projector) do
27
- ::IceCubeObj.new(
28
- :repeat_start_date => ::Date.new(2015, 6, 1),
29
- :repeat_day => '1'
30
- )
31
- end
32
-
33
- it 'should emit [::Date]' do
34
- results = projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 31))
35
- expect(results).to eq([::Date.new(2015, 7, 1)])
36
- expect(results[0]).to be_a(::Date)
37
- end
38
-
39
- it 'should render same day' do
40
- expect(projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 1))).to eq([::Date.new(2015, 7, 1)])
41
- end
42
-
43
- it 'should render across multiple months' do
44
- expect(projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 9, 1))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 8, 1), ::Date.new(2015, 9, 1)])
45
- end
46
- end
47
-
48
- describe 'twice monthly' do
49
- let(:projector) do
50
- ::IceCubeObj.new(
51
- :repeat_start_date => ::Date.new(2015, 6, 1),
52
- :repeat_day => '1,15'
53
- )
54
- end
55
-
56
- it 'should render one month' do
57
- expect(projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 31))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 7, 15)])
58
- end
59
-
60
- it 'should render one month' do
61
- expect(projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 8, 31))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 7, 15), ::Date.new(2015, 8, 1), ::Date.new(2015, 8, 15)])
62
- end
63
- end
64
-
65
- describe 'bi-monthly' do
66
- let(:projector) do
67
- ::IceCubeObj.new(
68
- :repeat_start_date => ::Date.new(2015, 5, 1),
69
- :repeat_day => '1',
70
- :repeat_interval => '2'
71
- )
72
- end
73
-
74
- it 'should render one month' do
75
- expect(projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 7, 31))).to eq([::Date.new(2015, 7, 1)])
76
- end
77
-
78
- it 'should render multiple months' do
79
- expect(projector.events_between(::Date.new(2015, 7, 1), ::Date.new(2015, 10, 31))).to eq([::Date.new(2015, 7, 1), ::Date.new(2015, 9, 1)])
80
- end
81
- end
82
-
83
- describe 'every week' do
84
- let(:projector) do
85
- ::IceCubeObj.new(
86
- :repeat_start_date => ::Date.new(2015, 7, 6),
87
- :repeat_weekday => '1',
88
- :repeat_day => nil
89
- )
90
- end
91
-
92
- it 'should render one week' do
93
- expect(
94
- projector.events_between(
95
- ::Date.new(2015, 7, 1),
96
- ::Date.new(2015, 7, 7)
97
- )
98
- ).to eq([::Date.new(2015, 7, 6)])
99
- end
100
-
101
- it 'should render one month' do
102
- expect(
103
- projector.events_between(
104
- ::Date.new(2015, 7, 1),
105
- ::Date.new(2015, 8, 31)
106
- )
107
- ).to eq(
108
- [
109
- ::Date.new(2015, 7, 6),
110
- ::Date.new(2015, 7, 13),
111
- ::Date.new(2015, 7, 20),
112
- ::Date.new(2015, 7, 27),
113
- ::Date.new(2015, 8, 3),
114
- ::Date.new(2015, 8, 10),
115
- ::Date.new(2015, 8, 17),
116
- ::Date.new(2015, 8, 24),
117
- ::Date.new(2015, 8, 31)
118
- ]
119
- )
120
- end
121
- end
122
-
123
- describe 'every two weeks' do
124
- let(:projector) do
125
- ::IceCubeObj.new(
126
- :repeat_start_date => ::Date.new(2015, 7, 6),
127
- :repeat_weekday => '1',
128
- :repeat_day => nil,
129
- :repeat_interval => '2'
130
- )
131
- end
132
-
133
- it 'should render one week' do
134
- expect(
135
- projector.events_between(
136
- ::Date.new(2015, 7, 1),
137
- ::Date.new(2015, 7, 7)
138
- )
139
- ).to eq([::Date.new(2015, 7, 6)])
140
- end
141
-
142
- it 'should render one month' do
143
- expect(
144
- projector.events_between(
145
- ::Date.new(2015, 7, 1),
146
- ::Date.new(2015, 8, 31)
147
- )
148
- ).to eq(
149
- [
150
- ::Date.new(2015, 7, 6),
151
- # ::Date.new(2015, 7, 13),
152
- ::Date.new(2015, 7, 20),
153
- # ::Date.new(2015, 7, 27),
154
- ::Date.new(2015, 8, 3),
155
- # ::Date.new(2015, 8, 10),
156
- ::Date.new(2015, 8, 17),
157
- # ::Date.new(2015, 8, 24),
158
- ::Date.new(2015, 8, 31)
159
- ]
160
- )
161
- end
162
- end
163
-
164
- describe 'annually' do
165
- let(:projector) do
166
- ::IceCubeObj.new(
167
- :repeat_start_date => ::Date.new(2015, 1, 1),
168
- :repeat_month => 2,
169
- :repeat_day => 1
170
- )
171
- end
172
-
173
- it 'should render one year' do
174
- expect(projector.events_between(::Date.new(2015, 1, 1), ::Date.new(2015, 12, 31))).to eq([::Date.new(2015, 2, 1)])
175
- end
176
- end
177
-
178
- describe 'bi-annually' do
179
- let(:projector) do
180
- ::IceCubeObj.new(
181
- :repeat_start_date => ::Date.new(2015, 1, 1),
182
- :repeat_interval => 2,
183
- :repeat_month => 2,
184
- :repeat_day => 1
185
- )
186
- end
187
-
188
- it 'should render two year' do
189
- expect(projector.events_between(::Date.new(2015, 1, 1), ::Date.new(2016, 12, 31))).to eq([::Date.new(2015, 2, 1)])
190
- end
191
- end
192
-
193
- describe 'last weekday of month' do
194
- context '31 day month' do
195
- let(:projector) do
196
- ::IceCubeObj.new(
197
- :repeat_start_date => ::Date.new(2015, 1, 1),
198
- :repeat_day => '31, 30, 29, 28, 27, 26, 25',
199
- :repeat_weekday => 5
200
- )
201
- end
202
-
203
- it 'should render' do
204
- expect(projector.events_between(::Date.new(2015, 12, 1), ::Date.new(2015, 12, 31))).to eq([::Date.new(2015, 12, 25)])
205
- end
206
- end
207
-
208
- context '31 day month' do
209
- let(:projector) do
210
- ::IceCubeObj.new(
211
- :repeat_start_date => ::Date.new(2015, 1, 1),
212
- :repeat_day => '31, 30, 29, 28, 27, 26, 25',
213
- :repeat_weekday => 1
214
- )
215
- end
216
-
217
- it 'should render' do
218
- expect(projector.events_between(::Date.new(2016, 2, 1), ::Date.new(2016, 2, 29))).to eq([::Date.new(2016, 2, 29)])
219
- end
220
- end
221
- end
222
-
223
- describe 'handles ::DateTime as input' do
224
- let(:projector) do
225
- ::IceCubeObj.new(
226
- :repeat_start_date => ::DateTime.new(2015, 5, 1),
227
- :repeat_day => '1',
228
- :repeat_interval => '2'
229
- )
230
- end
231
-
232
- it 'should render one month' do
233
- expect(projector.events_between(::DateTime.new(2015, 7, 1), ::DateTime.new(2015, 7, 31))).to eq([::DateTime.new(2015, 7, 1)])
234
- end
235
- end
236
-
237
- describe 'handles integer (epoch) as input' do
238
- let(:projector) do
239
- ::IceCubeObj.new(
240
- :repeat_start_date => 1_430_438_400, # Fri, 01 May 2015 00:00:00 GMT
241
- :repeat_day => '1',
242
- :repeat_interval => '2'
243
- )
244
- end
245
-
246
- it 'should render one month' do
247
- expect(projector.events_between(::DateTime.new(2015, 7, 1), ::DateTime.new(2015, 7, 31))).to eq([::DateTime.new(2015, 7, 1)])
248
- end
249
- end
250
-
251
- describe '::ClassMethods' do
252
- class IceCubeObjWithParameterMappings
253
- include ::IceCubeModel::Base
254
-
255
- with_repeat_param(:repeat_start_date, :start_date) # remap parameter to another
256
- with_repeat_param(:repeat_interval, :interval) # remap parameter to a method
257
- with_repeat_param(:repeat_day, -> { 1 }) # map parameter to lambda
258
-
259
- def initialize(options = {})
260
- @options = {
261
- :start_date => nil,
262
- :repeat_interval => nil,
263
- :repeat_year => nil,
264
- :repeat_month => nil,
265
- :repeat_day => nil,
266
- :repeat_weekday => nil,
267
- :repeat_week => nil
268
- }.merge(options)
269
- end
270
-
271
- def interval
272
- 1
273
- end
274
-
275
- def method_missing(m, *_args, &_block)
276
- return @options[m] if @options.key?(m)
277
- fail ArgumentError, "Method `#{m}` doesn't exist."
278
- end
279
- end
280
-
281
- let(:projector) do
282
- ::IceCubeObjWithParameterMappings.new(
283
- :start_date => ::Date.new(2015, 1, 1),
284
- :repeat_month => 2
285
- )
286
- end
287
-
288
- it 'should render correctly' do
289
- expect(projector.events_between(::Date.new(2015, 1, 1), ::Date.new(2015, 12, 31))).to eq([::Date.new(2015, 2, 1)])
290
- end
291
- end
292
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ::IceCubeModel::Util do
4
- describe '#sanitize_date_param' do
5
- it 'should handle epoch time' do
6
- expect(::IceCubeModel::Util.sanitize_date_param(1_430_438_400)).to eq(DateTime.new(2015, 5, 1, 0, 0, 0))
7
- end
8
-
9
- it 'should handle date' do
10
- expect(::IceCubeModel::Util.sanitize_date_param(Date.new(2015, 5, 1))).to eq(DateTime.new(2015, 5, 1, 0, 0, 0))
11
- end
12
-
13
- it 'should handle datetime' do
14
- expect(::IceCubeModel::Util.sanitize_date_param(DateTime.new(2015, 5, 1, 0, 0, 0))).to eq(DateTime.new(2015, 5, 1, 0, 0, 0))
15
- end
16
- end
17
- end