redis-objects-periodical 0.6.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/skills/dependabot-batch-maintenance/SKILL.md +141 -0
  3. data/.github/dependabot.yml +32 -3
  4. data/.github/scripts/dependabot-auto-merge.cjs +182 -0
  5. data/.github/scripts/dependabot-auto-merge.test.cjs +278 -0
  6. data/.github/scripts/dependabot-policy.cjs +132 -0
  7. data/.github/scripts/dependabot-policy.test.cjs +235 -0
  8. data/.github/scripts/timezone-inventory.cjs +48 -0
  9. data/.github/scripts/timezone-inventory.test.cjs +86 -0
  10. data/.github/workflows/checks.yml +124 -0
  11. data/.github/workflows/ci.yml +191 -0
  12. data/.github/workflows/dependabot-auto-merge.yml +61 -0
  13. data/.github/workflows/release.yml +59 -0
  14. data/.github/workflows/rubocop_challenge.yml +71 -0
  15. data/.rspec +1 -0
  16. data/.rubocop.yml +1 -1
  17. data/.rubocop_todo.yml +3 -2
  18. data/AGENTS.md +133 -0
  19. data/CHANGELOG.md +87 -0
  20. data/CONTRIBUTING.md +203 -0
  21. data/Dockerfile +3 -2
  22. data/Gemfile +6 -6
  23. data/Gemfile.lock +71 -66
  24. data/README.md +58 -180
  25. data/docker-compose.yml +1 -3
  26. data/docs/maintaining.md +237 -0
  27. data/docs/usage.md +216 -0
  28. data/docs/verification/2026-10-27-timezone.md +25 -0
  29. data/gemfiles/active_support/Gemfile +5 -0
  30. data/gemfiles/active_support/Gemfile.lock +137 -0
  31. data/lib/redis/base_value_object.rb +27 -0
  32. data/lib/redis/objects/periodical/version.rb +1 -1
  33. data/lib/redis/objects/periodical_counters.rb +1 -1
  34. data/lib/redis/objects/periodical_hashes.rb +1 -1
  35. data/lib/redis/objects/periodical_sets.rb +1 -1
  36. data/lib/redis/objects/periodical_values.rb +44 -0
  37. data/lib/redis/periodical_counter.rb +1 -1
  38. data/lib/redis/periodical_hash_key.rb +1 -1
  39. data/lib/redis/periodical_set.rb +1 -1
  40. data/lib/redis/periodical_value.rb +15 -0
  41. data/lib/redis/recurring_at_intervals/weekly.rb +3 -1
  42. data/lib/redis/recurring_at_intervals.rb +3 -3
  43. data/lib/redis-objects-periodical.rb +3 -0
  44. data/redis-objects-periodical.gemspec +2 -2
  45. metadata +33 -12
  46. data/.circleci/config.yml +0 -212
