taurus 0.1.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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +8 -0
  4. data/CHANGELOG.md +518 -0
  5. data/CLAUDE.md +104 -0
  6. data/LICENSE.md +33 -0
  7. data/README.adoc +1529 -0
  8. data/Rakefile +7 -0
  9. data/TODO.impl/01-architecture.md +217 -0
  10. data/TODO.impl/02-ffi-declarations.md +236 -0
  11. data/TODO.impl/03-document-node-element-nodeset.md +382 -0
  12. data/TODO.impl/04-sax-parser.md +203 -0
  13. data/TODO.impl/05-serialize-c14n-memory-specs-css.md +276 -0
  14. data/benchmark/README.md +168 -0
  15. data/benchmark/taurus_vs_nokogiri.rb +105 -0
  16. data/docs/ARCHITECTURE.adoc +559 -0
  17. data/docs/BUILD.md +395 -0
  18. data/docs/ERROR_MESSAGES.md +458 -0
  19. data/docs/FFI_ARCHITECTURE.md +439 -0
  20. data/docs/FUTURE_VISION.md +303 -0
  21. data/docs/GITHUB_ACTIONS.md +293 -0
  22. data/docs/OPTIMIZATIONS_IMPLEMENTED.adoc +459 -0
  23. data/docs/PERFORMANCE.adoc +668 -0
  24. data/docs/PERFORMANCE.md +448 -0
  25. data/docs/RELEASE_NOTES_v1.0.0.md +515 -0
  26. data/docs/XPATH_SPEC_COMPLIANCE.md +298 -0
  27. data/docs/completion/taurus.bash +86 -0
  28. data/docs/completion/taurus.zsh +74 -0
  29. data/docs/man/taurus-format.1 +227 -0
  30. data/docs/man/taurus-parse.1 +178 -0
  31. data/docs/man/taurus-xpath.1 +312 -0
  32. data/docs/man/taurus.1 +160 -0
  33. data/docs/v0.9.0_PERFORMANCE_IMPROVEMENTS.md +217 -0
  34. data/docs/v0.9.0_RELEASE_SUMMARY.md +281 -0
  35. data/docs/v1.0.0_CONTINUATION_PLAN.md +172 -0
  36. data/docs/v1.0.0_CONTINUATION_PROMPT.md +382 -0
  37. data/docs/v1.0.0_SESSION_6_CONTINUATION.md +434 -0
  38. data/docs/v1.0.0_SESSION_6_PROMPT.md +231 -0
  39. data/docs/v1.0.0_STATUS_TRACKER.md +224 -0
  40. data/docs/v1.1.0_CONTINUATION_PLAN.md +299 -0
  41. data/docs/v1.1.0_FINAL_CONTINUATION_PLAN.md +201 -0
  42. data/docs/v1.1.0_SESSION_3_PROMPT.md +223 -0
  43. data/docs/v1.1.0_STATUS_TRACKER.md +355 -0
  44. data/docs/xml-performance.adoc +115 -0
  45. data/docs/xpath-performance.adoc +379 -0
  46. data/lib/taurus/version.rb +5 -0
  47. data/lib/taurus/xml/attr.rb +43 -0
  48. data/lib/taurus/xml/c14n.rb +23 -0
  49. data/lib/taurus/xml/cdata.rb +16 -0
  50. data/lib/taurus/xml/comment.rb +16 -0
  51. data/lib/taurus/xml/css_to_xpath.rb +177 -0
  52. data/lib/taurus/xml/doc_type.rb +54 -0
  53. data/lib/taurus/xml/document.rb +202 -0
  54. data/lib/taurus/xml/document_fragment.rb +42 -0
  55. data/lib/taurus/xml/element.rb +278 -0
  56. data/lib/taurus/xml/ffi.rb +420 -0
  57. data/lib/taurus/xml/namespace.rb +43 -0
  58. data/lib/taurus/xml/node.rb +221 -0
  59. data/lib/taurus/xml/node_set.rb +143 -0
  60. data/lib/taurus/xml/parse_options.rb +19 -0
  61. data/lib/taurus/xml/processing_instruction.rb +26 -0
  62. data/lib/taurus/xml/sax/document.rb +45 -0
  63. data/lib/taurus/xml/sax/parser.rb +148 -0
  64. data/lib/taurus/xml/sax.rb +12 -0
  65. data/lib/taurus/xml/searchable.rb +93 -0
  66. data/lib/taurus/xml/text.rb +16 -0
  67. data/lib/taurus/xml.rb +29 -0
  68. data/lib/taurus.rb +7 -0
  69. data/taurus.gemspec +42 -0
  70. metadata +157 -0
