ice_cube_model 0.0.1 → 0.0.2

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: 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