@@ -0,0 +1,191 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [master, release]
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ci-${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ dependabot_policy:
18
+ name: dependabot-policy
19
+ runs-on: ubuntu-24.04
20
+ timeout-minutes: 5
21
+ steps:
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+ - name: Test auto-merge policy without API writes
26
+ run: node --test .github/scripts/*.test.cjs
27
+
28
+ active_support_timezone:
29
+ name: active-support-timezone
30
+ runs-on: ubuntu-24.04
31
+ timeout-minutes: 20
32
+ container:
33
+ image: cimg/ruby:3.3
34
+ options: --user 0
35
+ services:
36
+ redis:
37
+ image: redis:latest@sha256:97ec88159e6d7cfb5ddef9015386087d58a912de80112f06ebdfa78fa5989901
38
+ options: >-
39
+ --health-cmd "redis-cli ping"
40
+ --health-interval 5s
41
+ --health-timeout 3s
42
+ --health-retries 10
43
+ defaults:
44
+ run:
45
+ shell: bash
46
+ env:
47
+ TZ: UTC
48
+ BUNDLE_GEMFILE: gemfiles/active_support/Gemfile
49
+ BUNDLE_FROZEN: 'true'
50
+ BUNDLE_PATH: vendor/bundle
51
+ SIMPLECOV_COMMAND_NAME: active-support-timezone
52
+ steps:
53
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
54
+ with:
55
+ persist-credentials: false
56
+ - name: Install locked optional integration dependencies
57
+ run: |
58
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
59
+ git ls-files --error-unmatch lib/redis-objects-periodical.rb >/dev/null
60
+ gem install bundler -v 4.0.23 --no-document
61
+ bundle _4.0.23_ install
62
+ - name: Verify real ActiveSupport timezone behavior in a separate process
63
+ run: |
64
+ mkdir -p test-results
65
+ bundle exec rspec spec/integration/redis/recurring_at_intervals_spec.rb --exclude-pattern '' \
66
+ --format RspecJunitFormatter --out test-results/active-support.xml \
67
+ --format json --out test-results/active-support.json
68
+ - name: Verify every intended timezone example passed
69
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
70
+ with:
71
+ script: |
72
+ const { readFileSync } = require('node:fs');
73
+ const { validateInventory } = require('./.github/scripts/timezone-inventory.cjs');
74
+ const report = JSON.parse(readFileSync('test-results/active-support.json', 'utf8'));
75
+ core.info(`Verified ${validateInventory(report)} passed timezone integration examples`);
76
+ - name: Store integration results
77
+ if: ${{ always() }}
78
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
79
+ with:
80
+ name: active-support-timezone
81
+ path: |
82
+ test-results/
83
+ coverage/
84
+ retention-days: 14
85
+
86
+ checks:
87
+ uses: ./.github/workflows/checks.yml
88
+
89
+ yardoc:
90
+ runs-on: ubuntu-24.04
91
+ timeout-minutes: 15
92
+ container:
93
+ image: cimg/ruby:3.3
94
+ options: --user 0
95
+ defaults:
96
+ run:
97
+ shell: bash
98
+ env:
99
+ BUNDLE_FROZEN: 'true'
100
+ BUNDLE_PATH: vendor/bundle
101
+ steps:
102
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
103
+ with:
104
+ persist-credentials: false
105
+ - name: Install locked dependencies
106
+ run: |
107
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
108
+ git ls-files --error-unmatch lib/redis-objects-periodical.rb >/dev/null
109
+ gem install bundler -v 4.0.23 --no-document
110
+ bundle _4.0.23_ install
111
+ - name: Generate YARD documentation
112
+ run: bundle exec yardoc -o yardoc
113
+ - name: Store documentation
114
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
115
+ with:
116
+ name: yardoc
117
+ path: yardoc/
118
+ if-no-files-found: error
119
+ retention-days: 14
120
+
121
+ upload_coverage:
122
+ name: upload-coverage
123
+ needs: checks
124
+ runs-on: ubuntu-24.04
125
+ timeout-minutes: 15
126
+ container:
127
+ image: cimg/ruby:3.3
128
+ options: --user 0
129
+ defaults:
130
+ run:
131
+ shell: bash
132
+ env:
133
+ BUNDLE_FROZEN: 'true'
134
+ BUNDLE_PATH: vendor/bundle
135
+ steps:
136
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
137
+ with:
138
+ persist-credentials: false
139
+ - name: Install locked dependencies
140
+ run: |
141
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
142
+ git ls-files --error-unmatch lib/redis-objects-periodical.rb >/dev/null
143
+ gem install bundler -v 4.0.23 --no-document
144
+ bundle _4.0.23_ install
145
+ - name: Download coverage merge inputs
146
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8
147
+ with:
148
+ pattern: simplecov-ruby-*
149
+ path: tmp/simplecov-results
150
+ - name: Collate all three Ruby results
151
+ run: |
152
+ bundle exec ruby -e '
153
+ require "simplecov"
154
+ require "simplecov_json_formatter"
155
+
156
+ resultset_files = %w[3.3 3.4 4.0].map do |version|
157
+ "tmp/simplecov-results/simplecov-ruby-#{version}/resultset.json"
158
+ end
159
+ missing = resultset_files.reject { |file| File.file?(file) }
160
+ abort("Missing coverage results: #{missing.join(", ")}") unless missing.empty?
161
+
162
+ SimpleCov.collate(resultset_files, ignore_timeout: true) do
163
+ formatter SimpleCov::Formatter::JSONFormatter
164
+ coverage_dir "coverage"
165
+ end
166
+ '
167
+ - name: Store merged coverage
168
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
169
+ with:
170
+ name: merged-coverage
171
+ path: coverage/coverage.json
172
+ if-no-files-found: error
173
+ retention-days: 14
174
+ - name: Check Qlty authentication
175
+ id: qlty
176
+ env:
177
+ QLTY_COVERAGE_TOKEN: ${{ secrets.QLTY_COVERAGE_TOKEN }}
178
+ run: |
179
+ if [ -n "$QLTY_COVERAGE_TOKEN" ]; then
180
+ echo "available=true" >> "$GITHUB_OUTPUT"
181
+ else
182
+ echo "available=false" >> "$GITHUB_OUTPUT"
183
+ echo "QLTY_COVERAGE_TOKEN is not set. Coverage is saved; skipping Qlty upload."
184
+ fi
185
+ - name: Publish coverage to Qlty
186
+ if: ${{ steps.qlty.outputs.available == 'true' }}
187
+ uses: qltysh/qlty-action/coverage@ebcd284bf32e36a030afe15f1e136c7be08b9506 # v2.5.0
188
+ with:
189
+ token: ${{ secrets.QLTY_COVERAGE_TOKEN }}
190
+ files: coverage/coverage.json
191
+ skip-errors: false
@@ -0,0 +1,61 @@
1
+ name: Dependabot Auto Merge
2
+
3
+ on:
4
+ # Metadata only: never check out or execute the PR head in this privileged job.
5
+ # Required for a write token on Dependabot events; only the trusted base policy runs.
6
+ pull_request_target: # zizmor: ignore[dangerous-triggers]
7
+ types: [opened, reopened, synchronize, ready_for_review]
8
+
9
+ concurrency:
10
+ group: dependabot-auto-merge-${{ github.event.pull_request.number }}
11
+ # Serialize enable/revoke operations; cancellation has no expected-head API guard.
12
+ cancel-in-progress: false
13
+
14
+ permissions: {}
15
+
16
+ jobs:
17
+ enable:
18
+ if: >-
19
+ ${{ github.event.pull_request.user.login == 'dependabot[bot]' &&
20
+ github.event.pull_request.base.ref == 'master' &&
21
+ github.event.pull_request.head.repo.full_name == github.repository }}
22
+ runs-on: ubuntu-24.04
23
+ timeout-minutes: 5
24
+ permissions:
25
+ contents: write
26
+ pull-requests: write
27
+ actions: read # Verify the originating workflow run of an ownership marker.
28
+ steps:
29
+ - name: Check out trusted base policy only
30
+ id: policy_checkout
31
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32
+ with:
33
+ ref: ${{ github.event.pull_request.base.sha }}
34
+ persist-credentials: false
35
+ sparse-checkout: .github/scripts
36
+ - name: Fetch Dependabot metadata
37
+ id: metadata
38
+ uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0
39
+ with:
40
+ github-token: ${{ github.token }}
41
+ - name: Reconcile workflow-owned auto-merge
42
+ # An earlier metadata failure must still revoke an owned reservation.
43
+ if: ${{ always() && steps.policy_checkout.outcome == 'success' }}
44
+ id: policy
45
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
46
+ env:
47
+ METADATA_OUTCOME: ${{ steps.metadata.outcome }}
48
+ ECOSYSTEM: ${{ steps.metadata.outputs.package-ecosystem }}
49
+ UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }}
50
+ DEPENDENCY_NAMES: ${{ steps.metadata.outputs.dependency-names }}
51
+ with:
52
+ script: |
53
+ const { reconcile } = require('./.github/scripts/dependabot-auto-merge.cjs');
54
+ await reconcile({ github, context, core,
55
+ metadataOutcome: process.env.METADATA_OUTCOME,
56
+ metadata: {
57
+ ecosystem: process.env.ECOSYSTEM,
58
+ updateType: process.env.UPDATE_TYPE,
59
+ dependencyNames: process.env.DEPENDENCY_NAMES || '',
60
+ },
61
+ });
@@ -0,0 +1,59 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [release]
6
+ workflow_dispatch:
7
+
8
+ concurrency:
9
+ group: release
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ checks:
17
+ if: ${{ github.ref == 'refs/heads/release' }}
18
+ uses: ./.github/workflows/checks.yml
19
+
20
+ publish:
21
+ needs: checks
22
+ if: ${{ github.ref == 'refs/heads/release' }}
23
+ runs-on: ubuntu-24.04
24
+ timeout-minutes: 20
25
+ environment: release
26
+ permissions:
27
+ contents: write
28
+ id-token: write
29
+ env:
30
+ BUNDLE_FROZEN: 'true'
31
+ steps:
32
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33
+ with:
34
+ fetch-depth: 0
35
+ persist-credentials: false
36
+ - name: Set up Ruby without dependency caches
37
+ uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
38
+ with:
39
+ ruby-version: '3.3'
40
+ bundler: '4.0.23'
41
+ bundler-cache: false
42
+ - name: Install locked dependencies
43
+ run: bundle install
44
+ - name: Check release version and prepare the tested commit
45
+ run: |
46
+ git checkout -B release "$GITHUB_SHA"
47
+ version=$(bundle exec ruby -r ./lib/redis/objects/periodical/version -e 'puts Redis::Objects::Periodical::VERSION')
48
+ if git show-ref --verify --quiet "refs/tags/v$version"; then
49
+ echo "Tag v$version already exists. Inspect the previous release before retrying."
50
+ exit 1
51
+ fi
52
+ status=$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' \
53
+ "https://rubygems.org/api/v2/rubygems/redis-objects-periodical/versions/$version.json")
54
+ if [ "$status" != 404 ]; then
55
+ echo "Expected an unpublished version (HTTP 404); received HTTP $status."
56
+ exit 1
57
+ fi
58
+ - name: Publish via RubyGems Trusted Publishing
59
+ uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1
@@ -0,0 +1,71 @@
1
+ name: Rubocop Challenge
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '30 23 * * *' # 08:30 JST every day
6
+ workflow_dispatch:
7
+ inputs:
8
+ dry-run:
9
+ description: 'Check the challenge without pushing a branch or creating a PR'
10
+ type: boolean
11
+ default: true
12
+
13
+ concurrency:
14
+ group: rubocop-challenge
15
+ cancel-in-progress: false
16
+
17
+ permissions: {}
18
+
19
+ jobs:
20
+ dry_run:
21
+ if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry-run && github.ref == 'refs/heads/master' }}
22
+ runs-on: ubuntu-24.04
23
+ timeout-minutes: 20
24
+ permissions:
25
+ contents: read
26
+ steps:
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
28
+ with:
29
+ persist-credentials: false
30
+ - uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
31
+ with:
32
+ ruby-version: '3.3'
33
+ bundler: '4.0.23'
34
+ bundler-cache: false
35
+ - name: Install dependencies and Challenger
36
+ run: |
37
+ bundle install
38
+ gem install rubocop_challenger --no-document
39
+ - name: Run without remote writes
40
+ # PrComet checks for a token even when --no-create-pr skips remote writes.
41
+ env:
42
+ GITHUB_ACCESS_TOKEN: ${{ github.token }}
43
+ run: rubocop_challenger go --email=ryz310@gmail.com --name=ryz310 --no-create-pr
44
+
45
+ challenge:
46
+ if: >-
47
+ ${{ github.ref == 'refs/heads/master' &&
48
+ (github.event_name == 'schedule' || !inputs.dry-run) }}
49
+ runs-on: ubuntu-24.04
50
+ timeout-minutes: 20
51
+ permissions:
52
+ contents: write
53
+ pull-requests: write
54
+ steps:
55
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
56
+ with:
57
+ # PrComet authenticates its push using GITHUB_ACCESS_TOKEN below.
58
+ persist-credentials: false
59
+ - uses: ruby/setup-ruby@26e5b7d197ebf60545ee9667bcbace0be11ccaec # v1.334.0
60
+ with:
61
+ ruby-version: '3.3'
62
+ bundler: '4.0.23'
63
+ bundler-cache: false
64
+ - name: Install dependencies and Challenger
65
+ run: |
66
+ bundle install
67
+ gem install rubocop_challenger --no-document
68
+ - name: Create challenge PR
69
+ env:
70
+ GITHUB_ACCESS_TOKEN: ${{ github.token }}
71
+ run: rubocop_challenger go --email=ryz310@gmail.com --name=ryz310
data/.rspec CHANGED
@@ -1,3 +1,4 @@
1
1
  --format documentation
2
2
  --color
3
3
  --require spec_helper
4
+ --exclude-pattern spec/integration/**/*_spec.rb
data/.rubocop.yml CHANGED
@@ -5,7 +5,7 @@ require:
5
5
  - rubocop-rspec
6
6
 
7
7
  AllCops:
8
- TargetRubyVersion: 2.7
8
+ TargetRubyVersion: 3.3
9
9
  NewCops: enable
10
10
 
11
11
  Layout/LineLength:
data/.rubocop_todo.yml CHANGED
@@ -1,12 +1,12 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2023-02-08 23:31:05 UTC using RuboCop version 1.45.1.
3
+ # on 2024-03-07 00:36:04 UTC using RuboCop version 1.62.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 12
9
+ # Offense count: 13
10
10
  # Configuration parameters: AllowedConstants.
11
11
  Style/Documentation:
12
12
  Exclude:
@@ -16,6 +16,7 @@ Style/Documentation:
16
16
  - 'lib/redis/base_counter_object.rb'
17
17
  - 'lib/redis/base_hash_key_object.rb'
18
18
  - 'lib/redis/base_set_object.rb'
19
+ - 'lib/redis/base_value_object.rb'
19
20
  - 'lib/redis/recurring_at_intervals.rb'
20
21
  - 'lib/redis/recurring_at_intervals/annual.rb'
21
22
  - 'lib/redis/recurring_at_intervals/daily.rb'
data/AGENTS.md ADDED
@@ -0,0 +1,133 @@
1
+ # AGENTS.md
2
+
3
+ ## Project and sources of truth
4
+
5
+ - This Ruby gem extends `redis-objects` with counters, values, sets, and hashes
6
+ for six intervals: annual, monthly, weekly, daily, hourly, and minutely.
7
+ - Read [README.md](README.md) for the public entry point, [docs/usage.md](docs/usage.md)
8
+ for detailed usage, and [CONTRIBUTING.md](CONTRIBUTING.md) for development commands.
9
+ Check implementation and specs before changing behavior.
10
+ - When a repository's documentation and its existing code disagree, follow the
11
+ conventions used in the existing code, and in your final reply point out each
12
+ inconsistency you found between the documentation and the code.
13
+ - Apply this default to descriptions of existing conventions. It does not
14
+ override explicit user requests, security or compatibility requirements,
15
+ configured test/lint checks, or an approved migration. If existing behavior
16
+ appears defective or intent is unclear, surface the decision rather than
17
+ treating the code as correct by definition.
18
+ - Report inconsistencies encountered during the task with relevant file
19
+ references; this does not require a repository-wide audit. The precedence
20
+ sentence comes from [Xu and Wu (2026), section 4](https://arxiv.org/html/2610.30571v1#S4);
21
+ the scope and exceptions above are this repository's adaptation.
22
+ - Entry point and generated classes: `lib/redis-objects-periodical.rb`,
23
+ `lib/redis/periodical_*.rb`, and `lib/redis/objects/periodical_*.rb`.
24
+ - Shared date/range behavior: `lib/redis/recurring_at_intervals.rb`; key formats
25
+ and interval arithmetic: `lib/redis/recurring_at_intervals/`.
26
+ - Type-specific reads, aggregation, and deletion: `lib/redis/base_*_object.rb`.
27
+ - Behavior specs: `spec/lib/redis/`; Redis connection and cleanup:
28
+ [spec/spec_helper.rb](spec/spec_helper.rb).
29
+ - Dependencies and packaging: [Gemfile](Gemfile),
30
+ [redis-objects-periodical.gemspec](redis-objects-periodical.gemspec), and
31
+ [Gemfile.lock](Gemfile.lock). CI lives in
32
+ [.github/workflows/](.github/workflows/). External cutover and rollback steps
33
+ are in [docs/maintaining.md](docs/maintaining.md#circleci-migration-checklist).
34
+
35
+ ## Task workflow
36
+
37
+ - Check the checkout, branch, `git status`, and `git worktree list` first.
38
+ Preserve unrelated work and keep the task focused.
39
+ - Start independent work from an up-to-date `master`: fetch `origin`, update
40
+ with a fast-forward only, re-read this file, and create `codex/<task-name>`
41
+ (`claude/<task-name>` for Claude Code). Continue an existing task on its branch.
42
+ Do not reset local changes or force a divergent branch to match the remote.
43
+ - Explain scope and verification before substantial changes. Keep unrelated
44
+ cleanup, dependency upgrades, and support-policy changes separate.
45
+ - At completion, report changes, verification results, and unverified items.
46
+ Propose a brief KPT retrospective when useful; keep it in the conversation
47
+ unless the user requests another destination. Propose durable guidance changes
48
+ based on findings rather than expanding this file for one-off workarounds.
49
+
50
+ ## Runtime and compatibility
51
+
52
+ - Preserve the repository's declared Ruby minimum of 3.3 (`required_ruby_version`)
53
+ and `redis-objects ~> 1.0` dependency unless changing support is in scope.
54
+ The Docker development baseline and RuboCop target are Ruby 3.3; the configured
55
+ CI build matrix covers Ruby 3.3, 3.4, and 4.0. These describe this
56
+ repository's configuration, not upstream maintenance status.
57
+ - This is a standalone gem. Rails/ActiveSupport is optional; preserve both
58
+ `Time.current` and plain Ruby `Time.now` behavior without adding a Rails runtime
59
+ dependency for convenience.
60
+ - A support-policy change must align the gemspec, Dockerfile, Gemfile/lockfile,
61
+ RuboCop target, CI matrix/coverage reporting, README, and this guide.
62
+ Keep the Dockerfile's Bundler version compatible with Ruby and aligned with
63
+ the lockfile's `BUNDLED WITH` version.
64
+ Validate specs, lint, and gem build even if no `.rb` file changes.
65
+
66
+ ## Redis and development environment
67
+
68
+ - Use the Compose `ruby` service for development and the `redis` service for
69
+ tests. Follow the setup and commands in [CONTRIBUTING.md](CONTRIBUTING.md#development).
70
+ - Specs use real Redis at the hard-coded `redis:6379` address and call `flushdb`
71
+ after every example. Use only the disposable Redis belonging to this checkout;
72
+ never point that hostname at shared or production data. Do not assume setting
73
+ `REDIS_URL` redirects this test suite.
74
+ - Compose does not publish Redis to a host port. For parallel checkouts, set a
75
+ distinct `COMPOSE_PROJECT_NAME` in each checkout's shell before any Compose
76
+ commands and keep it for setup, tests, and cleanup. Project names isolate the
77
+ Redis service, default network, and bundle volume; do not override them with
78
+ shared resource names or connect another project's Redis to the test network.
79
+ Use `docker compose exec redis redis-cli` for an interactive Redis client.
80
+ - Use `bundle exec` for project tools. After dependency changes, rebuild the
81
+ image and run `bundle install` in the mounted service so the bundle volume
82
+ matches the lockfile. Avoid an unrelated `bundle update`.
83
+ - Prefer `docker compose down` for cleanup. Volume deletion is unnecessary for
84
+ routine development. Do not invoke `rake release` as a validation command.
85
+
86
+ ## Validation and code review
87
+
88
+ - For behavior changes, run focused specs first, then the full suite against
89
+ disposable Redis. Add regression coverage for the changed contract.
90
+ - For shared interval/type changes, check affected combinations across all six
91
+ periods and four object types. Preserve persisted key formats, week/year
92
+ boundaries, time-zone selection, expiration options, range boundaries,
93
+ missing/empty values, aggregation, and standard `Redis::Objects` behavior
94
+ unless the requested change explicitly alters them.
95
+ - Freeze or travel time with Timecop in specs; test boundaries deterministically
96
+ rather than sleeping. Existing cleanup restores Timecop after each example.
97
+ - Run RuboCop for Ruby, gemspec, Gemfile, Rakefile, or lint configuration changes.
98
+ Use configured cops as the style authority; avoid mass autocorrection or
99
+ regenerating `.rubocop_todo.yml` to conceal new offenses.
100
+ - Run `bundle exec rake build` through Compose for packaging/dependency changes;
101
+ use `bundle exec yardoc` for documentation-comment changes. The gemspec packages
102
+ Git-tracked files, so check the tracked file list when adding packaged sources.
103
+ - For Markdown-only changes, check paths, commands, examples, and
104
+ `git diff --check`; application specs/lint are unnecessary unless the task also
105
+ requires validating the documented runtime procedure.
106
+ - If validation is blocked, state the command and reason. Do not present static
107
+ checks or one local Ruby run as a successful CI compatibility matrix.
108
+ - Validate workflow changes with actionlint and zizmor. Keep Actions SHA-pinned,
109
+ routine jobs read-only, and publishing free of restored dependency caches.
110
+
111
+ ## Documentation, pull requests, and releases
112
+
113
+ - Keep the English `README.md` as the public entry point; detailed usage belongs
114
+ in `docs/usage.md`, contributor procedures in `CONTRIBUTING.md`, and maintainer
115
+ procedures in `docs/maintaining.md`. Do not create language-specific README
116
+ copies. Track unresolved work in GitHub Issues and keep agent workflow here.
117
+ - When updating examples, check method names, arguments, key formats, return
118
+ values, and consistency with specs. Resolve references when renaming/removing
119
+ documentation.
120
+ - Write PR titles and descriptions in English. Include `Purpose of this change`
121
+ and relevant verification results. Supply Markdown bodies through structured
122
+ tool arguments or a temporary file with `gh --body-file` to avoid shell
123
+ interpretation of backticks and other Markdown content.
124
+ - Compile `CHANGELOG.md` at release time rather than editing it in every PR.
125
+ Follow existing release formatting and `-` bullets; categorize entries as
126
+ Feature, Bugfix, Security, Breaking Change, Rubocop Challenge, Dependabot, or
127
+ Misc as applicable, omitting empty sections. Reserve Breaking Change for
128
+ backward-incompatible behavior and combine repeated dependency bumps.
129
+ - Releases require an explicit release task. The publisher uses the `release`
130
+ branch; pushing there or running `rake release` is not routine development.
131
+ Keep version changes, tags, and publishing within that scope. During migration,
132
+ stop the corresponding CircleCI writer before activating Actions publication
133
+ or scheduled writes; follow the maintainer guide cutover and rollback checklist.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,92 @@
1
1
  # Change log
2
2
 
3
+ ## v0.8.0 (Oct 29, 2026)
4
+
5
+ ### Bugfix
6
+
7
+ - [#264](https://github.com/ryz310/redis-objects-periodical/pull/264) Fix weekly keys for weeks spanning a year boundary across counters, values, sets, and hashes. ([@ashimomura](https://github.com/ashimomura))
8
+
9
+ ### Breaking Change
10
+
11
+ - [#291](https://github.com/ryz310/redis-objects-periodical/pull/291) Require Ruby 3.3 or newer; drop Ruby 2.7, 3.0, 3.1, and 3.2 support and test Ruby 3.3, 3.4, and 4.0. Applications on older Ruby versions must upgrade Ruby or remain on a compatible gem release. ([@ryz310](https://github.com/ryz310))
12
+ - [#264](https://github.com/ryz310/redis-objects-periodical/pull/264) Derive weekly keys from the Monday of the requested week. For example, January 1, 2022 now uses `2021W52` instead of `2022W00`. Existing January `W00` data is not migrated and affected accessors will select the preceding December key after upgrading. Assess retained weekly data and any application-specific migration before deployment. The keys still use `%Y`/`%W`, not ISO week-year numbering. ([@ashimomura](https://github.com/ashimomura))
13
+
14
+ ### Rubocop Challenge
15
+
16
+ - [#192](https://github.com/ryz310/redis-objects-periodical/pull/192) Apply Layout/ExtraSpacing and Performance/StringIdentifierArgument corrections. ([@ryz310](https://github.com/ryz310))
17
+
18
+ ### Dependabot
19
+
20
+ - [#288](https://github.com/ryz310/redis-objects-periodical/pull/288) Bump rubocop from 1.76.2 to 1.92.1 ([@ryz310](https://github.com/ryz310))
21
+ - [#277](https://github.com/ryz310/redis-objects-periodical/pull/277) Bump rubocop-rspec from 3.6.0 to 3.10.2 ([@ryz310](https://github.com/ryz310))
22
+ - [#281](https://github.com/ryz310/redis-objects-periodical/pull/281) Bump yard from 0.9.37 to 0.9.45 ([@ryz310](https://github.com/ryz310))
23
+ - [#289](https://github.com/ryz310/redis-objects-periodical/pull/289) Bump rubocop-performance from 1.25.0 to 1.27.0 ([@ryz310](https://github.com/ryz310))
24
+ - [#270](https://github.com/ryz310/redis-objects-periodical/pull/270) Bump timecop from 0.9.10 to 0.9.11 ([@ryz310](https://github.com/ryz310))
25
+ - [#268](https://github.com/ryz310/redis-objects-periodical/pull/268) Bump rake from 13.3.0 to 13.4.2 ([@ryz310](https://github.com/ryz310))
26
+ - [#273](https://github.com/ryz310/redis-objects-periodical/pull/273) Bump rspec from 3.13.1 to 3.13.2 ([@ryz310](https://github.com/ryz310))
27
+ - [#286](https://github.com/ryz310/redis-objects-periodical/pull/286) Bump actions/checkout from 6.1.0 to 7.0.1 ([@ryz310](https://github.com/ryz310))
28
+ - [#310](https://github.com/ryz310/redis-objects-periodical/pull/310) Bump rspec_junit_formatter from 0.6.2 to 0.8.0 ([@ryz310](https://github.com/ryz310))
29
+ - [#311](https://github.com/ryz310/redis-objects-periodical/pull/311) Bump simplecov from 0.22.0 to 1.3.2 ([@ryz310](https://github.com/ryz310))
30
+ - [#293](https://github.com/ryz310/redis-objects-periodical/pull/293) Bump dependabot/fetch-metadata from 3.0.0 to 3.1.0 ([@ryz310](https://github.com/ryz310))
31
+ - [#294](https://github.com/ryz310/redis-objects-periodical/pull/294) Bump actions/github-script from 8.0.0 to 9.0.0 ([@ryz310](https://github.com/ryz310))
32
+
33
+ ### Misc
34
+
35
+ - [#283](https://github.com/ryz310/redis-objects-periodical/pull/283) Restore CI while retiring unavailable Code Climate reporting. ([@ryz310](https://github.com/ryz310))
36
+ - [#284](https://github.com/ryz310/redis-objects-periodical/pull/284) Migrate combined SimpleCov coverage reporting to Qlty. ([@ryz310](https://github.com/ryz310))
37
+ - [#282](https://github.com/ryz310/redis-objects-periodical/pull/282) Add agent guidance and repair the Docker development setup. ([@ryz310](https://github.com/ryz310))
38
+ - [#285](https://github.com/ryz310/redis-objects-periodical/pull/285) Migrate CI, release publishing, and scheduled maintenance from CircleCI to SHA-pinned GitHub Actions; document external cutover and rollback requirements. ([@ryz310](https://github.com/ryz310))
39
+ - [#290](https://github.com/ryz310/redis-objects-periodical/pull/290) Add guarded Dependabot auto-merge and isolated ActiveSupport timezone verification; retain plain-Ruby coverage and optional ActiveSupport support. ([@ryz310](https://github.com/ryz310))
40
+ - [#304](https://github.com/ryz310/redis-objects-periodical/pull/304) Reconcile workflow-owned auto-merge reservations on rejection and guard the clean-status merge fallback. ([@ryz310](https://github.com/ryz310))
41
+ - [#305](https://github.com/ryz310/redis-objects-periodical/pull/305) Correct Actions ecosystem metadata matching for Dependabot policy. ([@ryz310](https://github.com/ryz310))
42
+ - [#301](https://github.com/ryz310/redis-objects-periodical/pull/301) Allow isolated Compose projects to run concurrently without publishing the Redis host port. ([@ryz310](https://github.com/ryz310))
43
+ - [#303](https://github.com/ryz310/redis-objects-periodical/pull/303) Pin development Redis to the immutable CI image digest. ([@ryz310](https://github.com/ryz310))
44
+ - [#302](https://github.com/ryz310/redis-objects-periodical/pull/302) Fail timezone CI when expected integration examples are missing, duplicated, unexpected, or pending. ([@ryz310](https://github.com/ryz310))
45
+ - [#306](https://github.com/ryz310/redis-objects-periodical/pull/306) Separate public usage, contributor, maintainer, and dated verification documentation. ([@ryz310](https://github.com/ryz310))
46
+ - [#308](https://github.com/ryz310/redis-objects-periodical/pull/308) Remove the additional Dependabot auto-merge enable variable. ([@ryz310](https://github.com/ryz310))
47
+ - [#309](https://github.com/ryz310/redis-objects-periodical/pull/309) Manage optional ActiveSupport dependencies across both lockfiles with Dependabot. ([@ryz310](https://github.com/ryz310))
48
+ - [#313](https://github.com/ryz310/redis-objects-periodical/pull/313) Add a repository-local Dependabot batch-maintenance skill. ([@ryz310](https://github.com/ryz310))
49
+
50
+ ## v0.7.0 (Feb 12, 2023)
51
+
52
+ ### Feature
53
+
54
+ - [#128](https://github.com/ryz310/redis-object-daily-counter/pull/128) Support`Redis::Value` as a periodical object ([@ryz310](https://github.com/ryz310))
55
+
56
+ > The periodical values automatically switches the save destination when the date changes.
57
+ >
58
+ > ```rb
59
+ > class Homepage
60
+ > include Redis::Objects
61
+ >
62
+ > daily_value :cache, expireat: -> { Time.now + 2_678_400 } # about a month
63
+ >
64
+ > def id
65
+ > 1
66
+ > end
67
+ > end
68
+ >
69
+ > homepage = Homepage.new
70
+ >
71
+ > # 2021-04-01
72
+ > homepage.cache.value = 'a'
73
+ >
74
+ > # 2021-04-02 (next day)
75
+ > homepage.cache.value = 'b'
76
+ >
77
+ > # 2021-04-03 (next day)
78
+ > homepage.cache.value = 'c'
79
+ >
80
+ > homepage.cache[Date.new(2021, 4, 1)] # => 'a'
81
+ > homepage.cache[Date.new(2021, 4, 1), 3] # => ['a', 'b', 'c']
82
+ > homepage.cache[Date.new(2021, 4, 1)..Date.new(2021, 4, 2)] # => ['a', 'b']
83
+ >
84
+ > homepage.cache.delete_at(Date.new(2021, 4, 1))
85
+ > homepage.cache.range(Date.new(2021, 4, 1), Date.new(2021, 4, 3)) # => [nil, 'b', 'c']
86
+ > homepage.cache.at(Date.new(2021, 4, 2)) # => #<Redis::Value key="homepage:1:cache:2021-04-02">
87
+ > homepage.cache.at(Date.new(2021, 4, 2)).value # 'b'
88
+ > ```
89
+
3
90
  ## v0.6.0 (Feb 12, 2023)
4
91
 
5
92
  ### Feature