redis-objects-periodical 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.agents/skills/dependabot-batch-maintenance/SKILL.md +141 -0
- data/.github/dependabot.yml +32 -3
- data/.github/scripts/dependabot-auto-merge.cjs +182 -0
- data/.github/scripts/dependabot-auto-merge.test.cjs +278 -0
- data/.github/scripts/dependabot-policy.cjs +132 -0
- data/.github/scripts/dependabot-policy.test.cjs +235 -0
- data/.github/scripts/timezone-inventory.cjs +48 -0
- data/.github/scripts/timezone-inventory.test.cjs +86 -0
- data/.github/workflows/checks.yml +124 -0
- data/.github/workflows/ci.yml +191 -0
- data/.github/workflows/dependabot-auto-merge.yml +61 -0
- data/.github/workflows/release.yml +59 -0
- data/.github/workflows/rubocop_challenge.yml +71 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +16 -16
- data/AGENTS.md +133 -0
- data/CHANGELOG.md +47 -0
- data/CONTRIBUTING.md +203 -0
- data/Dockerfile +3 -2
- data/Gemfile +6 -6
- data/Gemfile.lock +70 -65
- data/README.md +58 -221
- data/docker-compose.yml +1 -3
- data/docs/maintaining.md +237 -0
- data/docs/usage.md +216 -0
- data/docs/verification/2026-10-27-timezone.md +25 -0
- data/gemfiles/active_support/Gemfile +5 -0
- data/gemfiles/active_support/Gemfile.lock +137 -0
- data/lib/redis/objects/periodical/version.rb +1 -1
- data/lib/redis/objects/periodical_counters.rb +1 -1
- data/lib/redis/objects/periodical_hashes.rb +1 -1
- data/lib/redis/objects/periodical_sets.rb +1 -1
- data/lib/redis/objects/periodical_values.rb +1 -1
- data/lib/redis/periodical_counter.rb +1 -1
- data/lib/redis/periodical_hash_key.rb +1 -1
- data/lib/redis/periodical_set.rb +1 -1
- data/lib/redis/periodical_value.rb +1 -1
- data/lib/redis/recurring_at_intervals/weekly.rb +3 -1
- data/lib/redis/recurring_at_intervals.rb +3 -3
- data/redis-objects-periodical.gemspec +1 -1
- metadata +26 -8
- data/.circleci/config.yml +0 -212
data/docs/usage.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Usage guide
|
|
2
|
+
|
|
3
|
+
[README](../README.md) introduces installation and a minimal counter example.
|
|
4
|
+
Configure the Redis connection through Redis::Objects before using these fields.
|
|
5
|
+
|
|
6
|
+
## Declarations and object lifetime
|
|
7
|
+
|
|
8
|
+
The examples below use these four fields. Each type's example illustrates a
|
|
9
|
+
separate sequence of writes to initially empty period keys.
|
|
10
|
+
|
|
11
|
+
```rb
|
|
12
|
+
class Homepage
|
|
13
|
+
include Redis::Objects
|
|
14
|
+
|
|
15
|
+
daily_counter :pv, expireat: -> { Time.now + 2_678_400 } # about a month
|
|
16
|
+
daily_hash_key :browsing_history, expireat: -> { Time.now + 2_678_400 } # about a month
|
|
17
|
+
daily_set :dau, expireat: -> { Time.now + 2_678_400 } # about a month
|
|
18
|
+
daily_value :cache, expireat: -> { Time.now + 2_678_400 } # about a month
|
|
19
|
+
|
|
20
|
+
def id
|
|
21
|
+
1
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
homepage = Homepage.new
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each field accessor constructs a periodical object using the current time. Its
|
|
29
|
+
Redis key and cached current time are fixed at construction. Call the accessor
|
|
30
|
+
again after a period boundary to select the new key:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
counter = homepage.pv
|
|
34
|
+
# After midnight, counter still addresses the day on which it was constructed.
|
|
35
|
+
# homepage.pv creates a new object and selects the current day's key.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The `global: true` option also supports class-level fields, as in
|
|
39
|
+
`daily_counter :pv, global: true`. Standard Redis::Objects operations remain
|
|
40
|
+
available on each periodical object.
|
|
41
|
+
|
|
42
|
+
## Periods and key formats
|
|
43
|
+
|
|
44
|
+
Combine any prefix below with `counter`, `value`, `set`, or `hash_key`.
|
|
45
|
+
The normal instance key has the prefix `model_name:id:field_name:`.
|
|
46
|
+
|
|
47
|
+
| Period prefix | Key suffix | Argument for historical access |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `annual_` | `yyyy` | `Date` or `Time` |
|
|
50
|
+
| `monthly_` | `yyyy-mm` | `Date` or `Time` |
|
|
51
|
+
| `weekly_` | `yyyyWww` | `Date` or `Time` |
|
|
52
|
+
| `daily_` | `yyyy-mm-dd` | `Date` or `Time` |
|
|
53
|
+
| `hourly_` | `yyyy-mm-ddThh` | `Time` |
|
|
54
|
+
| `minutely_` | `yyyy-mm-ddThh:mi` | `Time` |
|
|
55
|
+
|
|
56
|
+
Weekly keys first normalize the requested date to Monday, then format that
|
|
57
|
+
Monday using `%Y` and `%W`. They are not ISO week-year keys. For example,
|
|
58
|
+
2021-12-31 and 2022-01-01 both use `2021W52`. The year in the key can therefore
|
|
59
|
+
belong to December of the previous year. A configurable strategy remains an
|
|
60
|
+
unresolved decision in [Issue #265](https://github.com/ryz310/redis-objects-periodical/issues/265);
|
|
61
|
+
this guide describes the existing implementation.
|
|
62
|
+
|
|
63
|
+
Annual periods are not recommended when Redis is the only copy of long-term
|
|
64
|
+
history. Choose retention and expiration deliberately for every period.
|
|
65
|
+
|
|
66
|
+
## Shared historical operations
|
|
67
|
+
|
|
68
|
+
| Method | Behavior |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| `field[date_or_time]` or `slice` | Read one period's value |
|
|
71
|
+
| `field[start, length]` | Read/combine `length` successive periods |
|
|
72
|
+
| `field[start..finish]` | Pass an inclusive Range to the range reader |
|
|
73
|
+
| `field.range(start, finish)` | Read/combine successive cursors while cursor is at most `finish` |
|
|
74
|
+
| `field.delete_at(date_or_time)` | Delete one period's key |
|
|
75
|
+
| `field.at(date_or_time)` | Return a standard Redis::Objects object for that fixed key |
|
|
76
|
+
|
|
77
|
+
For the length form, zero returns an empty array (counter/value/set) or hash
|
|
78
|
+
(hash_key), and a negative length returns `nil`. Examples use inclusive ranges;
|
|
79
|
+
do not infer unsupported argument forms from the array-like method names.
|
|
80
|
+
|
|
81
|
+
Range iteration starts at the supplied start date/time and advances one interval
|
|
82
|
+
at a time; it does not first align the cursor to the calendar period boundary.
|
|
83
|
+
The end comparison is inclusive for that cursor, so a partial final interval may
|
|
84
|
+
not be visited. For example, a weekly range from Thursday 2021-04-01 to Monday
|
|
85
|
+
2021-04-05 reads only the week of March 29: its next cursor is April 8. Use
|
|
86
|
+
period-aligned endpoints when requesting complete calendar periods.
|
|
87
|
+
|
|
88
|
+
Counter and value ranges return arrays in period order. Set ranges return a
|
|
89
|
+
union; member order is not guaranteed. Hash ranges combine fields across periods:
|
|
90
|
+
unsigned integer strings are summed as integers, unsigned decimal strings are
|
|
91
|
+
summed as floats, and other repeated values are joined with commas. The numeric
|
|
92
|
+
aggregate remains a string. Missing periods contribute `0`, `nil`, `[]`, or `{}`
|
|
93
|
+
for counter, value, set, and hash respectively.
|
|
94
|
+
|
|
95
|
+
## Expiration
|
|
96
|
+
|
|
97
|
+
Use `expireat` as shown in the declarations to bound retention; its callable
|
|
98
|
+
returns the expiration time. The specs also exercise the upstream `expiration`
|
|
99
|
+
option with a duration in seconds. These options are provided through
|
|
100
|
+
Redis::Objects. Changing periods creates different keys; it does not itself
|
|
101
|
+
delete older period keys.
|
|
102
|
+
|
|
103
|
+
## Periodical Counters
|
|
104
|
+
|
|
105
|
+
```rb
|
|
106
|
+
# 2021-04-01
|
|
107
|
+
homepage.pv.increment(3)
|
|
108
|
+
|
|
109
|
+
# 2021-04-02 (next day)
|
|
110
|
+
homepage.pv.increment(2)
|
|
111
|
+
|
|
112
|
+
# 2021-04-03 (next day)
|
|
113
|
+
homepage.pv.increment(5)
|
|
114
|
+
|
|
115
|
+
homepage.pv[Date.new(2021, 4, 1)] # => 3
|
|
116
|
+
homepage.pv[Date.new(2021, 4, 1), 3] # => [3, 2, 5]
|
|
117
|
+
homepage.pv[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # => [3, 2]
|
|
118
|
+
|
|
119
|
+
homepage.pv.delete_at(Date.new(2021, 4, 1))
|
|
120
|
+
homepage.pv.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # => [0, 2, 5]
|
|
121
|
+
homepage.pv.at(Date.new(2021, 4, 2)) # => #<Redis::Counter key="homepage:1:pv:2021-04-02">
|
|
122
|
+
homepage.pv.at(Date.new(2021, 4, 2)).value # 2
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Periodical Values
|
|
126
|
+
|
|
127
|
+
```rb
|
|
128
|
+
# 2021-04-01
|
|
129
|
+
homepage.cache.value = 'a'
|
|
130
|
+
|
|
131
|
+
# 2021-04-02 (next day)
|
|
132
|
+
homepage.cache.value = 'b'
|
|
133
|
+
|
|
134
|
+
# 2021-04-03 (next day)
|
|
135
|
+
homepage.cache.value = 'c'
|
|
136
|
+
|
|
137
|
+
homepage.cache[Date.new(2021, 4, 1)] # => 'a'
|
|
138
|
+
homepage.cache[Date.new(2021, 4, 1), 3] # => ['a', 'b', 'c']
|
|
139
|
+
homepage.cache[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # => ['a', 'b']
|
|
140
|
+
|
|
141
|
+
homepage.cache.delete_at(Date.new(2021, 4, 1))
|
|
142
|
+
homepage.cache.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # => [nil, 'b', 'c']
|
|
143
|
+
homepage.cache.at(Date.new(2021, 4, 2)) # => #<Redis::Value key="homepage:1:cache:2021-04-02">
|
|
144
|
+
homepage.cache.at(Date.new(2021, 4, 2)).value # 'b'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Periodical Hashes
|
|
148
|
+
|
|
149
|
+
```rb
|
|
150
|
+
# 2021-04-01
|
|
151
|
+
homepage.browsing_history.incr('item1')
|
|
152
|
+
homepage.browsing_history.incr('item2')
|
|
153
|
+
homepage.browsing_history.incr('item2')
|
|
154
|
+
puts homepage.browsing_history.all # { 'item1' => '1', 'item2' => '2' }
|
|
155
|
+
|
|
156
|
+
# 2021-04-02 (next day)
|
|
157
|
+
puts homepage.browsing_history.all # {}
|
|
158
|
+
|
|
159
|
+
homepage.browsing_history.bulk_set('item1' => 3, 'item3' => 5)
|
|
160
|
+
puts homepage.browsing_history.all # { 'item1' => '3', 'item3' => '5' }
|
|
161
|
+
|
|
162
|
+
# 2021-04-03 (next day)
|
|
163
|
+
homepage.browsing_history.incr('item2')
|
|
164
|
+
homepage.browsing_history.incr('item4')
|
|
165
|
+
puts homepage.browsing_history.all # { 'item2' => '1', 'item4' => '1' }
|
|
166
|
+
|
|
167
|
+
homepage.browsing_history[Date.new(2021, 4, 1)] # => { 'item1' => '1', 'item2' => '2' }
|
|
168
|
+
homepage.browsing_history[Date.new(2021, 4, 1), 3] # => { 'item1' => '4', 'item2' => '3', 'item3' => '5', 'item4' => '1' }
|
|
169
|
+
homepage.browsing_history[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # => { 'item1' => '4', 'item2' => '2', 'item3' => '5' }
|
|
170
|
+
|
|
171
|
+
homepage.browsing_history.delete_at(Date.new(2021, 4, 1))
|
|
172
|
+
homepage.browsing_history.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # => { 'item1' => '3', 'item2' => '1', 'item3' => '5', 'item4' => '1' }
|
|
173
|
+
homepage.browsing_history.at(Date.new(2021, 4, 2)) # => #<Redis::HashKey key="homepage:1:browsing_history:2021-04-02">
|
|
174
|
+
homepage.browsing_history.at(Date.new(2021, 4, 2)).all # { 'item1' => '3', 'item3' => '5' }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Periodical Sets
|
|
178
|
+
|
|
179
|
+
```rb
|
|
180
|
+
# 2021-04-01
|
|
181
|
+
homepage.dau << 'user1'
|
|
182
|
+
homepage.dau << 'user2'
|
|
183
|
+
homepage.dau << 'user1' # dup ignored
|
|
184
|
+
puts homepage.dau.members # ['user1', 'user2']
|
|
185
|
+
puts homepage.dau.length # 2
|
|
186
|
+
puts homepage.dau.count # alias of #length
|
|
187
|
+
|
|
188
|
+
# 2021-04-02 (next day)
|
|
189
|
+
puts homepage.dau.members # []
|
|
190
|
+
|
|
191
|
+
homepage.dau.merge('user2', 'user3')
|
|
192
|
+
puts homepage.dau.members # ['user2', 'user3']
|
|
193
|
+
|
|
194
|
+
# 2021-04-03 (next day)
|
|
195
|
+
homepage.dau.merge('user4')
|
|
196
|
+
|
|
197
|
+
homepage.dau[Date.new(2021, 4, 1)] # => ['user1', 'user2']
|
|
198
|
+
homepage.dau[Date.new(2021, 4, 1), 3] # => ['user1', 'user2', 'user3', 'user4']
|
|
199
|
+
homepage.dau[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # => ['user1', 'user2', 'user3']
|
|
200
|
+
|
|
201
|
+
homepage.dau.delete_at(Date.new(2021, 4, 1))
|
|
202
|
+
homepage.dau.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # => ['user2', 'user3', 'user4']
|
|
203
|
+
homepage.dau.at(Date.new(2021, 4, 2)) # => #<Redis::Set key="homepage:1:dau:2021-04-02">
|
|
204
|
+
homepage.dau.at(Date.new(2021, 4, 2)).members # ['user2', 'user3']
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Timezone
|
|
208
|
+
|
|
209
|
+
Without ActiveSupport, new periodical objects use `Time.now` in the Ruby
|
|
210
|
+
process timezone. If `Time.current` is available, they use it instead. With
|
|
211
|
+
ActiveSupport, `Time.zone` selects the application zone; when unset, its process
|
|
212
|
+
clock fallback applies. ActiveSupport is optional and is not a runtime dependency.
|
|
213
|
+
|
|
214
|
+
The [contributor guide](../CONTRIBUTING.md#optional-activesupport-integration)
|
|
215
|
+
describes the specific Ruby/ActiveSupport pair and boundary cases verified in CI;
|
|
216
|
+
it does not establish compatibility with every Rails release or timezone.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Timezone verification recorded on 2026-10-27
|
|
2
|
+
|
|
3
|
+
This historical record was moved from README.md during documentation cleanup.
|
|
4
|
+
Its source is [revision e4c8af4](https://github.com/ryz310/redis-objects-periodical/blob/e4c8af42a8b311dbab2d38ed0e6bb2c9613b677a/README.md#L402).
|
|
5
|
+
The cleanup did not rerun the recorded experiment. Current procedures and the
|
|
6
|
+
execution inventory guard are described in
|
|
7
|
+
[Contributing](../../CONTRIBUTING.md#optional-activesupport-integration).
|
|
8
|
+
|
|
9
|
+
On 2026-10-27, the JUnit artifact from the
|
|
10
|
+
[successful CI run for commit 8ab4de1](https://github.com/ryz310/redis-objects-periodical/actions/runs/40409599457)
|
|
11
|
+
confirmed both zone groups actually ran under Ruby 3.3 / ActiveSupport 8.1.4.
|
|
12
|
+
A separate diagnostic changed `Time.use_zone(zone)` to `Time.use_zone(nil)` in
|
|
13
|
+
an isolated temporary copy and ran it against disposable Redis:
|
|
14
|
+
|
|
15
|
+
| Verification | Tokyo: executed / failed | Unset: executed / failed |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| Actual CI JUnit report | 48 / 0 | 48 / 0 |
|
|
18
|
+
| Temporary copy with the zone setting disabled | 48 / 36 | 48 / 0 |
|
|
19
|
+
|
|
20
|
+
Both reports contained zero errors and zero skipped examples. The diagnostic
|
|
21
|
+
failed on incorrect keys, for example expected annual suffix `2021` versus actual
|
|
22
|
+
`2020`. Some periods share a key at one of the two boundary instants, so disabling
|
|
23
|
+
the zone does not make every Tokyo example fail. This experiment confirms that
|
|
24
|
+
the assertions detect ineffective timezone selection; it is a recorded one-off
|
|
25
|
+
diagnostic, not an additional CI step.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ../..
|
|
3
|
+
specs:
|
|
4
|
+
redis-objects-periodical (0.8.0)
|
|
5
|
+
redis-objects (~> 1.0)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
activesupport (8.1.4)
|
|
11
|
+
base64
|
|
12
|
+
bigdecimal
|
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
14
|
+
connection_pool (>= 2.2.5)
|
|
15
|
+
drb
|
|
16
|
+
i18n (>= 1.6, < 2)
|
|
17
|
+
json
|
|
18
|
+
logger (>= 1.4.2)
|
|
19
|
+
minitest (>= 5.1)
|
|
20
|
+
securerandom (>= 0.3)
|
|
21
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
22
|
+
uri (>= 0.13.1)
|
|
23
|
+
ast (2.4.3)
|
|
24
|
+
base64 (0.3.0)
|
|
25
|
+
bigdecimal (4.1.3)
|
|
26
|
+
byebug (13.0.0)
|
|
27
|
+
reline (>= 0.6.0)
|
|
28
|
+
coderay (1.1.3)
|
|
29
|
+
concurrent-ruby (1.3.8)
|
|
30
|
+
connection_pool (2.3.0)
|
|
31
|
+
diff-lcs (1.6.2)
|
|
32
|
+
drb (2.2.3)
|
|
33
|
+
i18n (1.14.8)
|
|
34
|
+
concurrent-ruby (~> 1.0)
|
|
35
|
+
io-console (0.9.4)
|
|
36
|
+
json (3.1.0)
|
|
37
|
+
language_server-protocol (3.17.0.6)
|
|
38
|
+
lint_roller (1.1.0)
|
|
39
|
+
logger (1.7.0)
|
|
40
|
+
method_source (1.0.0)
|
|
41
|
+
minitest (5.26.1)
|
|
42
|
+
parallel (1.28.0)
|
|
43
|
+
parser (3.3.13.0)
|
|
44
|
+
ast (~> 2.4.1)
|
|
45
|
+
racc
|
|
46
|
+
prism (1.9.0)
|
|
47
|
+
pry (0.16.1)
|
|
48
|
+
coderay (~> 1.1)
|
|
49
|
+
method_source (~> 1.0)
|
|
50
|
+
reline (>= 0.6.0)
|
|
51
|
+
pry-byebug (3.12.0)
|
|
52
|
+
byebug (~> 13.0)
|
|
53
|
+
pry (>= 0.13, < 0.17)
|
|
54
|
+
racc (1.8.1)
|
|
55
|
+
rainbow (3.1.1)
|
|
56
|
+
rake (13.4.2)
|
|
57
|
+
redis (5.0.6)
|
|
58
|
+
redis-client (>= 0.9.0)
|
|
59
|
+
redis-client (0.12.1)
|
|
60
|
+
connection_pool
|
|
61
|
+
redis-objects (1.7.0)
|
|
62
|
+
redis
|
|
63
|
+
regexp_parser (2.13.1)
|
|
64
|
+
reline (0.7.0)
|
|
65
|
+
io-console (~> 0.5)
|
|
66
|
+
rspec (3.13.2)
|
|
67
|
+
rspec-core (~> 3.13.0)
|
|
68
|
+
rspec-expectations (~> 3.13.0)
|
|
69
|
+
rspec-mocks (~> 3.13.0)
|
|
70
|
+
rspec-core (3.13.6)
|
|
71
|
+
rspec-support (~> 3.13.0)
|
|
72
|
+
rspec-expectations (3.13.5)
|
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
74
|
+
rspec-support (~> 3.13.0)
|
|
75
|
+
rspec-mocks (3.13.8)
|
|
76
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
77
|
+
rspec-support (~> 3.13.0)
|
|
78
|
+
rspec-support (3.13.7)
|
|
79
|
+
rspec_junit_formatter (0.8.0)
|
|
80
|
+
rspec-core (>= 3.13, < 4)
|
|
81
|
+
rubocop (1.92.1)
|
|
82
|
+
json (>= 2.3)
|
|
83
|
+
language_server-protocol (~> 3.17.0.2)
|
|
84
|
+
lint_roller (~> 1.1.0)
|
|
85
|
+
parallel (>= 1.10)
|
|
86
|
+
parser (>= 3.3.0.2)
|
|
87
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
88
|
+
regexp_parser (>= 2.11.3, < 3.0)
|
|
89
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
90
|
+
ruby-progressbar (~> 1.7)
|
|
91
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
92
|
+
rubocop-ast (1.50.0)
|
|
93
|
+
parser (>= 3.3.7.2)
|
|
94
|
+
prism (~> 1.7)
|
|
95
|
+
rubocop-performance (1.27.0)
|
|
96
|
+
lint_roller (~> 1.1)
|
|
97
|
+
rubocop (>= 1.89.0, < 2.0)
|
|
98
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
99
|
+
rubocop-rspec (3.10.2)
|
|
100
|
+
lint_roller (~> 1.1)
|
|
101
|
+
regexp_parser (>= 2.0)
|
|
102
|
+
rubocop (~> 1.86, >= 1.86.2)
|
|
103
|
+
ruby-progressbar (1.13.0)
|
|
104
|
+
securerandom (0.3.2)
|
|
105
|
+
simplecov (1.3.2)
|
|
106
|
+
timecop (0.9.11)
|
|
107
|
+
tzinfo (2.0.6)
|
|
108
|
+
concurrent-ruby (~> 1.0)
|
|
109
|
+
unicode-display_width (3.3.0)
|
|
110
|
+
unicode-emoji (~> 4.3)
|
|
111
|
+
unicode-emoji (4.3.0)
|
|
112
|
+
uri (1.1.2)
|
|
113
|
+
yard (0.9.45)
|
|
114
|
+
|
|
115
|
+
PLATFORMS
|
|
116
|
+
aarch64-linux
|
|
117
|
+
x86_64-darwin-19
|
|
118
|
+
x86_64-darwin-20
|
|
119
|
+
x86_64-linux
|
|
120
|
+
|
|
121
|
+
DEPENDENCIES
|
|
122
|
+
activesupport (~> 8.1.4)
|
|
123
|
+
bundler (~> 4.0)
|
|
124
|
+
pry-byebug (~> 3.12)
|
|
125
|
+
rake (~> 13.4)
|
|
126
|
+
redis-objects-periodical!
|
|
127
|
+
rspec (~> 3.13)
|
|
128
|
+
rspec_junit_formatter
|
|
129
|
+
rubocop (~> 1.92)
|
|
130
|
+
rubocop-performance
|
|
131
|
+
rubocop-rspec
|
|
132
|
+
simplecov (= 1.3.2)
|
|
133
|
+
timecop
|
|
134
|
+
yard
|
|
135
|
+
|
|
136
|
+
BUNDLED WITH
|
|
137
|
+
4.0.23
|
|
@@ -11,5 +11,5 @@ Redis::PERIODICALS.each do |periodical|
|
|
|
11
11
|
include Redis::BaseCounterObject
|
|
12
12
|
include const_get("Redis::RecurringAtIntervals::#{periodical.capitalize}")
|
|
13
13
|
end
|
|
14
|
-
Redis.const_set("#{periodical.capitalize}Counter", new_class)
|
|
14
|
+
Redis.const_set(:"#{periodical.capitalize}Counter", new_class)
|
|
15
15
|
end
|
|
@@ -11,5 +11,5 @@ Redis::PERIODICALS.each do |periodical|
|
|
|
11
11
|
include Redis::BaseHashKeyObject
|
|
12
12
|
include const_get("Redis::RecurringAtIntervals::#{periodical.capitalize}")
|
|
13
13
|
end
|
|
14
|
-
Redis.const_set("#{periodical.capitalize}HashKey", new_class)
|
|
14
|
+
Redis.const_set(:"#{periodical.capitalize}HashKey", new_class)
|
|
15
15
|
end
|
data/lib/redis/periodical_set.rb
CHANGED
|
@@ -11,5 +11,5 @@ Redis::PERIODICALS.each do |periodical|
|
|
|
11
11
|
include Redis::BaseSetObject
|
|
12
12
|
include const_get("Redis::RecurringAtIntervals::#{periodical.capitalize}")
|
|
13
13
|
end
|
|
14
|
-
Redis.const_set("#{periodical.capitalize}Set", new_class)
|
|
14
|
+
Redis.const_set(:"#{periodical.capitalize}Set", new_class)
|
|
15
15
|
end
|
|
@@ -11,5 +11,5 @@ Redis::PERIODICALS.each do |periodical|
|
|
|
11
11
|
include Redis::BaseValueObject
|
|
12
12
|
include const_get("Redis::RecurringAtIntervals::#{periodical.capitalize}")
|
|
13
13
|
end
|
|
14
|
-
Redis.const_set("#{periodical.capitalize}Value", new_class)
|
|
14
|
+
Redis.const_set(:"#{periodical.capitalize}Value", new_class)
|
|
15
15
|
end
|
|
@@ -6,7 +6,9 @@ class Redis
|
|
|
6
6
|
private
|
|
7
7
|
|
|
8
8
|
def redis_periodical_field_key(date_or_time)
|
|
9
|
-
|
|
9
|
+
wday = date_or_time.wday
|
|
10
|
+
beginning_of_week_date = date_or_time.to_date - (wday.zero? ? 6 : wday - 1)
|
|
11
|
+
date_key = beginning_of_week_date.strftime('%YW%W')
|
|
10
12
|
[original_key, date_key].flatten.join(':')
|
|
11
13
|
end
|
|
12
14
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
class Redis
|
|
4
4
|
module RecurringAtIntervals
|
|
5
|
-
def initialize(key, *
|
|
5
|
+
def initialize(key, *)
|
|
6
6
|
@original_key = key
|
|
7
|
-
super(redis_periodical_field_key(current_time), *
|
|
7
|
+
super(redis_periodical_field_key(current_time), *)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
attr_reader :original_key
|
|
@@ -16,7 +16,7 @@ class Redis
|
|
|
16
16
|
case length <=> 0
|
|
17
17
|
when 1 then range(date_or_time, next_key(date_or_time, length - 1))
|
|
18
18
|
when 0 then empty_value
|
|
19
|
-
when -1 then nil
|
|
19
|
+
when -1 then nil # Ruby does this (a bit weird)
|
|
20
20
|
end
|
|
21
21
|
else
|
|
22
22
|
get_value_from_redis(redis_periodical_field_key(date_or_time))
|
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
28
28
|
spec.require_paths = ['lib']
|
|
29
29
|
|
|
30
|
-
spec.required_ruby_version = '>=
|
|
30
|
+
spec.required_ruby_version = '>= 3.3.0'
|
|
31
31
|
|
|
32
32
|
spec.add_dependency 'redis-objects', '~> 1.0'
|
|
33
33
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: redis-objects-periodical
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ryz310
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-10-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: redis-objects
|
|
@@ -32,15 +32,28 @@ executables: []
|
|
|
32
32
|
extensions: []
|
|
33
33
|
extra_rdoc_files: []
|
|
34
34
|
files:
|
|
35
|
-
- ".
|
|
35
|
+
- ".agents/skills/dependabot-batch-maintenance/SKILL.md"
|
|
36
36
|
- ".gem_comet.yml"
|
|
37
37
|
- ".github/dependabot.yml"
|
|
38
|
+
- ".github/scripts/dependabot-auto-merge.cjs"
|
|
39
|
+
- ".github/scripts/dependabot-auto-merge.test.cjs"
|
|
40
|
+
- ".github/scripts/dependabot-policy.cjs"
|
|
41
|
+
- ".github/scripts/dependabot-policy.test.cjs"
|
|
42
|
+
- ".github/scripts/timezone-inventory.cjs"
|
|
43
|
+
- ".github/scripts/timezone-inventory.test.cjs"
|
|
44
|
+
- ".github/workflows/checks.yml"
|
|
45
|
+
- ".github/workflows/ci.yml"
|
|
46
|
+
- ".github/workflows/dependabot-auto-merge.yml"
|
|
47
|
+
- ".github/workflows/release.yml"
|
|
48
|
+
- ".github/workflows/rubocop_challenge.yml"
|
|
38
49
|
- ".gitignore"
|
|
39
50
|
- ".rspec"
|
|
40
51
|
- ".rubocop.yml"
|
|
41
52
|
- ".rubocop_todo.yml"
|
|
53
|
+
- AGENTS.md
|
|
42
54
|
- CHANGELOG.md
|
|
43
55
|
- CODE_OF_CONDUCT.md
|
|
56
|
+
- CONTRIBUTING.md
|
|
44
57
|
- Dockerfile
|
|
45
58
|
- Gemfile
|
|
46
59
|
- Gemfile.lock
|
|
@@ -50,6 +63,11 @@ files:
|
|
|
50
63
|
- bin/console
|
|
51
64
|
- bin/setup
|
|
52
65
|
- docker-compose.yml
|
|
66
|
+
- docs/maintaining.md
|
|
67
|
+
- docs/usage.md
|
|
68
|
+
- docs/verification/2026-10-27-timezone.md
|
|
69
|
+
- gemfiles/active_support/Gemfile
|
|
70
|
+
- gemfiles/active_support/Gemfile.lock
|
|
53
71
|
- lib/redis-objects-periodical.rb
|
|
54
72
|
- lib/redis/base_counter_object.rb
|
|
55
73
|
- lib/redis/base_hash_key_object.rb
|
|
@@ -80,7 +98,7 @@ metadata:
|
|
|
80
98
|
source_code_uri: https://github.com/ryz310/redis-objects-periodical
|
|
81
99
|
changelog_uri: https://github.com/ryz310/redis-objects-periodical/blob/master/CHANGELOG.md
|
|
82
100
|
rubygems_mfa_required: 'true'
|
|
83
|
-
post_install_message:
|
|
101
|
+
post_install_message:
|
|
84
102
|
rdoc_options: []
|
|
85
103
|
require_paths:
|
|
86
104
|
- lib
|
|
@@ -88,15 +106,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
88
106
|
requirements:
|
|
89
107
|
- - ">="
|
|
90
108
|
- !ruby/object:Gem::Version
|
|
91
|
-
version:
|
|
109
|
+
version: 3.3.0
|
|
92
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
111
|
requirements:
|
|
94
112
|
- - ">="
|
|
95
113
|
- !ruby/object:Gem::Version
|
|
96
114
|
version: '0'
|
|
97
115
|
requirements: []
|
|
98
|
-
rubygems_version: 3.
|
|
99
|
-
signing_key:
|
|
116
|
+
rubygems_version: 3.5.22
|
|
117
|
+
signing_key:
|
|
100
118
|
specification_version: 4
|
|
101
119
|
summary: Extends Redis::Objects as periodical.
|
|
102
120
|
test_files: []
|