ta_by_star 4.0.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +59 -0
  3. data/Gemfile +18 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +616 -0
  6. data/Rakefile +18 -0
  7. data/UPGRADING +4 -0
  8. data/by_star.gemspec +34 -0
  9. data/cleaner.rb +25 -0
  10. data/lib/by_star/base.rb +76 -0
  11. data/lib/by_star/between.rb +190 -0
  12. data/lib/by_star/directional.rb +35 -0
  13. data/lib/by_star/kernel/date.rb +41 -0
  14. data/lib/by_star/kernel/in_time_zone.rb +20 -0
  15. data/lib/by_star/kernel/time.rb +41 -0
  16. data/lib/by_star/normalization.rb +156 -0
  17. data/lib/by_star/orm/active_record/by_star.rb +75 -0
  18. data/lib/by_star/orm/mongoid/by_star.rb +90 -0
  19. data/lib/by_star/orm/mongoid/reorder.rb +23 -0
  20. data/lib/by_star/version.rb +3 -0
  21. data/lib/by_star.rb +18 -0
  22. data/spec/database.yml +15 -0
  23. data/spec/fixtures/active_record/models.rb +12 -0
  24. data/spec/fixtures/active_record/schema.rb +19 -0
  25. data/spec/fixtures/mongoid/models.rb +31 -0
  26. data/spec/fixtures/shared/seeds.rb +36 -0
  27. data/spec/gemfiles/Gemfile.rails +5 -0
  28. data/spec/gemfiles/Gemfile.rails32 +7 -0
  29. data/spec/gemfiles/Gemfile.rails40 +7 -0
  30. data/spec/gemfiles/Gemfile.rails41 +7 -0
  31. data/spec/gemfiles/Gemfile.rails42 +7 -0
  32. data/spec/gemfiles/Gemfile.rails50 +7 -0
  33. data/spec/gemfiles/Gemfile.rails51 +7 -0
  34. data/spec/gemfiles/Gemfile.rails52 +7 -0
  35. data/spec/gemfiles/Gemfile.rails60 +7 -0
  36. data/spec/gemfiles/Gemfile.rails61 +7 -0
  37. data/spec/integration/active_record/active_record_spec.rb +41 -0
  38. data/spec/integration/mongoid/mongoid_spec.rb +39 -0
  39. data/spec/integration/shared/at_time.rb +53 -0
  40. data/spec/integration/shared/between_dates.rb +99 -0
  41. data/spec/integration/shared/between_times.rb +99 -0
  42. data/spec/integration/shared/by_calendar_month.rb +55 -0
  43. data/spec/integration/shared/by_cweek.rb +54 -0
  44. data/spec/integration/shared/by_day.rb +120 -0
  45. data/spec/integration/shared/by_direction.rb +126 -0
  46. data/spec/integration/shared/by_fortnight.rb +48 -0
  47. data/spec/integration/shared/by_month.rb +50 -0
  48. data/spec/integration/shared/by_quarter.rb +49 -0
  49. data/spec/integration/shared/by_week.rb +54 -0
  50. data/spec/integration/shared/by_weekend.rb +49 -0
  51. data/spec/integration/shared/by_year.rb +48 -0
  52. data/spec/integration/shared/index_scope_parameter.rb +111 -0
  53. data/spec/integration/shared/offset_parameter.rb +32 -0
  54. data/spec/integration/shared/order_parameter.rb +36 -0
  55. data/spec/integration/shared/relative.rb +174 -0
  56. data/spec/spec_helper.rb +33 -0
  57. data/spec/unit/kernel_date_spec.rb +113 -0
  58. data/spec/unit/kernel_time_spec.rb +57 -0
  59. data/spec/unit/normalization_spec.rb +384 -0
  60. data/tmp/.gitignore +1 -0
  61. metadata +298 -0