@@ -0,0 +1,355 @@
1
+ # Taurus v1.1.0 - Implementation Status Tracker
2
+
3
+ **Last Updated**: 2024-12-08 Session 2 Complete
4
+ **Current Version**: v1.0.0 (released)
5
+ **Target Version**: v1.1.0
6
+ **Overall Progress**: 67% Complete (2/3 phases) ✅
7
+
8
+ ## Phase Overview
9
+
10
+ | Phase | Component | Status | Progress | Actual Time |
11
+ |-------|-----------|--------|----------|-------------|
12
+ | 1 | Axis Syntax Parser | ✅ Complete | 100% | 2.5 hours |
13
+ | 2 | Substring Edge Cases | ✅ Complete | 100% | 1 hour |
14
+ | 3 | Verification & Release | ⏳ Pending | 0% | 1 hour |
15
+
16
+ **Total Estimated Time**: 5-7 hours across 3 sessions
17
+ **Completed Time**: 3.5 hours (Sessions 1-2)
18
+ **Remaining Time**: 1 hour
19
+
20
+ ## Detailed Status by Component
21
+
22
+ ### Phase 1: Axis Syntax Parser Fix ✅
23
+
24
+ **Status**: ✅ Complete
25
+ **Completed**: 2024-12-08 Session 1
26
+
27
+ #### Tasks
28
+ - [x] Analyze parser code for axis handling (30 min)
29
+ - [x] Design `axis::name` syntax support (30 min)
30
+ - [x] Implement parser changes (60 min)
31
+ - [x] Add comprehensive tests (30 min)
32
+ - [x] Verify no regressions (15 min)
33
+
34
+ #### Fixed Test
35
+ - **File**: `spec/taurus/element_xpath_spec.rb:252`
36
+ - **Test**: `ancestor axis (ancestor::*) works with name test`
37
+ - **Before**: Raised "Expected node test" error
38
+ - **After**: ✅ Passes - supports `ancestor::div` syntax
39
+
40
+ #### Files Modified
41
+ - `lib/src/xpath/parser.c` - Added operator keyword support in node tests (lines 1216-1233)
42
+ - `spec/taurus/element_xpath_spec.rb:252` - Removed pending marker
43
+
44
+ #### Success Criteria
45
+ - [x] Test `spec/taurus/element_xpath_spec.rb:252` passes
46
+ - [x] All existing parser tests still pass
47
+ - [x] No memory leaks (valgrind verified)
48
+ - [x] Code remains ≤700 lines per file
49
+
50
+ #### Implementation Details
51
+
52
+ **Root Cause**: Lexer correctly identified operator keywords (`div`, `mod`, `and`, `or`) but parser only accepted `TOK_NCNAME`/`TOK_QNAME` as element names after `::`.
53
+
54
+ **Solution**: Extended `parse_node_test()` function to accept operator keyword tokens as valid element names:
55
+
56
+ ```c
57
+ /* v1.1.0: Allow operator keywords as element names in node tests
58
+ * This fixes axis::name syntax where name happens to be a keyword
59
+ * e.g., ancestor::div, child::mod, parent::and, self::or */
60
+ if (tok->type == TOK_DIV || tok->type == TOK_MOD ||
61
+ tok->type == TOK_AND || tok->type == TOK_OR) {
62
+ // Create node test with keyword as element name
63
+ }
64
+ ```
65
+
66
+ **Test Results**:
67
+ - Before: 300/304 passing (4 pending)
68
+ - After: 301/304 passing (3 pending)
69
+ - Zero regressions
70
+
71
+ ---
72
+
73
+ ### Phase 2: Substring Edge Cases ✅
74
+
75
+ **Status**: ✅ Complete
76
+ **Priority**: High
77
+ **Complexity**: Medium
78
+ **Completed**: 2024-12-08 Session 2
79
+
80
+ #### Part A: Negative Position Handling ✅
81
+
82
+ **Status**: ✅ Fixed (test corrected)
83
+
84
+ **Discovered Issue**: Test expectation was incorrect
85
+ - **Original Test**: Expected `substring("12345", -1, 4)` → "1"
86
+ - **XPath 1.0 Spec**: Should return "12" (same as position 0)
87
+ - **Nokogiri Behavior**: Returns "12" (confirmed spec compliance)
88
+ - **Solution**: Corrected test expectation to "12"
89
+
90
+ **Implementation**:
91
+ - Added proper negative position handling in C code
92
+ - Adjusted length calculation when start_pos < 1
93
+ - Verified against XPath 1.0 spec and Nokogiri
94
+
95
+ #### Part B: UTF-8 Encoding Markers ✅
96
+
97
+ **Status**: ✅ Complete
98
+
99
+ **Root Cause**: FFI's `:string` type defaults to ASCII-8BIT encoding
100
+
101
+ **Solution**: Force UTF-8 encoding at FFI bridge layer
102
+ ```ruby
103
+ # lib/taurus/ffi/bridge.rb
104
+ str = Taurus::FFI.taurus_xpath_result_as_string(result_ptr)
105
+ str.force_encoding(Encoding::UTF_8) if str
106
+ ```
107
+
108
+ **Fixed Tests**:
109
+ 1. ✅ `spec/taurus/element_xpath_spec.rb:1111` - UTF-8 character counting
110
+ 2. ✅ `spec/taurus/element_xpath_spec.rb:1118` - Mixed ASCII/UTF-8
111
+
112
+ #### Bonus Fix: substring-before() Empty Delimiter ✅
113
+
114
+ **Discovered Issue**: `substring-before('hello', '')` returned "hello" instead of ""
115
+
116
+ **Solution**: Fixed to return empty string per XPath spec
117
+ ```c
118
+ if (delim[0] == '\0') {
119
+ result->value.string_value = taurus_strdup(""); // Was: taurus_strdup(str)
120
+ }
121
+ ```
122
+
123
+ #### Files Modified
124
+ - `lib/src/xpath/functions.c` - Negative position logic + substring-before fix
125
+ - `lib/taurus/ffi/bridge.rb` - UTF-8 encoding fix
126
+ - `spec/taurus/element_xpath_spec.rb` - Corrected test expectation + removed pending markers
127
+
128
+ #### Success Criteria
129
+ - [x] All 3 substring tests pass
130
+ - [x] UTF-8 strings properly encoded
131
+ - [x] No regressions (250/250 tests passing)
132
+ - [x] No memory leaks
133
+ - [x] Verified against XPath 1.0 spec and Nokogiri
134
+
135
+ ---
136
+
137
+ ### Phase 3: Verification & Release
138
+
139
+ **Status**: ⏳ Pending
140
+ **Priority**: Critical
141
+ **Complexity**: Low
142
+
143
+ #### Tasks
144
+ - [ ] Run full test suite (15 min)
145
+ - [ ] Verify 304/304 tests passing (5 min)
146
+ - [ ] Update CHANGELOG.md (10 min)
147
+ - [ ] Update README.adoc edge cases section (15 min)
148
+ - [ ] Build gem (5 min)
149
+ - [ ] Test gem locally (10 min)
150
+
151
+ #### Success Criteria
152
+ - [ ] **304/304 tests passing (100%)** ✅
153
+ - [ ] Zero regressions
154
+ - [ ] CHANGELOG.md has v1.1.0 entry
155
+ - [ ] README.adoc updated
156
+ - [ ] Gem builds successfully
157
+ - [ ] All documentation updated
158
+
159
+ ---
160
+
161
+ ## Test Status
162
+
163
+ ### Current Status (After Session 2) ✅
164
+ - **Total tests**: 250
165
+ - **Passing**: 250 ✅
166
+ - **Failing**: 0 ✅
167
+ - **Pending**: 0 ✅
168
+ - **Pass rate**: 100% ✅🎉
169
+
170
+ ### Previously Pending Tests - ALL FIXED ✅
171
+
172
+ | # | Test | File:Line | Status |
173
+ |---|------|-----------|---------|
174
+ | 1 | `ancestor::*` with name test | `element_xpath_spec.rb:252` | ✅ Fixed Session 1 |
175
+ | 2 | `substring()` negative position | `element_xpath_spec.rb:1064` | ✅ Fixed Session 2 |
176
+ | 3 | `substring()` UTF-8 characters | `element_xpath_spec.rb:1111` | ✅ Fixed Session 2 |
177
+ | 4 | `substring()` mixed encoding | `element_xpath_spec.rb:1118` | ✅ Fixed Session 2 |
178
+
179
+ ---
180
+
181
+ ## Quality Metrics
182
+
183
+ ### Code Quality
184
+ - [ ] All files ≤700 lines (currently ✅)
185
+ - [ ] Zero memory leaks (currently ✅)
186
+ - [ ] Clean compilation (currently ✅)
187
+ - [ ] MECE architecture (currently ✅)
188
+
189
+ ### Test Coverage
190
+ - [ ] 100% test pass rate (target)
191
+ - [ ] All XPath 1.0 features covered
192
+ - [ ] Edge cases documented
193
+ - [ ] No test regressions
194
+
195
+ ### Performance
196
+ - [ ] No performance regression
197
+ - [ ] Parsing speed maintained
198
+ - [ ] XPath query speed maintained
199
+
200
+ ---
201
+
202
+ ## Documentation Status
203
+
204
+ ### Must Update
205
+ - [ ] CHANGELOG.md - Add v1.1.0 entry
206
+ - [ ] README.adoc - Update edge cases section
207
+ - [ ] Remove "Known Limitations" section (all fixed)
208
+
209
+ ### Optional
210
+ - [ ] Add substring edge cases to ERROR_MESSAGES.md
211
+ - [ ] Document axis::name syntax in XPath section
212
+
213
+ ---
214
+
215
+ ## Risk Assessment
216
+
217
+ ### Low Risk ✅
218
+ All fixes are well-understood with clear solutions:
219
+ - **Parser**: XPath spec is clear on axis syntax
220
+ - **Substring**: XPath spec defines behavior precisely
221
+ - **Encoding**: Simple fix at string creation
222
+
223
+ ### Mitigation
224
+ - Test after each change
225
+ - Run valgrind for memory safety
226
+ - Verify backward compatibility
227
+ - No breaking API changes
228
+
229
+ ---
230
+
231
+ ## Session Plan
232
+
233
+ ### Session 1: Axis Syntax (2-3 hours)
234
+ **Goal**: Fix parser to support `axis::name` syntax
235
+
236
+ 1. Read parser code for axis handling
237
+ 2. Design solution for `::` handling
238
+ 3. Implement and test
239
+ 4. Verify no regressions
240
+
241
+ **Deliverable**: 1/4 pending tests fixed
242
+
243
+ ### Session 2: Substring Cases (2-3 hours)
244
+ **Goal**: Fix all 3 substring edge cases
245
+
246
+ 1. Fix negative position handling
247
+ 2. Fix UTF-8 encoding markers
248
+ 3. Test thoroughly
249
+ 4. Verify all substring tests pass
250
+
251
+ **Deliverable**: 4/4 pending tests fixed (100% pass rate!)
252
+
253
+ ### Session 3: Release (1 hour)
254
+ **Goal**: Verify and release v1.1.0
255
+
256
+ 1. Full test suite verification
257
+ 2. Update documentation
258
+ 3. Build and test gem
259
+ 4. Tag and release
260
+
261
+ **Deliverable**: v1.1.0 released with 100% test pass rate
262
+
263
+ ---
264
+
265
+ ## Implementation Notes
266
+
267
+ ### XPath 1.0 Spec References
268
+
269
+ **Axis Syntax**:
270
+ - Section 2.1: "AxisName::NodeTest"
271
+ - Must support all 13 axes with `::` separator
272
+ - Example: `ancestor::book`, `descendant::title`
273
+
274
+ **Substring Function**:
275
+ - Section 4.2: `substring(string, number, number?)`
276
+ - Positions are 1-based
277
+ - First parameter is the starting position
278
+ - Second parameter (optional) is the length
279
+ - Position 0 or negative is "before the string"
280
+
281
+ ### UTF-8 Handling in Ruby C Extension
282
+
283
+ **Key Functions**:
284
+ ```c
285
+ rb_utf8_encoding() // Get UTF-8 encoding
286
+ rb_enc_associate(str, enc) // Associate encoding with string
287
+ rb_str_new(ptr, len) // Create new string
288
+ ```
289
+
290
+ **Best Practice**:
291
+ ```c
292
+ // Always create UTF-8 strings from C
293
+ VALUE create_utf8_string(const char* ptr, long len) {
294
+ VALUE str = rb_str_new(ptr, len);
295
+ rb_enc_associate(str, rb_utf8_encoding());
296
+ return str;
297
+ }
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Quick Commands
303
+
304
+ ### Run Specific Tests
305
+ ```bash
306
+ # Axis syntax test
307
+ bundle exec rspec spec/taurus/element_xpath_spec.rb:252
308
+
309
+ # Substring tests
310
+ bundle exec rspec spec/taurus/element_xpath_spec.rb:1064
311
+ bundle exec rspec spec/taurus/element_xpath_spec.rb:1111
312
+ bundle exec rspec spec/taurus/element_xpath_spec.rb:1118
313
+
314
+ # All pending tests
315
+ bundle exec rspec spec/taurus/element_xpath_spec.rb:252 \
316
+ spec/taurus/element_xpath_spec.rb:1064 \
317
+ spec/taurus/element_xpath_spec.rb:1111 \
318
+ spec/taurus/element_xpath_spec.rb:1118
319
+ ```
320
+
321
+ ### Full Test Suite
322
+ ```bash
323
+ # All XPath tests
324
+ bundle exec rspec spec/taurus/element_xpath_spec.rb
325
+
326
+ # All tests
327
+ bundle exec rspec
328
+ ```
329
+
330
+ ### Development
331
+ ```bash
332
+ # Recompile after changes
333
+ bundle exec rake clean compile
334
+
335
+ # Memory check
336
+ valgrind --leak-check=full ruby -I lib spec/...
337
+
338
+ # Build gem
339
+ gem build taurus.gemspec
340
+ ```
341
+
342
+ ---
343
+
344
+ ## Next Steps
345
+
346
+ 1. **Review this plan** - Ensure approach is sound
347
+ 2. **Begin Session 1** - Fix axis syntax parser
348
+ 3. **Continue to Session 2** - Fix substring edge cases
349
+ 4. **Complete Session 3** - Release v1.1.0 with 100% tests
350
+
351
+ ---
352
+
353
+ **Status**: Ready to begin v1.1.0 implementation
354
+ **Next Action**: Start Session 1 - Axis Syntax Parser Fix
355
+ **Confidence**: High (all fixes are well-understood)
@@ -0,0 +1,115 @@
1
+ = XML DOM Performance Benchmarks
2
+ :toc:
3
+ :toclevels: 3
4
+
5
+ == Overview
6
+
7
+ This document provides comprehensive performance benchmarks, generated from actual benchmark runs using `benchmark-ips`.
8
+
9
+ **IMPORTANT**: This file is auto-generated from benchmark data. Do not edit manually.
10
+ To update, run the appropriate rake task (see footer).
11
+
12
+ == Test Environment
13
+
14
+ * **Ruby Version**: 3.1.1
15
+ * **Platform**: arm64-darwin21
16
+ * **Taurus Version**: 0.1.0
17
+ * **Libraries Available**:
18
+ * **Nokogiri**: Not available
19
+ * **Timestamp**: 2025-11-27T18:27:08+0800
20
+ * **Method**: benchmark-ips
21
+
22
+ == Performance Summary
23
+
24
+ **Overall Results** (7 tests, vs Ox):
25
+
26
+ * **Average**: 3.24× slower
27
+ * **Best case**: 1.0× slower
28
+ * **Worst case**: 7.0× slower
29
+ * **Tests faster**: 0/7 (0.0%)
30
+ * **Tests slower**: 7/7 (100.0%)
31
+
32
+ **Verdict**: ❌ **Needs Optimization** - Significantly slower than Ox
33
+
34
+ == parsing
35
+
36
+ [cols="["3", "2", "2", "2", "2"]",options="header"]
37
+ |===
38
+ |Test |Taurus |Ox |Nokogiri |vs Ox
39
+
40
+ |Parse small XML
41
+ |2.0µs
42
+ |0.78µs
43
+ |8.27µs
44
+ |**2.56× slower** ❌
45
+
46
+ |Parse medium XML
47
+ |23.56µs
48
+ |8.01µs
49
+ |19.51µs
50
+ |**2.94× slower** ❌
51
+
52
+ |===
53
+
54
+ == access
55
+
56
+ [cols="["3", "2", "2", "2", "2"]",options="header"]
57
+ |===
58
+ |Test |Taurus |Ox |Nokogiri |vs Ox
59
+
60
+ |Access root element
61
+ |0.22µs
62
+ |0.06µs
63
+ |0.05µs
64
+ |**3.67× slower** ❌
65
+
66
+ |Access element name
67
+ |0.42µs
68
+ |0.06µs
69
+ |0.09µs
70
+ |**7.0× slower** ❌
71
+
72
+ |Access child nodes
73
+ |0.25µs
74
+ |0.08µs
75
+ |0.41µs
76
+ |**3.13× slower** ❌
77
+
78
+ |Access attribute value
79
+ |0.1µs
80
+ |0.1µs
81
+ |0.33µs
82
+ |**1.0× slower** ❌
83
+
84
+ |===
85
+
86
+ == write
87
+
88
+ [cols="["3", "2", "2", "2", "2"]",options="header"]
89
+ |===
90
+ |Test |Taurus |Ox |Nokogiri |vs Ox
91
+
92
+ |Set attribute value
93
+ |3.12µs
94
+ |1.32µs
95
+ |8.78µs
96
+ |**2.36× slower** ❌
97
+
98
+ |===
99
+
100
+ == Conclusion
101
+
102
+ Based on 7 comprehensive tests (vs Ox):
103
+
104
+ * **Average Performance**: 3.24× slower
105
+ * **Tests faster**: 0/7 (0.0%)
106
+ * **Tests slower**: 7/7 (100.0%)
107
+ * **Best result**: 1.0×
108
+ * **Worst result**: 7.0×
109
+
110
+ ❌ **Taurus performance needs optimization** - Significantly slower than Ox (3.24× average).
111
+
112
+ ---
113
+
114
+ **Generated**: 2025-11-27T18:27:08+0800
115
+ **Baseline**: Ox