Pack calendar definitions into per-year integers - #31
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Wareki::Calendar packs each year's lunisolar calendar data into a single 40-bit integer, replacing the Struct-based YEAR_DEFS lookup with a bootstrap that repacks the existing table. Later tasks will swap the bootstrap for generated data. Also grandfathers spec/calendar_spec.rb into the existing RSpec/SpecFilePathFormat todo list, following the precedent already set for the other top-level spec files describing namespaced constants. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Switch common.rb, utils.rb, and date.rb to use the Wareki::Calendar API instead of the raw YEAR_DEFS table, and remove the now-unused Utils.find_year and YEAR_BY_NUM. Behavior is unchanged; spec/utils_spec.rb is updated to exercise find_date_ary and Calendar::PACKED instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Rewrite build-util/gen-jp-cal-def.rb to emit the new bit-packed Wareki::Calendar constants (YEAR_MIN/YEAR_MAX/JD_MIN/JD_MAX/ LAST_MONTH_DAYS/PACKED) directly instead of the old Struct-based YEAR_DEFS. Replace lib/wareki/calendar_def.rb with the generator's output (verified byte-identical to the previous bootstrap-derived values) and drop the temporary bootstrap block from calendar.rb. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Record the bit-packed kyuureki calendar table (Tasks 1-4) in the ChangeLog and bump VERSION to 2.1.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
Replace the dangling Wareki::YEAR_DEFS reference in the era_def generator with Wareki::Calendar.find_date_ary. The old expression (y.end > jd) assigned an era starting on the last day of a lunisolar year to the following year; the new one returns the containing year, which is the intended semantics. Also align the ChangeLog load-time claim with measurements (~30x) and gitignore the kyuureki-map.txt data source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
…r-def # Conflicts: # build-util/parse_wikipedia.rb
PR #30's gen-era-def.rb landed on master referencing Wareki::YEAR_DEFS, which this branch removes. Replace meiji_start's struct lookup with Wareki::Calendar.to_jd(1868, 1, 1) (verified equal to the old value, JD 2403357) and load the repo's lib via $LOAD_PATH instead of require_relative so the in-tree code wins over any installed wareki gem. Regenerated output verified byte-identical to the committed era_def.rb. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
There was a problem hiding this comment.
Code Review
This pull request replaces the large in-memory kyuureki calendar table with a highly efficient bit-packed integer representation in a new internal module Wareki::Calendar, reducing memory usage and significantly speeding up load times. It also raises the required Ruby version to 2.3.0 to utilize Array#bsearch_index and cleans up deprecated internal constants and methods. The review feedback recommends enhancing the robustness of the new Wareki::Calendar module by replacing non-intuitive and operators with standard if modifiers, adding input validation to month_index to handle invalid months or mismatched leap flags, and adding corresponding nil guards in last_day_of_month and to_jd.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR refactors Wareki’s internal kyuureki (lunisolar) calendar table representation from object-heavy year definitions to a compact per-year 40-bit packed integer array, reducing memory usage and improving load time, while also raising the minimum supported Ruby version and bumping the gem version.
Changes:
- Introduce
Wareki::Calendarwith bit-packed calendar lookup APIs and add comprehensive boundary/roundtrip specs. - Migrate existing consumers (
Wareki::Date,Wareki::Utils, era generator) off the removed internal year-definition APIs. - Raise
required_ruby_versionto>= 2.3.0and bump version/ChangeLog for release2.1.0.
Reviewed changes
Copilot reviewed 14 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| wareki.gemspec | Raises minimum supported Ruby version to 2.3.0. |
| .rubocop.yml | Updates Ruby-version-related RuboCop comments/config. |
| .rubocop_todo.yml | Excludes the new spec/calendar_spec.rb from a path-format cop. |
| .gitignore | Ignores kyuureki-map.txt to prevent accidental commits. |
| lib/wareki/common.rb | Switches calendar loading from calendar_def to calendar and removes YEAR_BY_NUM. |
| lib/wareki/calendar.rb | Adds the packed-calendar lookup API surface (covers_*, to_jd, find_date_ary, etc.). |
| lib/wareki/calendar_def.rb | Replaces old year structs with generated packed integer table + constants. |
| lib/wareki/utils.rb | Routes lunisolar lookups through Wareki::Calendar and removes find_year. |
| lib/wareki/date.rb | Replaces direct year-table access with Wareki::Calendar APIs for indexing/validation/JD conversion. |
| build-util/gen-jp-cal-def.rb | Rewrites generator to emit packed integer calendar definitions with invariants. |
| build-util/gen-era-def.rb | Updates Meiji start computation to use Wareki::Calendar.to_jd and ensures repo lib is loaded. |
| spec/utils_spec.rb | Updates specs to use find_date_ary and checks packed definitions are frozen. |
| spec/calendar_spec.rb | Adds coverage for packed calendar constants, boundaries, leap months, and full-table roundtrip. |
| lib/wareki/version.rb | Bumps gem version from 2.0.0 to 2.1.0. |
| ChangeLog | Adds 2.1.0 release notes for the packed-calendar migration and Ruby requirement bump. |
| docs/superpowers/plans/2026-07-13-packed-calendar-def.md | Adds an implementation plan/reference document for the migration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
The method lost its indirect coverage when _validate_date! and #jd switched to Wareki::Calendar internally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK
|
[ClaudeCode] The -0.4% drop was |
概要
旧暦カレンダーテーブルの内部表現を「1年 = 整数1個 (40bit bit-pack)」に全面刷新し、メモリ消費とロード時間を大幅に削減します。あわせて required_ruby_version を 2.3 に引き上げます。
ビットレイアウト (
Wareki::Calendar::PACKED[西暦年 - YEAR_MIN])明治5年12月 (グレゴリオ切替で2日打ち切り) のみ
LAST_MONTH_DAYS定数で特別扱い。効果 (Ruby 2.7.8 実測)
演算スループットは同等〜微増 (ホットパスは全 JD 域 521,542 日の roundtrip spec で担保)。
削除した API (互換なし・意図的)
Wareki::YEAR_DEFS/Wareki::YEAR_BY_NUM/Wareki::Year/Wareki::Utils.find_year。いずれも README 非記載の事実上内部 API のため 2.1.0 のマイナーバンプとし、ChangeLog に削除を明記しています。検証
build-util/gen-jp-cal-def.rb(invariant チェック 8 種付き) の出力が移行用ブートストラップ値と Marshal 完全一致、再実行でバイト一致再現spec/calendar_spec.rb追加: 境界 (JD_MIN/JD_MAX/年境界/閏月/明治5年12月) + 全域 roundtrip備考
build-util/gen-era-def.rbも新 API に追随 (meiji_start の等価性 JD 2403357 を検証、再生成出力がコミット済み era_def.rb とバイト一致)kyuureki-map.txtを .gitignore に追加 (再生成手順のフットガン防止)🤖 Generated with Claude Code
https://claude.ai/code/session_019zprNf9ALwJ5UgyB4hf3cK