data/README.md ADDED
@@ -0,0 +1,616 @@
1
+ # ByStar
2
+
3
+ [![Build Status](https://travis-ci.org/radar/by_star.svg)](https://travis-ci.org/radar/by_star)
4
+ [![Code Climate](https://codeclimate.com/github/radar/by_star.svg)](https://codeclimate.com/github/radar/by_star)
5
+
6
+ ByStar (by_*) allows you easily and reliably query ActiveRecord and Mongoid objects based on time.
7
+
8
+ ### Examples
9
+
10
+ ```ruby
11
+ Post.by_year(2013) # all posts in 2013
12
+ Post.before(Date.today) # all posts for before today
13
+ Post.yesterday # all posts for yesterday
14
+ Post.between_times(Time.zone.now - 3.hours, # all posts in last 3 hours
15
+ Time.zone.now)
16
+ @post.next # next post after a given post
17
+ ```
18
+
19
+ ## Installation
20
+
21
+ Install this gem by adding this to your Gemfile:
22
+
23
+ ```ruby
24
+ gem 'by_star', git: 'https://github.com/radar/by_star'
25
+ ```
26
+
27
+ Then run `bundle install`
28
+
29
+ If you are using ActiveRecord, you're done!
30
+
31
+ Mongoid users, please include the Mongoid::ByStar module for each model you wish to use the functionality.
32
+ This is the convention among Mongoid plugins.
33
+
34
+ ```ruby
35
+ class MyModel
36
+ include Mongoid::Document
37
+ include Mongoid::ByStar
38
+ ```
39
+
40
+ ## Finder Methods
41
+
42
+ ### Base Scopes
43
+
44
+ ByStar adds the following finder scopes (class methods) to your model to query time ranges.
45
+ These accept a `Date`, `Time`, or `DateTime` object as an argument, which defaults to `Time.zone.now` if not specified:
46
+
47
+ | Scope | Meaning |
48
+ | --- | --- |
49
+ | `between_times(start_time, end_time)` | Finds all records occurring between two given times. |
50
+ | `between_dates(start_date, end_date)` | Finds all records occurring between two given dates, from beginning of start_date until end of end_date. |
51
+ | `before(end_time)` | Finds all records occurring before the given time. |
52
+ | `after(start_time)` | Finds all records occurring after the given time. |
53
+ | `at_time(time)` | Finds all records occurring exactly at the given time, or which overlap the time in the case of "timespan"-type object (see below) |
54
+
55
+ `between_times` and `between_dates` supports alternate argument forms:
56
+ * `between_times(Range)`
57
+ * `between_times(Array)`
58
+ * `between_times(start_time, nil)` - same as `after(start_time)`
59
+ * `between_times(nil, end_time)` - same as `before(end_time)`
60
+
61
+ ### Time Range Scopes
62
+
63
+ ByStar adds additional shortcut scopes based on commonly used time ranges.
64
+ See sections below for detailed argument usage of each:
65
+
66
+ | Scope | Meaning |
67
+ | --- | --- |
68
+ | `by_day` | Query by a given date. |
69
+ | `by_week` | Allows zero-based week value from 0 to 52. |
70
+ | `by_cweek` | Allows one-based week value from 1 to 53. |
71
+ | `by_weekend` | Saturday and Sunday only of the given week. |
72
+ | `by_fortnight` | A two-week period, with the first fortnight of the year beginning on 1st January. |
73
+ | `by_month` | Query by month. Allows integer arg, e.g. `11` for November. |
74
+ | `by_calendar_month` | Month as it appears on a calendar; days form previous/following months which are part of the first/last weeks of the given month. |
75
+ | `by_quarter` | 3-month intervals of the year. |
76
+ | `by_year` | Query by year. Allows integer arg, e.g. `2017`. |
77
+
78
+ ### Relative Scopes
79
+
80
+ ByStar also adds scopes which are relative to the current time.
81
+ Note the `past_*` and `next_*` methods represent a time distance from current time (`Time.zone.now`),
82
+ and do not strictly end/begin evenly on a calendar week/month/year (unlike `by_*` methods which do.)
83
+
84
+ | Scope | Meaning |
85
+ | --- | --- |
86
+ | `today` | Finds all occurrences on today's date. |
87
+ | `yesterday` | Finds all occurrences on yesterday's date. |
88
+ | `tomorrow` | Finds all occurrences on tomorrow's date. |
89
+ | `past_day` | Prior 24-hour period from current time. |
90
+ | `past_week` | Prior 7-day period from current time. |
91
+ | `past_fortnight` | Prior 14-day period from current time. |
92
+ | `past_month` | Prior 30-day period from current time. |
93
+ | `past_year` | Prior 365-day period from current time. |
94
+ | `next_day` | Subsequent 24-hour period from current time. |
95
+ | `next_week` | Subsequent 7-day period from current time. |
96
+ | `next_fortnight` | Subsequent 14-day period from current time. |
97
+ | `next_month` | Subsequent 30-day period from current time. |
98
+ | `next_year` | Subsequent 365-day period from current time. |
99
+
100
+ ### Superlative Finders
101
+
102
+ Find the oldest or newest records. Returns an object instance (not a relation):
103
+
104
+ * `newest`
105
+ * `oldest`
106
+
107
+ ### Instance Methods
108
+
109
+ In addition, ByStar adds instance methods to return the next / previous record in the timewise sequence.
110
+ Returns an object instance (not a relation):
111
+
112
+ * `object.next`
113
+ * `object.previous`
114
+
115
+ ### Kernel Extensions
116
+
117
+ ByStar extends the kernel `Date`, `Time`, and `DateTime` objects with the following instance methods,
118
+ which mirror the ActiveSupport methods `beginning_of_day`, `end_of_week`, etc:
119
+
120
+ * `beginning_of_weekend`
121
+ * `end_of_weekend`
122
+ * `beginning_of_fortnight`
123
+ * `end_of_fortnight`
124
+ * `beginning_of_calendar_month`
125
+ * `end_of_calendar_month`
126
+
127
+ Lastly, ByStar aliases Rails 3 `Date#to_time_in_current_zone` to the Rails 4 syntax `#in_time_zone`, if it has not already been defined.
128
+
129
+ ## Usage
130
+
131
+ ### Setting the Query Field
132
+
133
+ By default, ByStar assumes you will use the `created_at` field to query objects by time.
134
+ You may specify an alternate field on all query methods as follows:
135
+
136
+ ```ruby
137
+ Post.by_month("January", field: :updated_at)
138
+ ```
139
+
140
+ Alternatively, you may set a default in your model using the `by_star_field` macro:
141
+
142
+ ```ruby
143
+ class Post < ActiveRecord::Base
144
+ by_star_field :updated_at
145
+ end
146
+ ```
147
+
148
+ ### Scoping the Query
149
+
150
+ All ByStar methods (except `oldest`, `newest`, `previous`, `next`) return an `ActiveRecord::Relation`
151
+ (or `Mongoid::Criteria`) which can be daisy-chained with other scopes/finder methods:
152
+
153
+ ```ruby
154
+ Post.by_month.your_scope
155
+ Post.by_month(1).include(:tags).where("tags.name" => "ruby")
156
+ ```
157
+
158
+ Want to count records? Simple:
159
+
160
+ ```ruby
161
+ Post.by_month.count
162
+ ```
163
+
164
+ ### Timezone Handling
165
+
166
+ ByStar date-range finders will use value of `Time.zone` to evaluate the args.
167
+ This may cause unexpected behavior when use Time values in timezones other than `Time.zone`.
168
+
169
+ ```ruby
170
+ Time.zone = 'Australia/Sydney'
171
+ Post.by_day('2020-04-05 18:00:00 EST')
172
+ #=> Returns Apr 6th, 0:00 until Apr 6th, 23:59 in Sydney timezone.
173
+ ```
174
+
175
+ ### `:offset` Option
176
+
177
+ All ByStar finders support an `:offset` option which is applied to time period of the query condition.
178
+ This is useful in cases where the daily cycle occurs at a time other than midnight.
179
+
180
+ For example, if you'd like to find all Posts from 9:00 on 2014-03-05 until 8:59:59.999 on 2014-03-06, you can do:
181
+
182
+ ```ruby
183
+ Post.by_day('2014-03-05', offset: 9.hours)
184
+ ```
185
+
186
+ **Note:** When passing `offset` in date finders, it will set the hour, minute, and second on the queried date in order to properly handle DST transitions. Example:
187
+
188
+ ```ruby
189
+ Time.zone = 'Australia/Sydney'
190
+ Post.by_day('2020-04-05', offset: 9.hours)
191
+ #=> Returns Apr 5th, 09:00 until Apr 6th, 08:59
192
+ ```
193
+
194
+ ### Timespan Objects
195
+
196
+ If your object has both a start and end time, you may pass both params to `by_star_field`:
197
+
198
+ ```ruby
199
+ by_star_field :start_time, :end_time
200
+ ```
201
+
202
+ By default, ByStar queries will return all objects whose range has any overlap within the desired period (permissive):
203
+
204
+ ```ruby
205
+ MultiDayEvent.by_month("January")
206
+ #=> returns MultiDayEvents that overlap in January,
207
+ # even if they start in December and/or end in February
208
+ ```
209
+
210
+ ### Timespan Objects: `#at_time`
211
+
212
+ To find all instances of a timespan object which contain a specific time:
213
+
214
+ ```ruby
215
+ Post.at_time(time)
216
+ ```
217
+
218
+ This can be useful to find all currently active instances. Note that object instances which start
219
+ exactly at the given `time` will be included in the result, but instances that end exactly at the given
220
+ `time` will not be.
221
+
222
+ ### Timespan Objects: `:strict` Option
223
+
224
+ If you'd like to confine results to only those both starting and ending within the given range, use the `:strict` option:
225
+
226
+ ```ruby
227
+ MultiDayEvent.by_month("January", :strict => true)
228
+ #=> returns MultiDayEvents that both start AND end in January
229
+ ```
230
+
231
+ ### Timespan Objects: Database Indexing and `:index_scope` Option
232
+
233
+ In order to ensure query performance on large dataset, you must add an index to the query field (e.g. "created_at") be indexed. ByStar does **not** define indexes automatically.
234
+
235
+ Database indexes require querying a range query on a single field, i.e. `start_time >= X and start_time <= Y`.
236
+ If we use a single-sided query, the database will iterate through all items either from the beginning or until the end of time.
237
+ This poses a challenge for timespan-type objects which have two fields, i.e. `start_time` and `end_time`.
238
+ There are two cases to consider:
239
+
240
+ 1) Timespan with `:strict` option, e.g. `start_time >= X and end_time <= Y`.
241
+
242
+ Given that this gem requires `start_time >= end_time`, we add the converse constraint `start_time <= Y and end_time >= X`
243
+ to ensure both fields are double-sided, i.e. an index can be used on either field.
244
+
245
+ 2) Timespan without `:strict` option, e.g. "start_time < Y and end_time > X".
246
+
247
+ Here we need to add a condition `start_time >= X` to ensure `start_time` is bounded on both sides.
248
+ To achieve this, we allow an `:index_scope` option which is the minimum "strict" bound on the querying range,
249
+ in other words, it is an assumption about the maximum timespan of objects.
250
+
251
+ `:index_scope` supports multiple value types:
252
+
253
+ | `:index_scope` Value | Meaning |
254
+ | --- | --- |
255
+ | `nil` or `false` | No constraint set; query will be one-sided (default, but not recommended) |
256
+ | `Date` or `Time`, etc. | A fixed point in time |
257
+ | `ActiveSupport::Duration` (e.g. `1.month`) | The duration value will be subtracted from the start of the range. In other words, a value of `1.month` would imply the longest possible object in the database is no longer than `1.month`. |
258
+ | `Numeric` | Will be converted to seconds, then handled the same as `ActiveSupport::Duration` |
259
+ | `:beginning_of_day` (`Symbol` literal) |
260
+ | `Proc<Range, Hash(options)>` | A proc which evaluates to one of the above types. Args are `(start_time, end_time, options)` |
261
+
262
+ An example settings of `:index_scope`:
263
+
264
+ ```
265
+ # The maximum possible object length is 5 hours.
266
+ by_star index_scope: 5.hours
267
+
268
+ # Objects are guaranteed to start within the same month, with some offset.
269
+ by_star index_scope: ->(start_time, end_time, options){ start_time.beginning_of_month + (options[:offset] || 0) }
270
+
271
+ # The maximum possible object length half the range being queried.
272
+ by_star index_scope: ->(start_time, end_time, options){ ((start_time - end_time)*0.5).seconds }
273
+ ```
274
+
275
+ ### Chronic Support
276
+
277
+ If [Chronic](https://github.com/mojombo/chronic) gem is present, it will be used to parse natural-language date/time
278
+ strings in all ByStar finder methods. Otherwise, the Ruby `Time.parse` kernel method will be used as a fallback.
279
+
280
+ As of ByStar 2.2.0, you must explicitly include `gem 'chronic'` into your Gemfile in order to use Chronic.
281
+
282
+ ## Advanced Usage
283
+
284
+ ### between_times
285
+
286
+ To find records between two times:
287
+
288
+ ```ruby
289
+ Post.between_times(time1, time2)
290
+ ```
291
+
292
+ You use a Range like so:
293
+
294
+ ```ruby
295
+ Post.between_times(time1..time2)
296
+ ```
297
+
298
+ Also works with dates - WARNING: there are currently some caveats see [Issue #49](https://github.com/radar/by_star/issues/49):
299
+
300
+ ```ruby
301
+ Post.between_times(date1, date2)
302
+ ```
303
+
304
+ It will query records from `date1` (00:00:00 Hrs) until `date2` (23:59:59 Hrs).
305
+
306
+ ### before and after
307
+
308
+ To find all posts before / after the current time:
309
+
310
+ ```ruby
311
+ Post.before
312
+ Post.after
313
+ ```
314
+
315
+ To find all posts before certain time or date:
316
+
317
+ ```ruby
318
+ Post.before(Date.today + 2)
319
+ Post.after(Time.now + 5.days)
320
+ ```
321
+
322
+ You can also pass a string:
323
+
324
+ ```ruby
325
+ Post.before("next tuesday")
326
+ ```
327
+
328
+ For Time-Range type objects, only the start time is considered for `before` and `after`.
329
+
330
+ ### previous and next
331
+
332
+ To find the prior/subsequent record to a model instance, `previous`/`next` on it:
333
+
334
+ ```ruby
335
+ Post.last.previous
336
+ Post.first.next
337
+ ```
338
+
339
+ You can specify a field also:
340
+
341
+ ```ruby
342
+ Post.last.previous(field: "published_at")
343
+ Post.first.next(field: "published_at")
344
+ ```
345
+
346
+ For Time-Range type objects, only the start time is considered for `previous` and `next`.
347
+
348
+ ### by_year
349
+
350
+ To find records from the current year, simply call the method without any arguments:
351
+
352
+ ```ruby
353
+ Post.by_year
354
+ ```
355
+
356
+ To find records based on a year you can pass it a two or four digit number:
357
+
358
+ ```ruby
359
+ Post.by_year(09)
360
+ ```
361
+
362
+ This will return all posts in 2009, whereas:
363
+
364
+ ```ruby
365
+ Post.by_year(99)
366
+ ```
367
+
368
+ will return all the posts in the year 1999.
369
+
370
+ You can also specify the full year:
371
+
372
+ ```ruby
373
+ Post.by_year(2009)
374
+ Post.by_year(1999)
375
+ ```
376
+
377
+ ### by_month
378
+
379
+ If you know the number of the month you want:
380
+
381
+ ```ruby
382
+ Post.by_month(1)
383
+ ```
384
+
385
+ This will return all posts in the first month (January) of the current year.
386
+
387
+ If you like being verbose:
388
+
389
+ ```ruby
390
+ Post.by_month("January")
391
+ ```
392
+
393
+ This will return all posts created in January of the current year.
394
+
395
+ If you want to find all posts in January of last year just do
396
+
397
+ ```ruby
398
+ Post.by_month(1, year: 2007)
399
+ ```
400
+
401
+ or
402
+
403
+ ```ruby
404
+ Post.by_month("January", year: 2007)
405
+ ```
406
+
407
+ This will perform a find using the column you've specified.
408
+
409
+ If you have a Time object you can use it to find the posts:
410
+
411
+ ```ruby
412
+ Post.by_month(Time.local(2012, 11, 24))
413
+ ```
414
+
415
+ This will find all the posts in November 2012.
416
+
417
+ ### by_calendar_month
418
+
419
+ Finds records for a given month as shown on a calendar. Includes all the results of `by_month`, plus any results which fall in the same week as the first and last of the month. Useful for working with UI calendars which show rows of weeks.
420
+
421
+ ```ruby
422
+ Post.by_calendar_month
423
+ ```
424
+
425
+ Parameter behavior is otherwise the same as `by_month`. Also, `:start_day` option is supported to specify the start day of the week (`:monday`, `:tuesday`, etc.)
426
+
427
+ ### by_fortnight
428
+
429
+ Fortnight numbering starts at 0. The beginning of a fortnight is Monday, 12am.
430
+
431
+ To find records from the current fortnight:
432
+
433
+ ```ruby
434
+ Post.by_fortnight
435
+ ```
436
+
437
+ To find records based on a fortnight, you can pass in a number (representing the fortnight number) or a time object:
438
+
439
+ ```ruby
440
+ Post.by_fortnight(18)
441
+ ```
442
+
443
+ This will return all posts in the 18th fortnight of the current year.
444
+
445
+ ```ruby
446
+ Post.by_fortnight(18, year: 2012)
447
+ ```
448
+
449
+ This will return all posts in the 18th fortnight week of 2012.
450
+
451
+ ```ruby
452
+ Post.by_fortnight(Time.local(2012,1,1))
453
+ ```
454
+
455
+ This will return all posts from the first fortnight of 2012.
456
+
457
+ ### by_week and by_cweek
458
+
459
+ Week numbering starts at 0, and cweek numbering starts at 1 (same as `Date#cweek`). The beginning of a week is as defined in `ActiveSupport#beginning_of_week`, which can be configured.
460
+
461
+ To find records from the current week:
462
+
463
+ ```ruby
464
+ Post.by_week
465
+ Post.by_cweek # same result
466
+ ```
467
+
468
+ This will return all posts in the 37th week of the current year (remember week numbering starts at 0):
469
+
470
+ ```ruby
471
+ Post.by_week(36)
472
+ Post.by_cweek(37) # same result
473
+ ```
474
+
475
+ This will return all posts in the 37th week of 2012:
476
+
477
+ ```ruby
478
+ Post.by_week(36, year: 2012)
479
+ Post.by_cweek(37, year: 2012) # same result
480
+ ```
481
+
482
+ This will return all posts in the week which contains Jan 1, 2012:
483
+
484
+ ```ruby
485
+ Post.by_week(Time.local(2012,1,1))
486
+ Post.by_cweek(Time.local(2012,1,1)) # same result
487
+ ```
488
+
489
+ You may pass in a `:start_day` option (`:monday`, `:tuesday`, etc.) to specify the starting day of the week. This may also be configured in Rails.
490
+
491
+ ### by_weekend
492
+
493
+ If the time passed in (or the time now is a weekend) it will return posts from 0:00 Saturday to 23:59:59 Sunday. If the time is a week day, it will show all posts for the coming weekend.
494
+
495
+ ```ruby
496
+ Post.by_weekend(Time.now)
497
+ ```
498
+
499
+ ### by_day and today
500
+
501
+ To find records for today:
502
+
503
+ ```ruby
504
+ Post.by_day
505
+ Post.today
506
+ ```
507
+
508
+ To find records for a certain day:
509
+
510
+ ```ruby
511
+ Post.by_day(Time.local(2012, 1, 1))
512
+ ```
513
+
514
+ You can also pass a string:
515
+
516
+ ```ruby
517
+ Post.by_day("next tuesday")
518
+ ```
519
+
520
+ This will return all posts for the given day.
521
+
522
+ ### by_quarter
523
+
524
+ Finds records by 3-month quarterly period of year. Quarter numbering starts at 1. The four quarters of the year begin on Jan 1, Apr 1, Jul 1, and Oct 1 respectively.
525
+
526
+ To find records from the current quarter:
527
+
528
+ ```ruby
529
+ Post.by_quarter
530
+ ```
531
+
532
+ To find records based on a quarter, you can pass in a number (representing the quarter number) or a time object:
533
+
534
+ ```ruby
535
+ Post.by_quarter(4)
536
+ ```
537
+
538
+ This will return all posts in the 4th quarter of the current year.
539
+
540
+ ```ruby
541
+ Post.by_quarter(2, year: 2012)
542
+ ```
543
+
544
+ This will return all posts in the 2nd quarter of 2012.
545
+
546
+ ```ruby
547
+ Post.by_week(Time.local(2012,1,1))
548
+ ```
549
+
550
+ This will return all posts from the first quarter of 2012.
551
+
552
+ ## Version Support
553
+
554
+ ByStar is tested against the following versions:
555
+
556
+ * Ruby 2.0.0+
557
+ * Rails/ActiveRecord 3.2+
558
+ * Mongoid 3.1+
559
+
560
+ Note that ByStar automatically adds the following version compatibility shims:
561
+
562
+ * ActiveSupport 3.x: Add `Time/Date/DateTime#in_time_zone` (as an alias to `#to_time_in_current_zone`) for compatibility with Rails 4+.
563
+ * Mongoid 3.x: Adds `Criteria#reorder` method from Mongoid 4.
564
+
565
+
566
+ ## Testing
567
+
568
+ ### Test Setup
569
+
570
+ Specify a database by supplying a `DB` environmental variable:
571
+
572
+ ```bash
573
+ bundle exec rake spec DB=sqlite
574
+ ```
575
+
576
+ You can also take an ORM-specific test task for a ride:
577
+
578
+ ```bash
579
+ bundle exec rake spec:active_record
580
+ ```
581
+
582
+ Have an Active Record or Mongoid version in mind? Set the environment variables
583
+ `ACTIVE_RECORD_VERSION` and `MONGOID_VERSION` to a version of your choice. A
584
+ version number provided will translate to `~> VERSION`, and the string `master`
585
+ will grab the latest from Github.
586
+
587
+ ```bash
588
+ # Update your bundle appropriately...
589
+ ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle update
590
+
591
+ # ...then run the specs
592
+ ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle exec rpsec spec
593
+ ```
594
+
595
+ ### Test Implementation
596
+
597
+ ByStar tests use TimeCop to lock the system `Time.now` at Jan 01, 2014, and seed
598
+ objects with fixed dates according to `spec/fixtures/shared/seeds.rb`.
599
+ Note that the timezone is randomized on each run to shake-out timezone related quirks.
600
+
601
+
602
+ ## Collaborators
603
+
604
+ ByStar is actively maintained by Ryan Bigg (radar) and Johnny Shields (johnnyshields)
605
+
606
+ Thank you to the following people:
607
+
608
+ * Thomas Sinclair for the original bump for implementing ByStar
609
+ * [Ruby on Rails](http://rubyonrails.org/) for their support
610
+ * Mislav Marohnic
611
+ * August Lilleas (leethal)
612
+ * gte351s
613
+ * Sam Elliott (lenary)
614
+ * The creators of the [Chronic](https://github.com/mojombo/chronic) gem
615
+ * Erik Fonselius
616
+ * Johnny Shields (johnnyshields)
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ def orm_test(orm)
8
+ RSpec::Core::RakeTask.new(orm) do |task|
9
+ task.pattern = "./spec/{unit,integration/#{orm}}/{,/*/**}/*_spec.rb"
10
+ end
11
+ end
12
+
13
+ namespace :spec do
14
+ orm_test 'active_record'
15
+ orm_test 'mongoid'
16
+ end
17
+
18
+ task default: :spec
data/UPGRADING ADDED
@@ -0,0 +1,4 @@
1
+ Upgrading ByStar
2
+ ----------------
3
+
4
+ * As of version 4.0.0, ByStar changes the way it handles `Date` arg to the `#between_times` method. If a `Date` is given as the second (end) arg, the query will use `Date.end_of_day` to include all time values which fall inside that date.
data/by_star.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/by_star/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "ta_by_star"
6
+ s.version = ByStar::VERSION
7
+ s.authors = ["Ryan Bigg", "Johnny Shields"]
8
+ s.email = ["radarlistener@gmail.com"]
9
+ s.homepage = "http://github.com/radar/by_star"
10
+ s.summary = "ActiveRecord and Mongoid extension for easier date scopes and time ranges"
11
+ s.description = "ActiveRecord and Mongoid extension for easier date scopes and time ranges"
12
+
13
+ s.required_ruby_version = '>= 2.0.0'
14
+
15
+ s.post_install_message = File.read('UPGRADING') if File.exists?('UPGRADING')
16
+
17
+ s.add_dependency "activesupport", ">= 3.2.0"
18
+
19
+ s.add_development_dependency "chronic"
20
+ s.add_development_dependency "bundler"
21
+ s.add_development_dependency "sqlite3"
22
+ s.add_development_dependency "activerecord"
23
+ s.add_development_dependency "mongoid"
24
+ s.add_development_dependency "pg"
25
+ s.add_development_dependency "mysql2"
26
+ s.add_development_dependency "rspec-rails", "~> 3.1"
27
+ s.add_development_dependency "timecop", "~> 0.3"
28
+ s.add_development_dependency "pry"
29
+
30
+ s.files = `git ls-files`.split($/)
31
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
33
+ s.require_paths = ['lib']
34
+ end
data/cleaner.rb ADDED
@@ -0,0 +1,25 @@
1
+ files = Dir["**/*"]
2
+ ignored_files = [
3
+ /log\/.*/,
4
+ ]
5
+
6
+ files.delete_if do |file|
7
+ if File.directory?(file)
8
+ true
9
+ else
10
+ ignored_files.any? do |condition|
11
+ if condition.is_a?(String)
12
+ file == condition
13
+ else
14
+ condition.match(file)
15
+ end
16
+ end || false
17
+ end
18
+ end
19
+
20
+ for file in files - ignored_files
21
+ if File.file?(file)
22
+ lines = File.readlines(file).map { |line| line.gsub(/^\s+$/, "\n") }
23
+ File.open(file, "w+") { |f| f.write(lines.join) }
24
+ end
25
+ end