fasti 1.0.0 → 1.0.1
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/CHANGELOG.md +5 -0
- data/README.md +8 -2
- data/lib/fasti/version.rb +1 -1
- metadata +6 -24
- data/.mcp.json +0 -19
- data/.rspec +0 -3
- data/.rubocop.yml +0 -82
- data/.rubocop_todo.yml +0 -89
- data/.serena/project.yml +0 -68
- data/.simplecov +0 -31
- data/.yardopts +0 -9
- data/AGENTS.md +0 -60
- data/CLAUDE.md +0 -1
- data/RELEASING.md +0 -202
- data/Rakefile +0 -34
- data/TODO.md +0 -11
- data/benchmark/holiday_cache_benchmark.rb +0 -111
- data/benchmark/memory_benchmark.rb +0 -86
- data/docs/agents/git-pr.md +0 -298
- data/docs/agents/languages.md +0 -388
- data/docs/agents/rubocop.md +0 -55
- data/docs/plans/positional-arguments.md +0 -303
- data/docs/plans/structured-config.md +0 -232
- data/examples/config.rb +0 -80
- data/mise.toml +0 -5
data/RELEASING.md
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
# Releasing
|
|
2
|
-
|
|
3
|
-
This document describes the release process for Ruby gems used in this project, which is fully automated through GitHub Actions workflows.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The release process consists of three automated workflows:
|
|
8
|
-
|
|
9
|
-
1. **Release Preparation** - Creates a release branch with version updates
|
|
10
|
-
2. **Release Validation** - Validates the release branch on PR creation
|
|
11
|
-
3. **Release Publish** - Publishes the gem after PR merge
|
|
12
|
-
|
|
13
|
-
## Prerequisites
|
|
14
|
-
|
|
15
|
-
Before initiating a release, ensure:
|
|
16
|
-
|
|
17
|
-
- [ ] All desired features and fixes are merged to `main`
|
|
18
|
-
- [ ] CI is passing on `main` branch
|
|
19
|
-
- [ ] `CHANGELOG.md` has entries under `## [Unreleased]` section
|
|
20
|
-
- [ ] `RUBYGEMS_API_KEY` secret is configured in repository settings
|
|
21
|
-
|
|
22
|
-
## Release Process
|
|
23
|
-
|
|
24
|
-
### Step 1: Initiate Release
|
|
25
|
-
|
|
26
|
-
1. Go to the [Actions tab](../../actions) in the GitHub repository
|
|
27
|
-
2. Select "Release Preparation" workflow
|
|
28
|
-
3. Click "Run workflow"
|
|
29
|
-
4. Enter the version number (e.g., `1.0.0`)
|
|
30
|
-
5. Click "Run workflow"
|
|
31
|
-
|
|
32
|
-
The workflow will automatically:
|
|
33
|
-
- Create a new branch `release-v{version}`
|
|
34
|
-
- Update `lib/[gem_name]/version.rb` with the new version
|
|
35
|
-
- Update `CHANGELOG.md`:
|
|
36
|
-
- Replace `## [Unreleased]` with `## [{version}] - {date}`
|
|
37
|
-
- Add a new `## [Unreleased]` section for future changes
|
|
38
|
-
- Create a git tag `v{version}` on the release branch
|
|
39
|
-
- Push the branch and tag to GitHub
|
|
40
|
-
- Create a Pull Request to `main`
|
|
41
|
-
|
|
42
|
-
### Step 2: Review and Merge
|
|
43
|
-
|
|
44
|
-
Once the PR is created, the Release Validation workflow automatically:
|
|
45
|
-
- Validates version format (must be `x.y.z`)
|
|
46
|
-
- Verifies version consistency between branch name and `version.rb`
|
|
47
|
-
- Checks that the git tag doesn't already exist (or can be updated)
|
|
48
|
-
- Confirms the version isn't already published on RubyGems
|
|
49
|
-
- Verifies `RUBYGEMS_API_KEY` secret is configured
|
|
50
|
-
- Validates `CHANGELOG.md` has an entry for this version
|
|
51
|
-
|
|
52
|
-
**Note**: Quality checks (tests and RuboCop) are handled by the CI workflow to avoid duplication.
|
|
53
|
-
|
|
54
|
-
**Important**: If you push additional commits to the release PR (e.g., bug fixes, workflow updates, documentation changes):
|
|
55
|
-
- The validation workflow automatically moves the release tag to the latest commit
|
|
56
|
-
- This ensures the tag always points to the final reviewed code
|
|
57
|
-
- No manual intervention required
|
|
58
|
-
- All changes will be included in the final release
|
|
59
|
-
|
|
60
|
-
If all checks pass, merge the PR.
|
|
61
|
-
|
|
62
|
-
### Step 3: Automatic Publishing
|
|
63
|
-
|
|
64
|
-
After the PR is merged, the Release Publish workflow automatically:
|
|
65
|
-
- Checks out the exact git tag created on the release branch
|
|
66
|
-
- Builds the gem from the tagged commit
|
|
67
|
-
- Publishes the gem to RubyGems
|
|
68
|
-
- Creates a GitHub Release with:
|
|
69
|
-
- Release notes extracted from `CHANGELOG.md`
|
|
70
|
-
- The built gem file as an attachment
|
|
71
|
-
- Cleans up the release branch
|
|
72
|
-
|
|
73
|
-
## Workflow Architecture
|
|
74
|
-
|
|
75
|
-
### Key Design Decisions
|
|
76
|
-
|
|
77
|
-
#### Tag-Based Deployment
|
|
78
|
-
|
|
79
|
-
The release workflow uses a **tag-based deployment strategy** to ensure the released gem contains exactly the code that was reviewed and approved in the release PR, without any subsequent changes from `main`.
|
|
80
|
-
|
|
81
|
-
```mermaid
|
|
82
|
-
graph LR
|
|
83
|
-
A[main branch] -->|Create release branch| B[release-v1.0.0]
|
|
84
|
-
B -->|Update version & tag| C[Tagged: v1.0.0]
|
|
85
|
-
B -->|Create PR| D[Pull Request]
|
|
86
|
-
A -->|Other PRs merged| E[main with new commits]
|
|
87
|
-
D -->|Merge PR| E
|
|
88
|
-
C -->|Checkout tag| F[Build & Publish gem]
|
|
89
|
-
F -->|Contains only| G[Code from release branch]
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
#### Automatic Tag Movement
|
|
93
|
-
|
|
94
|
-
When additional commits are pushed to a release PR, the tag automatically moves to the latest commit:
|
|
95
|
-
|
|
96
|
-
```mermaid
|
|
97
|
-
graph LR
|
|
98
|
-
A[Initial commit] -->|Tag v1.0.0| B[Tagged commit]
|
|
99
|
-
B -->|Fix typo| C[New commit]
|
|
100
|
-
C -->|Auto-move tag| D[Tag v1.0.0 on latest]
|
|
101
|
-
D -->|Final review| E[Ready to merge]
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
This ensures:
|
|
105
|
-
- The tag always points to the final reviewed code
|
|
106
|
-
- No manual tag management required
|
|
107
|
-
- The published gem matches exactly what was approved
|
|
108
|
-
|
|
109
|
-
## Manual Release (Emergency Only)
|
|
110
|
-
|
|
111
|
-
If automation fails, you can release manually using our tag-based strategy:
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
# 1. Create release branch
|
|
115
|
-
git checkout -b release-v1.0.0
|
|
116
|
-
|
|
117
|
-
# 2. Update version
|
|
118
|
-
vim lib/[gem_name]/version.rb
|
|
119
|
-
|
|
120
|
-
# 3. Update CHANGELOG (move content from [Unreleased] to [1.0.0])
|
|
121
|
-
vim CHANGELOG.md
|
|
122
|
-
|
|
123
|
-
# 4. Commit changes and create tag
|
|
124
|
-
git add -A
|
|
125
|
-
git commit -m ":bookmark: Release v1.0.0"
|
|
126
|
-
git tag -a v1.0.0 -m "Release v1.0.0"
|
|
127
|
-
|
|
128
|
-
# 5. Push release branch and tag
|
|
129
|
-
git push origin release-v1.0.0
|
|
130
|
-
git push origin v1.0.0
|
|
131
|
-
|
|
132
|
-
# 6. Create PR and merge after review
|
|
133
|
-
gh pr create --title "Release v1.0.0" --body "Release v1.0.0"
|
|
134
|
-
# (Review and merge PR)
|
|
135
|
-
|
|
136
|
-
# 7. Checkout the tag and build gem
|
|
137
|
-
git checkout v1.0.0
|
|
138
|
-
bundle exec rake build
|
|
139
|
-
|
|
140
|
-
# 8. Push to RubyGems
|
|
141
|
-
gem push pkg/[gem_name]-1.0.0.gem
|
|
142
|
-
|
|
143
|
-
# 9. Create GitHub release
|
|
144
|
-
gh release create v1.0.0 --title "[gem_name] v1.0.0" --generate-notes pkg/[gem_name]-1.0.0.gem
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Troubleshooting
|
|
148
|
-
|
|
149
|
-
### Release Validation Fails
|
|
150
|
-
|
|
151
|
-
**Version already exists on RubyGems**
|
|
152
|
-
- Solution: Increment the version number and try again
|
|
153
|
-
|
|
154
|
-
**RUBYGEMS_API_KEY not configured**
|
|
155
|
-
1. Generate an API key at https://rubygems.org/profile/edit
|
|
156
|
-
2. Go to repository Settings → Secrets and variables → Actions
|
|
157
|
-
3. Add new secret: `RUBYGEMS_API_KEY` with your API key
|
|
158
|
-
|
|
159
|
-
**Tests or RuboCop failing**
|
|
160
|
-
- These are checked by the CI workflow, not in release validation
|
|
161
|
-
- Fix the issues on the release branch or `main` as appropriate
|
|
162
|
-
- Release validation focuses on version consistency and format
|
|
163
|
-
|
|
164
|
-
### Release Publish Fails
|
|
165
|
-
|
|
166
|
-
**Tag not found**
|
|
167
|
-
- The release preparation workflow may have failed to create the tag
|
|
168
|
-
- Check if the tag exists: `git tag | grep v1.0.0`
|
|
169
|
-
- If missing, the release validation workflow will recreate it on PR updates
|
|
170
|
-
- For manual fix: create tag on release branch with `git tag -a v1.0.0 -m "Release v1.0.0"`
|
|
171
|
-
|
|
172
|
-
**Gem push fails**
|
|
173
|
-
- Verify RubyGems API key is valid
|
|
174
|
-
- Check if you have push permissions for the gem
|
|
175
|
-
- Ensure the version doesn't already exist on RubyGems
|
|
176
|
-
|
|
177
|
-
## Version Numbering
|
|
178
|
-
|
|
179
|
-
Follow [Semantic Versioning](https://semver.org/):
|
|
180
|
-
|
|
181
|
-
- **MAJOR** version for incompatible API changes
|
|
182
|
-
- **MINOR** version for backwards-compatible functionality additions
|
|
183
|
-
- **PATCH** version for backwards-compatible bug fixes
|
|
184
|
-
|
|
185
|
-
Examples:
|
|
186
|
-
- `0.1.0` → `0.1.1`: Bug fixes only
|
|
187
|
-
- `0.1.1` → `0.2.0`: New features added
|
|
188
|
-
- `0.2.0` → `1.0.0`: Breaking changes or stable release
|
|
189
|
-
|
|
190
|
-
## Workflow Files
|
|
191
|
-
|
|
192
|
-
The release automation is implemented in:
|
|
193
|
-
|
|
194
|
-
- `.github/workflows/release-preparation.yml` - Creates release branch and PR
|
|
195
|
-
- `.github/workflows/release-validation.yml` - Validates release PR
|
|
196
|
-
- `.github/workflows/release-publish.yml` - Publishes gem after merge
|
|
197
|
-
|
|
198
|
-
## Security Notes
|
|
199
|
-
|
|
200
|
-
- The `RUBYGEMS_API_KEY` secret is only accessible to workflows running on the default branch
|
|
201
|
-
- Release branches are automatically deleted after successful release
|
|
202
|
-
- All releases are tagged for audit trail and rollback capability
|
data/Rakefile
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "bundler/gem_tasks"
|
|
4
|
-
|
|
5
|
-
require "rake/clean"
|
|
6
|
-
CLEAN.include("coverage", ".rspec_status", ".yardoc")
|
|
7
|
-
CLOBBER.include("docs/api", "pkg")
|
|
8
|
-
|
|
9
|
-
require "rspec/core/rake_task"
|
|
10
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
11
|
-
|
|
12
|
-
require "rubocop/rake_task"
|
|
13
|
-
RuboCop::RakeTask.new
|
|
14
|
-
|
|
15
|
-
require "gemoji"
|
|
16
|
-
require "yard"
|
|
17
|
-
YARD::Rake::YardocTask.new(:doc)
|
|
18
|
-
Rake::Task[:doc].enhance do
|
|
19
|
-
# Convert GitHub emoji shortcodes to actual emojis in generated HTML
|
|
20
|
-
Dir["docs/api/**/*.html"].each do |file|
|
|
21
|
-
content = File.read(file)
|
|
22
|
-
|
|
23
|
-
# Replace :emoji_name: patterns with actual unicode emojis
|
|
24
|
-
content.gsub!(/:([a-z0-9+\-_]+):/) do |match|
|
|
25
|
-
alias_name = $1
|
|
26
|
-
emoji = Emoji.find_by_alias(alias_name)
|
|
27
|
-
emoji ? emoji.raw : match # Keep original if emoji not found
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
File.write(file, content)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
task default: %i[spec rubocop]
|
data/TODO.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# TODO
|
|
2
|
-
|
|
3
|
-
**Tasks were previously managed in this file, but have been migrated to GitHub Issues for better tracking and collaboration.**
|
|
4
|
-
|
|
5
|
-
## Quick Links
|
|
6
|
-
- [Open Issues](https://github.com/sakuro/fasti/issues)
|
|
7
|
-
- [Current Milestone](https://github.com/sakuro/fasti/milestones)
|
|
8
|
-
- [All Milestones](https://github.com/sakuro/fasti/milestones?state=closed)
|
|
9
|
-
- [Project Board](https://github.com/sakuro/fasti/projects) (planned)
|
|
10
|
-
|
|
11
|
-
For ongoing maintenance guidelines, see the [AI Development Guide](CLAUDE.md).
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "benchmark"
|
|
5
|
-
require "bundler/setup"
|
|
6
|
-
require "fasti"
|
|
7
|
-
|
|
8
|
-
# Temporary class to simulate old behavior without caching
|
|
9
|
-
class LegacyCalendar < Fasti::Calendar
|
|
10
|
-
# Override to disable caching for benchmark comparison
|
|
11
|
-
def holiday?(day)
|
|
12
|
-
date = to_date(day)
|
|
13
|
-
return false unless date
|
|
14
|
-
|
|
15
|
-
begin
|
|
16
|
-
Holidays.on(date, country).any?
|
|
17
|
-
rescue Holidays::InvalidRegion, StandardError
|
|
18
|
-
false
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Benchmarks month display performance by checking holidays for all days in a month
|
|
24
|
-
def benchmark_month_display(calendar_class, year, month, country, iterations=100)
|
|
25
|
-
calendar = calendar_class.new(year, month, country:)
|
|
26
|
-
|
|
27
|
-
Benchmark.realtime do
|
|
28
|
-
iterations.times do
|
|
29
|
-
# Simulate checking all days in the month (like formatter does)
|
|
30
|
-
(1..calendar.days_in_month).each do |day|
|
|
31
|
-
calendar.holiday?(day)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Benchmarks year display performance by checking holidays for all days in all months
|
|
38
|
-
def benchmark_year_display(calendar_class, year, country, iterations=10)
|
|
39
|
-
Benchmark.realtime do
|
|
40
|
-
iterations.times do
|
|
41
|
-
(1..12).each do |month|
|
|
42
|
-
calendar = calendar_class.new(year, month, country:)
|
|
43
|
-
(1..calendar.days_in_month).each do |day|
|
|
44
|
-
calendar.holiday?(day)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Formats benchmark time results in appropriate units (μs/ms/s)
|
|
52
|
-
def format_time(seconds)
|
|
53
|
-
if seconds < 0.001
|
|
54
|
-
"#{(seconds * 1_000_000).round(2)}μs"
|
|
55
|
-
elsif seconds < 1
|
|
56
|
-
"#{(seconds * 1000).round(2)}ms"
|
|
57
|
-
else
|
|
58
|
-
"#{seconds.round(3)}s"
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Calculates and formats performance improvement ratio between two benchmark times
|
|
63
|
-
def format_speedup(old_time, new_time)
|
|
64
|
-
return "N/A" if new_time.zero?
|
|
65
|
-
|
|
66
|
-
speedup = old_time / new_time
|
|
67
|
-
"#{speedup.round(2)}x faster"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
puts "Fasti Holiday Cache Performance Benchmark"
|
|
71
|
-
puts "=" * 50
|
|
72
|
-
puts
|
|
73
|
-
|
|
74
|
-
# Test parameters
|
|
75
|
-
YEAR = 2024
|
|
76
|
-
COUNTRIES = %i[us jp gb].freeze
|
|
77
|
-
MONTH_ITERATIONS = 100
|
|
78
|
-
YEAR_ITERATIONS = 10
|
|
79
|
-
|
|
80
|
-
COUNTRIES.each do |country|
|
|
81
|
-
puts "Country: #{country.upcase}"
|
|
82
|
-
puts "-" * 20
|
|
83
|
-
|
|
84
|
-
# Month display benchmark
|
|
85
|
-
puts "Month Display (July #{YEAR}, #{MONTH_ITERATIONS} iterations):"
|
|
86
|
-
|
|
87
|
-
legacy_month_time = benchmark_month_display(LegacyCalendar, YEAR, 7, country, MONTH_ITERATIONS)
|
|
88
|
-
cached_month_time = benchmark_month_display(Fasti::Calendar, YEAR, 7, country, MONTH_ITERATIONS)
|
|
89
|
-
|
|
90
|
-
puts " Legacy (no cache): #{format_time(legacy_month_time)}"
|
|
91
|
-
puts " Cached: #{format_time(cached_month_time)}"
|
|
92
|
-
puts " Improvement: #{format_speedup(legacy_month_time, cached_month_time)}"
|
|
93
|
-
puts
|
|
94
|
-
|
|
95
|
-
# Year display benchmark
|
|
96
|
-
puts "Year Display (#{YEAR}, #{YEAR_ITERATIONS} iterations):"
|
|
97
|
-
|
|
98
|
-
legacy_year_time = benchmark_year_display(LegacyCalendar, YEAR, country, YEAR_ITERATIONS)
|
|
99
|
-
cached_year_time = benchmark_year_display(Fasti::Calendar, YEAR, country, YEAR_ITERATIONS)
|
|
100
|
-
|
|
101
|
-
puts " Legacy (no cache): #{format_time(legacy_year_time)}"
|
|
102
|
-
puts " Cached: #{format_time(cached_year_time)}"
|
|
103
|
-
puts " Improvement: #{format_speedup(legacy_year_time, cached_year_time)}"
|
|
104
|
-
puts
|
|
105
|
-
puts
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
puts "Benchmark completed!"
|
|
109
|
-
puts
|
|
110
|
-
puts "Note: Results may vary based on network latency to holiday data sources"
|
|
111
|
-
puts "and system performance. Run multiple times for consistent results."
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "bundler/setup"
|
|
5
|
-
require "fasti"
|
|
6
|
-
|
|
7
|
-
# Simple memory measurement helper
|
|
8
|
-
def measure_memory_usage
|
|
9
|
-
# Force garbage collection to get accurate measurements
|
|
10
|
-
GC.start
|
|
11
|
-
GC.compact if GC.respond_to?(:compact)
|
|
12
|
-
|
|
13
|
-
before = GC.stat[:heap_live_slots]
|
|
14
|
-
yield
|
|
15
|
-
GC.start
|
|
16
|
-
after = GC.stat[:heap_live_slots]
|
|
17
|
-
|
|
18
|
-
after - before
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Formats memory usage in human-readable units (slots/K slots/M slots)
|
|
22
|
-
def format_memory(slots)
|
|
23
|
-
# Rough estimation: each object slot ≈ 40 bytes on 64-bit systems
|
|
24
|
-
bytes = slots * 40
|
|
25
|
-
if bytes < 1024
|
|
26
|
-
"#{bytes}B"
|
|
27
|
-
elsif bytes < 1024 * 1024
|
|
28
|
-
"#{(bytes / 1024.0).round(2)}KB"
|
|
29
|
-
else
|
|
30
|
-
"#{(bytes / (1024.0 * 1024)).round(2)}MB"
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
puts "Fasti Memory Usage Benchmark"
|
|
35
|
-
puts "=" * 40
|
|
36
|
-
puts
|
|
37
|
-
|
|
38
|
-
# Test creating calendars and checking holidays
|
|
39
|
-
YEAR = 2024
|
|
40
|
-
COUNTRIES = %i[us jp gb].freeze
|
|
41
|
-
|
|
42
|
-
COUNTRIES.each do |country|
|
|
43
|
-
puts "Country: #{country.upcase}"
|
|
44
|
-
puts "-" * 15
|
|
45
|
-
|
|
46
|
-
# Single month calendar
|
|
47
|
-
month_memory = measure_memory_usage {
|
|
48
|
-
calendar = Fasti::Calendar.new(YEAR, 7, country:)
|
|
49
|
-
(1..calendar.days_in_month).each {|day| calendar.holiday?(day) }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# Year worth of calendars (simulating year view)
|
|
53
|
-
year_memory = measure_memory_usage {
|
|
54
|
-
(1..12).each do |month|
|
|
55
|
-
calendar = Fasti::Calendar.new(YEAR, month, country:)
|
|
56
|
-
(1..calendar.days_in_month).each {|day| calendar.holiday?(day) }
|
|
57
|
-
end
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
puts " Single month: #{format_memory(month_memory)}"
|
|
61
|
-
puts " Full year: #{format_memory(year_memory)}"
|
|
62
|
-
puts
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Test cache behavior - multiple accesses to same month
|
|
66
|
-
puts "Cache Efficiency Test"
|
|
67
|
-
puts "-" * 20
|
|
68
|
-
|
|
69
|
-
cache_memory = measure_memory_usage {
|
|
70
|
-
calendar = Fasti::Calendar.new(YEAR, 7, country: :us)
|
|
71
|
-
|
|
72
|
-
# First pass - cache gets populated
|
|
73
|
-
(1..calendar.days_in_month).each {|day|
|
|
74
|
-
calendar.holiday?(day)
|
|
75
|
-
# Second pass - should use cache
|
|
76
|
-
calendar.holiday?(day)
|
|
77
|
-
|
|
78
|
-
# Third pass - still using cache
|
|
79
|
-
calendar.holiday?(day)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
puts "Triple access (cache test): #{format_memory(cache_memory)}"
|
|
84
|
-
puts
|
|
85
|
-
puts "Note: Memory measurements are approximate and may vary"
|
|
86
|
-
puts "based on Ruby version and system configuration."
|