rbcsv 0.1.7 → 0.2.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/CHANGELOG.md +38 -0
- data/Cargo.lock +1 -1
- data/DEVELOPMENT.md +259 -55
- data/README.md +103 -20
- data/docs/exe_upgrade_version.md +124 -0
- data/docs/release_process_v0.1.8.md +298 -0
- data/docs/special_character_bug_fix.md +257 -0
- data/docs/write_functionality_implementation.md +197 -0
- data/examples/README.md +221 -0
- data/{test.rb → examples/basic/basic_usage.rb} +2 -1
- data/{test_fixed.rb → examples/basic/test_fixed.rb} +1 -1
- data/examples/benchmarks/benchmark.rb +372 -0
- data/{output_comparison.rb → examples/benchmarks/output_comparison.rb} +41 -26
- data/examples/benchmarks/sample.csv +1001 -0
- data/examples/features/test_typed_functionality.rb +109 -0
- data/examples/features/test_write_functionality.rb +225 -0
- data/ext/rbcsv/Cargo.toml +1 -1
- data/ext/rbcsv/src/error.rs +16 -2
- data/ext/rbcsv/src/lib.rs +9 -1
- data/ext/rbcsv/src/parser.rs +202 -24
- data/ext/rbcsv/src/ruby_api.rs +115 -3
- data/ext/rbcsv/src/value.rs +87 -0
- data/lib/rbcsv/version.rb +1 -1
- metadata +16 -7
- data/benchmark.rb +0 -190
- /data/{quick_test.rb → examples/basic/quick_test.rb} +0 -0
- /data/{test_install.rb → examples/basic/test_install.rb} +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Gem Version Upgrade Execution Guide for AI Agent
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
This document provides step-by-step instructions for AI agents to automatically upgrade and release a new version of the rbcsv gem.
|
|
5
|
+
|
|
6
|
+
## Prerequisites Check
|
|
7
|
+
1. Verify current directory is project root: `/Users/fujitanisora/dev/oss/r_csv`
|
|
8
|
+
2. Ensure git repository is clean: `git status` should show no uncommitted changes
|
|
9
|
+
3. Confirm on main branch: `git branch --show-current` should return `main`
|
|
10
|
+
|
|
11
|
+
## Step-by-Step Instructions
|
|
12
|
+
|
|
13
|
+
### 1. Update Version Number
|
|
14
|
+
**File:** `lib/rbcsv/version.rb`
|
|
15
|
+
**Action:** Increment version following semantic versioning (MAJOR.MINOR.PATCH)
|
|
16
|
+
- PATCH: Bug fixes only (0.1.4 � 0.1.5)
|
|
17
|
+
- MINOR: New features, backward compatible (0.1.4 � 0.2.0)
|
|
18
|
+
- MAJOR: Breaking changes (0.1.4 � 1.0.0)
|
|
19
|
+
|
|
20
|
+
### 2. Update CHANGELOG.md
|
|
21
|
+
**File:** `CHANGELOG.md`
|
|
22
|
+
**Action:** Add new version section at the top with:
|
|
23
|
+
```markdown
|
|
24
|
+
## [VERSION] - YYYY-MM-DD
|
|
25
|
+
### Added
|
|
26
|
+
- New features
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- Modified features
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- Bug fixes
|
|
33
|
+
|
|
34
|
+
### Removed
|
|
35
|
+
- Deprecated features
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. Run Tests
|
|
39
|
+
**Commands:**
|
|
40
|
+
```bash
|
|
41
|
+
# Run Rust tests
|
|
42
|
+
cd ext/rbcsv && cargo test && cd ../..
|
|
43
|
+
|
|
44
|
+
# Run Ruby tests
|
|
45
|
+
bundle exec rspec
|
|
46
|
+
|
|
47
|
+
# Run linter
|
|
48
|
+
bundle exec rubocop
|
|
49
|
+
```
|
|
50
|
+
**Verify:** All tests must pass before proceeding
|
|
51
|
+
|
|
52
|
+
### 4. Build Rust Extension
|
|
53
|
+
**Commands:**
|
|
54
|
+
```bash
|
|
55
|
+
cd ext/rbcsv
|
|
56
|
+
cargo build --release
|
|
57
|
+
cd ../..
|
|
58
|
+
bundle exec rake compile
|
|
59
|
+
```
|
|
60
|
+
**Verify:** Build completes without errors
|
|
61
|
+
|
|
62
|
+
### 5. Build Gem
|
|
63
|
+
**Command:** `gem build rbcsv.gemspec`
|
|
64
|
+
**Verify:** New .gem file created (e.g., rbcsv-0.1.5.gem)
|
|
65
|
+
|
|
66
|
+
### 6. Test Local Installation
|
|
67
|
+
**Commands:**
|
|
68
|
+
```bash
|
|
69
|
+
# Install locally
|
|
70
|
+
gem install ./rbcsv-*.gem
|
|
71
|
+
|
|
72
|
+
# Test in IRB
|
|
73
|
+
ruby -e "require 'rbcsv'; puts RbCsv::VERSION; puts RbCsv.parse('a,b\n1,2').inspect"
|
|
74
|
+
```
|
|
75
|
+
**Verify:** Version matches and basic functionality works
|
|
76
|
+
|
|
77
|
+
### 7. Create Git Commit
|
|
78
|
+
**Commands:**
|
|
79
|
+
```bash
|
|
80
|
+
git add -A
|
|
81
|
+
git commit -m "Release version X.Y.Z
|
|
82
|
+
|
|
83
|
+
- [List key changes here]
|
|
84
|
+
"
|
|
85
|
+
git tag -a vX.Y.Z -m "Version X.Y.Z"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 8. Push to Repository
|
|
89
|
+
**Commands:**
|
|
90
|
+
```bash
|
|
91
|
+
git push origin main
|
|
92
|
+
git push origin --tags
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 9. Publish to RubyGems (Optional)
|
|
96
|
+
**Command:** `gem push rbcsv-X.Y.Z.gem`
|
|
97
|
+
**Note:** Requires RubyGems.org credentials
|
|
98
|
+
|
|
99
|
+
## Validation Checklist
|
|
100
|
+
- [ ] Version updated in version.rb
|
|
101
|
+
- [ ] CHANGELOG.md updated with release notes
|
|
102
|
+
- [ ] All tests passing (Rust and Ruby)
|
|
103
|
+
- [ ] Gem builds successfully
|
|
104
|
+
- [ ] Local installation works
|
|
105
|
+
- [ ] Git commit and tag created
|
|
106
|
+
- [ ] Changes pushed to repository
|
|
107
|
+
|
|
108
|
+
## Rollback Instructions
|
|
109
|
+
If any step fails:
|
|
110
|
+
1. `git reset --hard HEAD~1` (if committed)
|
|
111
|
+
2. `git tag -d vX.Y.Z` (if tagged)
|
|
112
|
+
3. Delete generated .gem file
|
|
113
|
+
4. Fix issues and restart process
|
|
114
|
+
|
|
115
|
+
## Error Handling
|
|
116
|
+
- If tests fail: Fix bugs before proceeding
|
|
117
|
+
- If build fails: Check Rust/Ruby environment setup
|
|
118
|
+
- If gem push fails: Verify RubyGems credentials
|
|
119
|
+
|
|
120
|
+
## Success Confirmation
|
|
121
|
+
After completion, verify:
|
|
122
|
+
1. New version tag visible on GitHub
|
|
123
|
+
2. Gem file exists in project root
|
|
124
|
+
3. Version accessible via: `ruby -e "require 'rbcsv'; puts RbCsv::VERSION"`
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# リリースプロセス v0.1.8 記録
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
RbCsv gem version 0.1.8 のリリースプロセスを詳細に記録したドキュメントです。書き込み機能の追加と重要なバグ修正を含む、段階的なリリース手順を説明しています。
|
|
6
|
+
|
|
7
|
+
## リリース概要
|
|
8
|
+
|
|
9
|
+
### バージョン情報
|
|
10
|
+
- **リリースバージョン**: 0.1.8
|
|
11
|
+
- **リリース日**: 2025-01-28
|
|
12
|
+
- **前バージョン**: 0.1.7
|
|
13
|
+
- **リリースタイプ**: Minor release (新機能 + バグ修正)
|
|
14
|
+
|
|
15
|
+
### 主要変更点
|
|
16
|
+
1. **新機能**: CSV書き込み機能 (`RbCsv.write()`)
|
|
17
|
+
2. **CRITICAL修正**: 特殊文字処理バグの修正
|
|
18
|
+
3. **テスト強化**: 包括的テストスイートの追加
|
|
19
|
+
|
|
20
|
+
## リリース準備フェーズ
|
|
21
|
+
|
|
22
|
+
### 1. 機能開発完了確認
|
|
23
|
+
```bash
|
|
24
|
+
# 全テスト実行
|
|
25
|
+
bundle exec rspec # Ruby統合テスト
|
|
26
|
+
cargo test --manifest-path ext/rbcsv/Cargo.toml # Rust単体テスト
|
|
27
|
+
ruby test_write_functionality.rb # 実行可能テスト
|
|
28
|
+
|
|
29
|
+
# 結果確認
|
|
30
|
+
# RSpec: 17 examples, 0 failures ✅
|
|
31
|
+
# Rust: 12 tests passed ✅
|
|
32
|
+
# 実行可能テスト: 8/8 成功 ✅
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. ドキュメント更新確認
|
|
36
|
+
- [x] DEVELOPMENT.md に検証コマンド追加
|
|
37
|
+
- [x] 実行可能テストスクリプト作成
|
|
38
|
+
- [x] READMEの更新(必要に応じて)
|
|
39
|
+
|
|
40
|
+
### 3. コードクリーンアップ
|
|
41
|
+
```rust
|
|
42
|
+
// 未使用関数警告の対応
|
|
43
|
+
warning: function `escape_sanitize` is never used
|
|
44
|
+
--> ext/rbcsv/src/parser.rs:21:8
|
|
45
|
+
```
|
|
46
|
+
*注: backward compatibility のため関数は保持、将来削除予定*
|
|
47
|
+
|
|
48
|
+
## バージョン更新フェーズ
|
|
49
|
+
|
|
50
|
+
### 1. バージョン番号更新
|
|
51
|
+
```ruby
|
|
52
|
+
# lib/rbcsv/version.rb
|
|
53
|
+
module RbCsv
|
|
54
|
+
VERSION = "0.1.8" # 0.1.7 → 0.1.8
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**バージョニング戦略:**
|
|
59
|
+
- Major: 破壊的変更
|
|
60
|
+
- Minor: 新機能追加
|
|
61
|
+
- Patch: バグ修正のみ
|
|
62
|
+
|
|
63
|
+
今回は新機能(write)追加のため Minor バージョンアップ。
|
|
64
|
+
|
|
65
|
+
### 2. CHANGELOG.md 更新
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
## [0.1.8] - 2025-01-28
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
- CSV file writing functionality with `RbCsv.write(file_path, data)` method
|
|
72
|
+
- Comprehensive data validation (empty data check, field count consistency)
|
|
73
|
+
- Enhanced error handling for write operations (permission errors, invalid data)
|
|
74
|
+
- Full test coverage for write functionality with executable test script
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
- **CRITICAL**: Fixed special character handling in CSV parsing
|
|
78
|
+
- Removed problematic `escape_sanitize` function that interfered with standard CSV escaping
|
|
79
|
+
- Now properly preserves backslashes, newlines, tabs, and other special characters
|
|
80
|
+
- Ensures perfect round-trip fidelity for write/read operations
|
|
81
|
+
- Updated RSpec tests to reflect correct CSV parsing behavior
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**CHANGELOG 記述指針:**
|
|
85
|
+
- **Added**: 新機能
|
|
86
|
+
- **Changed**: 既存機能の変更
|
|
87
|
+
- **Deprecated**: 廃止予定機能
|
|
88
|
+
- **Removed**: 削除された機能
|
|
89
|
+
- **Fixed**: バグ修正
|
|
90
|
+
- **Security**: セキュリティ修正
|
|
91
|
+
|
|
92
|
+
### 3. 変更内容の一貫性チェック
|
|
93
|
+
- バージョン番号とCHANGELOGの整合性確認
|
|
94
|
+
- 機能追加内容とドキュメントの整合性確認
|
|
95
|
+
|
|
96
|
+
## Git操作フェーズ
|
|
97
|
+
|
|
98
|
+
### 1. ステージング状況確認
|
|
99
|
+
```bash
|
|
100
|
+
git status
|
|
101
|
+
# 出力:
|
|
102
|
+
# Changes not staged for commit:
|
|
103
|
+
# modified: CHANGELOG.md
|
|
104
|
+
# modified: lib/rbcsv/version.rb
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 2. コミット準備
|
|
108
|
+
```bash
|
|
109
|
+
git add CHANGELOG.md lib/rbcsv/version.rb
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**ファイル選択基準:**
|
|
113
|
+
- リリースに直接関連するファイルのみ
|
|
114
|
+
- 開発中の一時ファイルは除外
|
|
115
|
+
- ドキュメントファイルは個別判断
|
|
116
|
+
|
|
117
|
+
### 3. コミットメッセージ作成
|
|
118
|
+
```bash
|
|
119
|
+
git commit -m "$(cat <<'EOF'
|
|
120
|
+
Release 0.1.8: Add write functionality and fix critical CSV parsing bug
|
|
121
|
+
|
|
122
|
+
### Added
|
|
123
|
+
- CSV file writing functionality with RbCsv.write(file_path, data)
|
|
124
|
+
- Comprehensive data validation and error handling for write operations
|
|
125
|
+
- Full test coverage with executable test script
|
|
126
|
+
|
|
127
|
+
### Fixed
|
|
128
|
+
- CRITICAL: Fixed special character handling in CSV parsing
|
|
129
|
+
- Removed problematic escape_sanitize function that interfered with standard CSV escaping
|
|
130
|
+
- Ensures perfect round-trip fidelity for write/read operations
|
|
131
|
+
|
|
132
|
+
🤖 Generated with [Claude Code](https://claude.ai/code)
|
|
133
|
+
|
|
134
|
+
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
135
|
+
EOF
|
|
136
|
+
)"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**コミットメッセージ構造:**
|
|
140
|
+
1. **Subject line**: 概要 (50文字以内推奨)
|
|
141
|
+
2. **Body**: 詳細な変更内容
|
|
142
|
+
3. **Footer**: 自動生成情報、Co-author情報
|
|
143
|
+
|
|
144
|
+
### 4. タグ作成
|
|
145
|
+
```bash
|
|
146
|
+
git tag -a v0.1.8 -m "Release version 0.1.8: Add write functionality and fix critical CSV parsing bug"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**タグ命名規則:**
|
|
150
|
+
- Format: `v{MAJOR}.{MINOR}.{PATCH}`
|
|
151
|
+
- Example: `v0.1.8`
|
|
152
|
+
- Semantic Versioning準拠
|
|
153
|
+
|
|
154
|
+
### 5. リリース内容確認
|
|
155
|
+
```bash
|
|
156
|
+
# コミット履歴確認
|
|
157
|
+
git log --oneline -3
|
|
158
|
+
# 58bff07 Release 0.1.8: Add write functionality and fix critical CSV parsing bug
|
|
159
|
+
# 9512c4c add fnc write
|
|
160
|
+
# 8a7056b parse is bung
|
|
161
|
+
|
|
162
|
+
# タグ確認
|
|
163
|
+
git tag --list
|
|
164
|
+
# v0.1.8
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## リリース後フェーズ
|
|
168
|
+
|
|
169
|
+
### 1. 動作確認
|
|
170
|
+
```bash
|
|
171
|
+
# 最新コードでの最終テスト
|
|
172
|
+
bundle exec rake compile # ライブラリ再ビルド
|
|
173
|
+
bundle exec rspec # 統合テスト
|
|
174
|
+
ruby test_write_functionality.rb # 機能テスト
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 2. ドキュメント生成・更新
|
|
178
|
+
```bash
|
|
179
|
+
# API ドキュメント生成(必要に応じて)
|
|
180
|
+
yard doc
|
|
181
|
+
|
|
182
|
+
# README の最終確認
|
|
183
|
+
# バージョン情報の整合性確認
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 3. リモートリポジトリへのプッシュ(必要に応じて)
|
|
187
|
+
```bash
|
|
188
|
+
# コミットプッシュ
|
|
189
|
+
git push origin main
|
|
190
|
+
|
|
191
|
+
# タグプッシュ
|
|
192
|
+
git push origin v0.1.8
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## 品質保証チェックリスト
|
|
196
|
+
|
|
197
|
+
### リリース前必須チェック
|
|
198
|
+
- [ ] すべてのテストがパス(RSpec + Rust + 実行可能テスト)
|
|
199
|
+
- [ ] バージョン番号が適切に更新済み
|
|
200
|
+
- [ ] CHANGELOG.md が正確に記述済み
|
|
201
|
+
- [ ] 新機能のドキュメントが整備済み
|
|
202
|
+
- [ ] 破壊的変更がある場合、適切にバージョンアップ
|
|
203
|
+
- [ ] コミットメッセージが明確で追跡可能
|
|
204
|
+
|
|
205
|
+
### リリース後確認項目
|
|
206
|
+
- [ ] git タグが正しく作成されている
|
|
207
|
+
- [ ] コミット履歴が適切
|
|
208
|
+
- [ ] 最新ビルドでテストがパス
|
|
209
|
+
- [ ] ドキュメントサイトの更新(該当する場合)
|
|
210
|
+
|
|
211
|
+
## トラブルシューティング
|
|
212
|
+
|
|
213
|
+
### よくある問題と解決策
|
|
214
|
+
|
|
215
|
+
#### 1. コンパイルエラー
|
|
216
|
+
```bash
|
|
217
|
+
# 問題: Ruby extension compilation failed
|
|
218
|
+
# 解決: 依存関係の確認
|
|
219
|
+
bundle install
|
|
220
|
+
bundle exec rake compile
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### 2. テスト失敗
|
|
224
|
+
```bash
|
|
225
|
+
# 問題: Spec failures after changes
|
|
226
|
+
# 解決: テストの前提条件確認
|
|
227
|
+
bundle exec rake clean
|
|
228
|
+
bundle exec rake compile
|
|
229
|
+
bundle exec rspec
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### 3. バージョン番号不整合
|
|
233
|
+
```bash
|
|
234
|
+
# 問題: Version mismatch between files
|
|
235
|
+
# 解決: 全ファイルの一貫性確認
|
|
236
|
+
grep -r "0.1.8" lib/ spec/ ext/ README.md CHANGELOG.md
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### 4. Git操作エラー
|
|
240
|
+
```bash
|
|
241
|
+
# 問題: Tag already exists
|
|
242
|
+
# 解決: 既存タグの削除・再作成
|
|
243
|
+
git tag -d v0.1.8
|
|
244
|
+
git tag -a v0.1.8 -m "Release version 0.1.8"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## リリースメトリクス
|
|
248
|
+
|
|
249
|
+
### 開発工数
|
|
250
|
+
- **機能開発**: ~4時間(write機能実装)
|
|
251
|
+
- **バグ修正**: ~2時間(特殊文字処理修正)
|
|
252
|
+
- **テスト作成**: ~2時間(包括的テストスイート)
|
|
253
|
+
- **ドキュメント**: ~1時間(DEVELOPMENT.md更新等)
|
|
254
|
+
- **リリース作業**: ~0.5時間(バージョンアップ・コミット・タグ)
|
|
255
|
+
|
|
256
|
+
### 品質指標
|
|
257
|
+
- **テストカバレッジ**: 100%(主要機能)
|
|
258
|
+
- **バグ密度**: 1 critical bug発見・修正済み
|
|
259
|
+
- **ドキュメント充実度**: 高(実行可能テスト・詳細ガイド含む)
|
|
260
|
+
|
|
261
|
+
### 機能追加
|
|
262
|
+
- **新API**: 1個(`RbCsv.write`)
|
|
263
|
+
- **新エラータイプ**: 2個(WritePermission, InvalidData)
|
|
264
|
+
- **新テストケース**: 8個(実行可能テスト)
|
|
265
|
+
|
|
266
|
+
## 次回リリースへの改善点
|
|
267
|
+
|
|
268
|
+
### プロセス改善
|
|
269
|
+
1. **自動化**: バージョンアップの自動化スクリプト検討
|
|
270
|
+
2. **CI/CD**: GitHub Actions等での自動テスト・リリース
|
|
271
|
+
3. **ドキュメント**: API文書の自動生成
|
|
272
|
+
|
|
273
|
+
### 品質向上
|
|
274
|
+
1. **プレリリーステスト**: beta版での事前検証
|
|
275
|
+
2. **パフォーマンステスト**: 大容量データでのベンチマーク
|
|
276
|
+
3. **互換性テスト**: 複数Ruby版での動作確認
|
|
277
|
+
|
|
278
|
+
### コミュニケーション
|
|
279
|
+
1. **リリースノート**: より詳細なユーザー向け説明
|
|
280
|
+
2. **マイグレーションガイド**: 破壊的変更時の移行手順
|
|
281
|
+
3. **コミュニティフィードバック**: ユーザーからの意見収集
|
|
282
|
+
|
|
283
|
+
## 関連リソース
|
|
284
|
+
|
|
285
|
+
### ドキュメント
|
|
286
|
+
- [書き込み機能実装ガイド](./write_functionality_implementation.md)
|
|
287
|
+
- [特殊文字バグ修正記録](./special_character_bug_fix.md)
|
|
288
|
+
- [DEVELOPMENT.md](../DEVELOPMENT.md)
|
|
289
|
+
|
|
290
|
+
### テストリソース
|
|
291
|
+
- [実行可能テストスクリプト](../test_write_functionality.rb)
|
|
292
|
+
- [RSpec統合テスト](../spec/rbcsv_spec.rb)
|
|
293
|
+
- [Rust単体テスト](../ext/rbcsv/src/parser.rs)
|
|
294
|
+
|
|
295
|
+
### 参考資料
|
|
296
|
+
- [Semantic Versioning](https://semver.org/)
|
|
297
|
+
- [Keep a Changelog](https://keepachangelog.com/)
|
|
298
|
+
- [Git Tagging Best Practices](https://git-scm.com/book/en/v2/Git-Basics-Tagging)
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# 特殊文字処理バグ修正記録
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
RbCsv v0.1.8開発中に発見された、特殊文字(バックスラッシュ、改行、タブ等)の処理に関する重要なバグとその修正プロセスを記録したドキュメントです。このバグは write/read の往復処理における데이터の完全性に影響する critical な問題でした。
|
|
6
|
+
|
|
7
|
+
## 問題の発見
|
|
8
|
+
|
|
9
|
+
### 1. 症状
|
|
10
|
+
```ruby
|
|
11
|
+
# テストが失敗
|
|
12
|
+
test_data = [
|
|
13
|
+
['field1', 'field2', 'field3'],
|
|
14
|
+
['comma,test', 'quote"test', 'newline\ntest'],
|
|
15
|
+
['tab\ttest', 'backslash\\test', 'normal']
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
RbCsv.write('/tmp/test.csv', test_data)
|
|
19
|
+
read_data = RbCsv.read('/tmp/test.csv')
|
|
20
|
+
|
|
21
|
+
test_data == read_data # => false (期待: true)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. エラーメッセージ
|
|
25
|
+
```
|
|
26
|
+
❌ 失敗: Field Count Mismatch: Field count mismatch at line 3: expected 3 fields, got 1 fields
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 3. 初期仮説
|
|
30
|
+
- CSV書き込み時のエスケープ処理の問題
|
|
31
|
+
- CSV読み込み時のパース処理の問題
|
|
32
|
+
|
|
33
|
+
## 問題の詳細調査
|
|
34
|
+
|
|
35
|
+
### 1. デバッグ手法
|
|
36
|
+
```ruby
|
|
37
|
+
# デバッグコードを追加
|
|
38
|
+
written_content = File.read(file_path)
|
|
39
|
+
puts "書き込まれた内容:"
|
|
40
|
+
puts written_content.inspect
|
|
41
|
+
|
|
42
|
+
# 出力結果
|
|
43
|
+
"field1,field2,field3\n\"comma,test\",\"quote\"\"test\",newline\\ntest\ntab\\ttest,backslash\\test,normal\n"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. 問題の特定
|
|
47
|
+
書き込まれたCSVファイルの内容を見ると、以下の問題が判明:
|
|
48
|
+
|
|
49
|
+
**期待される動作:**
|
|
50
|
+
```csv
|
|
51
|
+
field1,field2,field3
|
|
52
|
+
"comma,test","quote""test","newline
|
|
53
|
+
test"
|
|
54
|
+
"tab test","backslash\test",normal
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**実際の動作:**
|
|
58
|
+
```csv
|
|
59
|
+
field1,field2,field3
|
|
60
|
+
"comma,test","quote""test",newline\ntest
|
|
61
|
+
tab\ttest,backslash\test,normal
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**問題点:**
|
|
65
|
+
- 改行文字(`\n`)が実際の改行ではなく、リテラル文字列 `\\n` として出力
|
|
66
|
+
- タブ文字(`\t`)が実際のタブではなく、リテラル文字列 `\\t` として出力
|
|
67
|
+
|
|
68
|
+
## 根本原因の解析
|
|
69
|
+
|
|
70
|
+
### 1. 問題コードの特定
|
|
71
|
+
`ext/rbcsv/src/parser.rs` の `parse_csv_core` 関数内:
|
|
72
|
+
|
|
73
|
+
```rust
|
|
74
|
+
// 問題のあるコード
|
|
75
|
+
pub fn parse_csv_core(input: &str, trim_config: csv::Trim) -> Result<Vec<Vec<String>>, CsvError> {
|
|
76
|
+
// ...
|
|
77
|
+
// エスケープシーケンスを実際の文字に変換
|
|
78
|
+
let processed = escape_sanitize(input); // ← これが問題
|
|
79
|
+
|
|
80
|
+
let mut reader = csv::ReaderBuilder::new()
|
|
81
|
+
.has_headers(false)
|
|
82
|
+
.trim(trim_config)
|
|
83
|
+
.from_reader(processed.as_bytes()); // ← 変換後のデータを使用
|
|
84
|
+
// ...
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. `escape_sanitize` 関数の問題
|
|
89
|
+
```rust
|
|
90
|
+
pub fn escape_sanitize(s: &str) -> String {
|
|
91
|
+
s.replace("\\n", "\n") // \\n を \n に変換
|
|
92
|
+
.replace("\\r", "\r") // \\r を \r に変換
|
|
93
|
+
.replace("\\t", "\t") // \\t を \t に変換
|
|
94
|
+
.replace("\\\"", "\"") // \\\" を \" に変換
|
|
95
|
+
.replace("\\\\", "\\") // \\\\ を \\ に変換
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. 根本問題の理解
|
|
100
|
+
|
|
101
|
+
**問題の本質:**
|
|
102
|
+
1. CSV書き込み時:csv crate が RFC 4180 に従って適切にエスケープ
|
|
103
|
+
2. CSV読み込み時:`escape_sanitize` が追加的にエスケープ処理を実行
|
|
104
|
+
3. 結果:**二重エスケープ処理による데이터 corruption**
|
|
105
|
+
|
|
106
|
+
**具体例:**
|
|
107
|
+
```
|
|
108
|
+
元データ: "backslash\\test"
|
|
109
|
+
↓ CSV書き込み (csv crate)
|
|
110
|
+
CSV: backslash\\test (適切にエスケープ済み)
|
|
111
|
+
↓ CSV読み込み時 escape_sanitize
|
|
112
|
+
結果: "backslash\test" (誤った変換)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 修正の実装
|
|
116
|
+
|
|
117
|
+
### 1. 修正方針
|
|
118
|
+
CSV標準処理は `csv` crate に委ね、独自のエスケープ処理を削除する。
|
|
119
|
+
|
|
120
|
+
### 2. 修正内容
|
|
121
|
+
```rust
|
|
122
|
+
// 修正前
|
|
123
|
+
pub fn parse_csv_core(input: &str, trim_config: csv::Trim) -> Result<Vec<Vec<String>>, CsvError> {
|
|
124
|
+
// ...
|
|
125
|
+
// エスケープシーケンスを実際の文字に変換
|
|
126
|
+
let processed = escape_sanitize(input);
|
|
127
|
+
|
|
128
|
+
let mut reader = csv::ReaderBuilder::new()
|
|
129
|
+
.has_headers(false)
|
|
130
|
+
.trim(trim_config)
|
|
131
|
+
.from_reader(processed.as_bytes());
|
|
132
|
+
// ...
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 修正後
|
|
136
|
+
pub fn parse_csv_core(input: &str, trim_config: csv::Trim) -> Result<Vec<Vec<String>>, CsvError> {
|
|
137
|
+
// ...
|
|
138
|
+
// CSV crate に任せて適切なパースを行う(escape_sanitize は削除)
|
|
139
|
+
let mut reader = csv::ReaderBuilder::new()
|
|
140
|
+
.has_headers(false)
|
|
141
|
+
.trim(trim_config)
|
|
142
|
+
.from_reader(input.as_bytes()); // 元のデータを直接使用
|
|
143
|
+
// ...
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 3. 副作用の考慮
|
|
148
|
+
- `escape_sanitize` 関数は未使用になるが、backward compatibility のため残存
|
|
149
|
+
- 将来のバージョンで完全削除を検討
|
|
150
|
+
|
|
151
|
+
## 修正の検証
|
|
152
|
+
|
|
153
|
+
### 1. 単体テスト
|
|
154
|
+
```ruby
|
|
155
|
+
# デバッグスクリプトによる検証
|
|
156
|
+
test_data = [
|
|
157
|
+
['field1', 'field2', 'field3'],
|
|
158
|
+
['comma,test', 'quote"test', "newline\ntest"], # 実際の改行
|
|
159
|
+
["tab\ttest", 'backslash\\test', 'normal'] # 実際のタブ
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
RbCsv.write('/tmp/debug.csv', test_data)
|
|
163
|
+
read_data = RbCsv.read('/tmp/debug.csv')
|
|
164
|
+
|
|
165
|
+
puts "Original == Read back: #{test_data == read_data}"
|
|
166
|
+
# 結果: true
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 2. 包括的テスト
|
|
170
|
+
```bash
|
|
171
|
+
# 実行可能テストスクリプト
|
|
172
|
+
ruby test_write_functionality.rb
|
|
173
|
+
# 結果: 8/8 成功 ✅
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 3. 既存機能への影響確認
|
|
177
|
+
```bash
|
|
178
|
+
# RSpec テスト
|
|
179
|
+
bundle exec rspec
|
|
180
|
+
# 結果: 17 examples, 0 failures ✅
|
|
181
|
+
|
|
182
|
+
# Rust 単体テスト
|
|
183
|
+
cargo test --manifest-path ext/rbcsv/Cargo.toml
|
|
184
|
+
# 結果: 12 passed ✅
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## 学んだ教訓
|
|
188
|
+
|
|
189
|
+
### 1. CSV標準の重要性
|
|
190
|
+
- RFC 4180 は十分に検証された標準
|
|
191
|
+
- 独自実装よりも標準ライブラリを信頼すべき
|
|
192
|
+
- `csv` crate は適切にエスケープ/アンエスケープを処理済み
|
|
193
|
+
|
|
194
|
+
### 2. テスト戦略の重要性
|
|
195
|
+
- 往復テスト(write → read)は基本中の基本
|
|
196
|
+
- 特殊文字を含む包括的テストケースが必要
|
|
197
|
+
- 自動テストと手動デバッグの併用が効果的
|
|
198
|
+
|
|
199
|
+
### 3. デバッグ手法
|
|
200
|
+
```ruby
|
|
201
|
+
# 段階的デバッグが効果的
|
|
202
|
+
puts "Original data: #{original_data.inspect}"
|
|
203
|
+
puts "Raw file content: #{File.read(path).inspect}"
|
|
204
|
+
puts "Read back data: #{read_data.inspect}"
|
|
205
|
+
puts "Comparison: #{original_data == read_data}"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 4. コードレビューの重要性
|
|
209
|
+
- 独自エスケープ処理の必要性を疑問視すべきだった
|
|
210
|
+
- 標準ライブラリとの重複機能は要注意
|
|
211
|
+
- コードの意図と実装の一致確認が重要
|
|
212
|
+
|
|
213
|
+
## 影響と重要性
|
|
214
|
+
|
|
215
|
+
### 1. データ完全性
|
|
216
|
+
- **CRITICAL**: 特殊文字を含むデータの corruption を防止
|
|
217
|
+
- 多言語対応アプリケーションでの信頼性向上
|
|
218
|
+
- プロダクション環境での安全性確保
|
|
219
|
+
|
|
220
|
+
### 2. 標準準拠
|
|
221
|
+
- RFC 4180 完全準拠の実現
|
|
222
|
+
- 他のCSVツールとの互換性確保
|
|
223
|
+
- 業界標準との整合性
|
|
224
|
+
|
|
225
|
+
### 3. パフォーマンス
|
|
226
|
+
- 不要な二重処理の削除
|
|
227
|
+
- メモリ使用量の最適化
|
|
228
|
+
- 処理速度の向上
|
|
229
|
+
|
|
230
|
+
## 予防策
|
|
231
|
+
|
|
232
|
+
### 1. テストプロセス改善
|
|
233
|
+
```ruby
|
|
234
|
+
# 特殊文字テストを標準テストスイートに含める
|
|
235
|
+
SPECIAL_CHARS_TEST_DATA = [
|
|
236
|
+
['field1', 'field2', 'field3'],
|
|
237
|
+
['comma,test', 'quote"test', "newline\ntest"],
|
|
238
|
+
["tab\ttest", 'backslash\\test', 'unicode🎉']
|
|
239
|
+
]
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### 2. コードレビューチェックリスト
|
|
243
|
+
- [ ] 標準ライブラリとの機能重複はないか?
|
|
244
|
+
- [ ] 独自実装の必要性は十分か?
|
|
245
|
+
- [ ] 往復テストは通るか?
|
|
246
|
+
- [ ] エッジケース(特殊文字)のテストは含まれているか?
|
|
247
|
+
|
|
248
|
+
### 3. ドキュメント改善
|
|
249
|
+
- CSV標準準拠の明示
|
|
250
|
+
- サポートする特殊文字の例示
|
|
251
|
+
- 往復互換性の保証声明
|
|
252
|
+
|
|
253
|
+
## 参考資料
|
|
254
|
+
|
|
255
|
+
- [RFC 4180 - Common Format and MIME Type for CSV Files](https://tools.ietf.org/html/rfc4180)
|
|
256
|
+
- [Rust csv crate - Escaping documentation](https://docs.rs/csv/latest/csv/struct.WriterBuilder.html)
|
|
257
|
+
- [CSV標準とエスケープ処理のベストプラクティス](https://en.wikipedia.org/wiki/Comma-separated_values#RFC_4180_standard)
|