fasti 1.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.
@@ -0,0 +1,111 @@
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."
@@ -0,0 +1,86 @@
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."
@@ -0,0 +1,298 @@
1
+ # Git Commit and Pull Request Guidelines for AI Agents
2
+
3
+ This guide helps AI agents follow the project's Git and GitHub conventions for commits, pull requests, and merges.
4
+
5
+ ## Table of Contents
6
+ - [Commit Messages](#commit-messages)
7
+ - [Branch Management](#branch-management)
8
+ - [Pull Request Creation](#pull-request-creation)
9
+ - [Pull Request Merging](#pull-request-merging)
10
+ - [Common Issues and Solutions](#common-issues-and-solutions)
11
+
12
+ ## Commit Messages
13
+
14
+ ### Format Requirements
15
+
16
+ All commit messages MUST follow this format:
17
+
18
+ ```
19
+ :emoji: Subject line in imperative mood
20
+
21
+ Detailed explanation of changes (optional)
22
+ - Bullet points for key changes
23
+ - Technical details and trade-offs
24
+
25
+ :robot: Generated with [Agent Name](http://agent.url)
26
+
27
+ Co-Authored-By: Agent Name <agent@email>
28
+ ```
29
+
30
+ **Note**: Replace `[Agent Name]`, `http://agent.url`, and `<agent@email>` with your specific AI agent information.
31
+
32
+ ### Key Rules
33
+
34
+ 1. **Always use GitHub emoji codes** (`:emoji:`), never raw Unicode emojis
35
+ 2. **Start with emoji**: The first character must be `:`
36
+ 3. **Space after emoji**: `:emoji: Subject` not `:emoji:Subject`
37
+ 4. **Imperative mood**: "Fix bug" not "Fixed bug" or "Fixes bug"
38
+ 5. **No period at end of subject**
39
+ 6. **Include AI attribution** for AI-generated commits
40
+
41
+ ### Common Emoji Codes
42
+
43
+ | Emoji | Code | Use Case |
44
+ |-------|------|----------|
45
+ | ⚡ | `:zap:` | Performance improvements |
46
+ | 🐛 | `:bug:` | Bug fixes |
47
+ | ✨ | `:sparkles:` | New features |
48
+ | 📝 | `:memo:` | Documentation |
49
+ | ♻️ | `:recycle:` | Refactoring |
50
+ | 🎨 | `:art:` | Code structure/format improvements |
51
+ | 🔧 | `:wrench:` | Configuration changes |
52
+ | ✅ | `:white_check_mark:` | Adding/updating tests |
53
+ | 🔥 | `:fire:` | Removing code/files |
54
+ | 📦 | `:package:` | Updating dependencies |
55
+
56
+ ### Commit Command Example
57
+
58
+ ```bash
59
+ git commit -m "$(cat <<'EOF'
60
+ :zap: Optimize Style#call performance with caching
61
+
62
+ Cache SGR sequences at initialization to avoid recalculation.
63
+ - 7-18x performance improvement
64
+ - 85-91% reduction in object allocations
65
+
66
+ :robot: Generated with [Agent Name](http://agent.url)
67
+
68
+ Co-Authored-By: Agent Name <agent@email>
69
+ EOF
70
+ )"
71
+ ```
72
+
73
+ **Important**: Use heredoc with single quotes (`<<'EOF'`) to preserve special characters.
74
+
75
+ ## Branch Management
76
+
77
+ ### Branch Naming Convention
78
+
79
+ ```
80
+ type/description-with-hyphens
81
+ ```
82
+
83
+ Examples:
84
+ - `feature/style-performance-optimization`
85
+ - `fix/readme-installation-instructions`
86
+ - `docs/git-pr-guidelines`
87
+ - `cleanup/remove-described-class`
88
+
89
+ ### Creating a New Branch
90
+
91
+ ```bash
92
+ git switch -c feature/your-feature-name
93
+ ```
94
+
95
+ ## Pull Request Creation
96
+
97
+ ### Using gh CLI
98
+
99
+ Always use the `gh` CLI tool for creating pull requests.
100
+
101
+ ### Basic PR Creation
102
+
103
+ ```bash
104
+ gh pr create --title ":emoji: Clear descriptive title" --body "PR description"
105
+ ```
106
+
107
+ ### PR with Complex Body
108
+
109
+ For PR bodies containing backticks or complex markdown, use command substitution with heredoc:
110
+
111
+ ```bash
112
+ gh pr create --title ":memo: Update documentation" --body "$(cat <<'EOF'
113
+ ## Summary
114
+ Brief description of changes
115
+
116
+ ## Changes
117
+ - Change 1
118
+ - Change 2
119
+
120
+ ## Before
121
+ ```ruby
122
+ old_code
123
+ ```
124
+
125
+ ## After
126
+ ```ruby
127
+ new_code
128
+ ```
129
+
130
+ :robot: Generated with [Agent Name](http://agent.url)
131
+ EOF
132
+ )"
133
+ ```
134
+
135
+ ### PR Title Format
136
+
137
+ - Must start with GitHub emoji code (same as commits)
138
+ - Clear, descriptive title
139
+ - Example: `:zap: Optimize Style#call performance with SGR caching`
140
+
141
+ ## Pull Request Merging
142
+
143
+ ### Merge Command Format
144
+
145
+ Use merge commits (not squash) with custom messages:
146
+
147
+ ```bash
148
+ gh pr merge PR_NUMBER --merge \
149
+ --subject ":inbox_tray: :emoji: Merge pull request #PR from branch" \
150
+ --body "Brief description of what was merged"
151
+ ```
152
+
153
+ ### Merge Commit Convention
154
+
155
+ The merge commit automatically gets `:inbox_tray:` prefix, so the format is:
156
+
157
+ ```
158
+ :inbox_tray: :original_emoji: Merge pull request #N from user/branch
159
+ ```
160
+
161
+ Example:
162
+ ```bash
163
+ gh pr merge 6 --merge \
164
+ --subject ":inbox_tray: :zap: Merge pull request #6 from sakuro/feature/style-performance-optimization" \
165
+ --body "Style#call performance optimization with SGR caching"
166
+ ```
167
+
168
+ ## Common Issues and Solutions
169
+
170
+ ### Issue: Commit Hook Rejects Message
171
+
172
+ **Error**: "Commit message must start with a GitHub :emoji:"
173
+
174
+ **Solution**: Ensure your commit message starts with `:emoji_code:` (colon on both sides)
175
+
176
+ ### Issue: Raw Emoji in Commit
177
+
178
+ **Error**: "Commit message contains raw emojis"
179
+
180
+ **Solution**: Replace Unicode emoji (🎉) with GitHub codes (`:tada:`)
181
+
182
+ ### Issue: Backticks in PR Body
183
+
184
+ **Problem**: Backticks in heredoc cause shell interpretation issues
185
+
186
+ **Solution**: Use command substitution with heredoc:
187
+ ```bash
188
+ gh pr create --title "Title" --body "$(cat <<'EOF'
189
+ Content with `backticks` in markdown
190
+ EOF
191
+ )"
192
+ ```
193
+
194
+ ### Issue: Pre-push Hook Failures
195
+
196
+ **Problem**: RuboCop or tests fail during push
197
+
198
+ **Solution**:
199
+ 1. Run `rake` locally first
200
+ 2. Fix any issues before pushing
201
+ 3. Use `bundle exec rubocop -A` for safe auto-fixes
202
+
203
+ ## Staging Changes Safely
204
+
205
+ ### Avoid Bulk Operations
206
+
207
+ **Never use these commands** as they can add unintended files:
208
+ ```bash
209
+ git add . # Adds ALL files in current directory
210
+ git add -A # Adds ALL tracked and untracked files
211
+ git add * # Adds files matching shell glob
212
+ ```
213
+
214
+ ### Recommended Approaches
215
+
216
+ **Option 1: Add specific files explicitly**
217
+ ```bash
218
+ git add lib/specific_file.rb
219
+ git add spec/specific_spec.rb
220
+ git add README.md
221
+ ```
222
+
223
+ **Option 2: Review changes first, then stage**
224
+ ```bash
225
+ # See what would be added
226
+ git status
227
+ git diff
228
+
229
+ # Add specific files you want to commit
230
+ git add path/to/changed_file.rb
231
+ ```
232
+
233
+ **Option 3: Interactive staging for complex changes**
234
+ ```bash
235
+ git add -p # Review and stage changes interactively
236
+ ```
237
+
238
+ ## Best Practices
239
+
240
+ 1. **Always run tests before pushing**: `rake` or `bundle exec rspec`
241
+ 2. **Check RuboCop**: `bundle exec rubocop` before committing
242
+ 3. **Keep commits focused**: One logical change per commit
243
+ 4. **Stage files explicitly**: Avoid `git add .` - specify files individually
244
+ 5. **Review staged changes**: Use `git diff --cached` before committing
245
+ 6. **Write clear PR descriptions**: Include before/after examples when relevant
246
+ 7. **Link issues**: Use "Fixes #123" in PR descriptions
247
+ 8. **Update documentation**: Keep README and CHANGELOG current
248
+
249
+ ## Example Workflow
250
+
251
+ ```bash
252
+ # 1. Create branch
253
+ git switch -c fix/performance-issue
254
+
255
+ # 2. Make changes
256
+ # ... edit files ...
257
+
258
+ # 3. Run tests and lint
259
+ rake
260
+
261
+ # 4. Stage changes (be specific!)
262
+ git add lib/performance_fix.rb
263
+ git add spec/performance_fix_spec.rb
264
+
265
+ # 5. Commit with proper message
266
+ git commit -m "$(cat <<'EOF'
267
+ :zap: Fix performance regression in render method
268
+
269
+ Memoize expensive calculations to avoid recalculation.
270
+ - 3x faster rendering
271
+ - Reduces memory allocations
272
+
273
+ Fixes #42
274
+
275
+ :robot: Generated with [Agent Name](http://agent.url)
276
+
277
+ Co-Authored-By: Agent Name <agent@email>
278
+ EOF
279
+ )"
280
+
281
+ # 6. Push branch
282
+ git push -u origin fix/performance-issue
283
+
284
+ # 7. Create PR
285
+ gh pr create --title ":zap: Fix performance regression in render method" \
286
+ --body "Fixes #42 - Memoization of expensive calculations"
287
+
288
+ # 8. After approval, merge
289
+ gh pr merge 7 --merge \
290
+ --subject ":inbox_tray: :zap: Merge pull request #7 from sakuro/fix/performance-issue" \
291
+ --body "Performance fix through memoization"
292
+ ```
293
+
294
+ ## References
295
+
296
+ - [GitHub Emoji Codes](https://github.com/ikatyang/emoji-cheat-sheet)
297
+ - [Conventional Commits](https://www.conventionalcommits.org/)
298
+ - Project's commit hooks in `.git/hooks/`