leptris 1.5.0-aarch64-linux → 1.6.1-aarch64-linux

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/CLAUDE.md +76 -87
  4. data/Rakefile +1 -1
  5. data/lib/leptris/version.rb +1 -1
  6. data/lib/leptris/xml/cdata.rb +1 -0
  7. data/lib/leptris/xml/comment.rb +1 -0
  8. data/lib/leptris/xml/document.rb +47 -14
  9. data/lib/leptris/xml/element.rb +21 -3
  10. data/lib/leptris/xml/ffi.rb +70 -13
  11. data/lib/leptris/xml/iterparse.rb +57 -0
  12. data/lib/leptris/xml/node.rb +32 -10
  13. data/lib/leptris/xml/node_set.rb +6 -5
  14. data/lib/leptris/xml/processing_instruction.rb +2 -0
  15. data/lib/leptris/xml/pull.rb +123 -0
  16. data/lib/leptris/xml/searchable.rb +5 -2
  17. data/lib/leptris/xml/serialization.rb +20 -2
  18. data/lib/leptris/xml/text.rb +1 -0
  19. data/lib/leptris/xml/xpath.rb +80 -0
  20. data/lib/leptris/xml.rb +6 -2
  21. data/lib/libleptris.so +0 -0
  22. metadata +5 -37
  23. data/TODO.impl/01-architecture.md +0 -217
  24. data/TODO.impl/02-ffi-declarations.md +0 -236
  25. data/TODO.impl/03-document-node-element-nodeset.md +0 -382
  26. data/TODO.impl/04-sax-parser.md +0 -203
  27. data/TODO.impl/05-serialize-c14n-memory-specs-css.md +0 -276
  28. data/docs/ARCHITECTURE.adoc +0 -559
  29. data/docs/BUILD.md +0 -395
  30. data/docs/ERROR_MESSAGES.md +0 -458
  31. data/docs/FFI_ARCHITECTURE.md +0 -439
  32. data/docs/FUTURE_VISION.md +0 -303
  33. data/docs/GITHUB_ACTIONS.md +0 -293
  34. data/docs/OPTIMIZATIONS_IMPLEMENTED.adoc +0 -459
  35. data/docs/PERFORMANCE.adoc +0 -668
  36. data/docs/PERFORMANCE.md +0 -448
  37. data/docs/RELEASE_NOTES_v1.0.0.md +0 -515
  38. data/docs/XPATH_SPEC_COMPLIANCE.md +0 -298
  39. data/docs/completion/leptris.bash +0 -86
  40. data/docs/completion/leptris.zsh +0 -74
  41. data/docs/man/leptris-format.1 +0 -227
  42. data/docs/man/leptris-parse.1 +0 -178
  43. data/docs/man/leptris-xpath.1 +0 -312
  44. data/docs/man/leptris.1 +0 -160
  45. data/docs/v0.9.0_PERFORMANCE_IMPROVEMENTS.md +0 -217
  46. data/docs/v0.9.0_RELEASE_SUMMARY.md +0 -281
  47. data/docs/v1.0.0_CONTINUATION_PLAN.md +0 -172
  48. data/docs/v1.0.0_CONTINUATION_PROMPT.md +0 -382
  49. data/docs/v1.0.0_SESSION_6_CONTINUATION.md +0 -434
  50. data/docs/v1.0.0_SESSION_6_PROMPT.md +0 -231
  51. data/docs/v1.0.0_STATUS_TRACKER.md +0 -224
  52. data/docs/v1.1.0_CONTINUATION_PLAN.md +0 -299
  53. data/docs/v1.1.0_FINAL_CONTINUATION_PLAN.md +0 -201
  54. data/docs/v1.1.0_SESSION_3_PROMPT.md +0 -223
  55. data/docs/v1.1.0_STATUS_TRACKER.md +0 -355
  56. data/docs/xml-performance.adoc +0 -115
  57. data/docs/xpath-performance.adoc +0 -379
@@ -1,276 +0,0 @@
1
- # TODO 5 — Serialization, C14N, memory management, specs, CSS
2
-
3
- ## Serialization
4
-
5
- Wrap `leptris_serialize_document` and `leptris_c14n_canonicalize`.
6
-
7
- ```ruby
8
- # lib/leptris/xml/serialize_options.rb
9
- class Leptris::XML::SerializeOptions < FFI::Struct
10
- layout \
11
- :indent, :int,
12
- :xml_declaration, :int,
13
- :no_empty_tags, :int,
14
- :preserve_whitespace, :int
15
- end
16
-
17
- # Document#to_xml
18
- def to_xml(options = {})
19
- opts = SerializeOptions.new
20
- opts[:indent] = options[:indent] || 0
21
- opts[:xml_declaration] = options[:no_decl] ? 0 : 1
22
- opts[:no_empty_tags] = options[:no_empty_tags] ? 1 : 0
23
- opts[:preserve_whitespace] = options[:preserve_whitespace] ? 1 : 0
24
- ptr = FFI.leptris_serialize_document(@c_ptr, opts.pointer)
25
- return '' if ptr.nil? || ptr.null?
26
- str = ptr.read_string
27
- FFI.leptris_free_string(ptr)
28
- str
29
- end
30
-
31
- # Node#to_xml (serialize just this subtree)
32
- def to_xml(options = {})
33
- # No C API for single-node serialization yet. Use Document serialize
34
- # with a filter, or build the string manually. For v0.4.2, use the
35
- # document-level serialize and post-process. This is a known limitation.
36
- document.to_xml(options)
37
- end
38
-
39
- # Node#inner_html
40
- def inner_html
41
- children.map { |c| c.to_xml }.join
42
- end
43
- ```
44
-
45
- ## C14N (Canonical XML)
46
-
47
- ```ruby
48
- # lib/leptris/xml/c14n.rb
49
- module Leptris::XML
50
- C14N_1_0 = 0
51
- C14N_1_1 = 1
52
- C14N_EXCLUSIVE = 2
53
-
54
- class Document
55
- def canonicalize(mode = C14N_1_0, with_comments = false)
56
- ptr = FFI.leptris_c14n_canonicalize(@c_ptr, mode, with_comments ? 1 : 0)
57
- return '' if ptr.nil? || ptr.null?
58
- str = ptr.read_string
59
- FFI.leptris_free_string(ptr)
60
- str
61
- end
62
- end
63
- end
64
- ```
65
-
66
- ## Memory management
67
-
68
- ### Ownership rules
69
-
70
- | Ruby class | Owns C memory? | Free function |
71
- |-------------|----------------|---------------|
72
- | Document | YES | `leptris_document_free` |
73
- | Node/Element| NO (borrowed) | none (freed by Document) |
74
- | NodeSet | YES (XPath result) | `leptris_xpath_result_free` |
75
- | Attr | NO (borrowed) | none |
76
-
77
- ### Explicit free pattern
78
-
79
- ```ruby
80
- doc = Leptris::XML.parse(xml)
81
- begin
82
- # ... work with doc ...
83
- ensure
84
- doc.free
85
- end
86
- ```
87
-
88
- ### GC safety net
89
-
90
- ```ruby
91
- class Leptris::XML::Document
92
- def self.wrap(ptr)
93
- obj = allocate
94
- obj.instance_variable_set(:@c_ptr, ptr)
95
- ObjectSpace.define_finalizer(obj, finalizer(ptr))
96
- obj
97
- end
98
-
99
- def self.finalizer(ptr)
100
- proc { FFI.leptris_document_free(ptr) if ptr && !ptr.null? }
101
- end
102
-
103
- def free
104
- return unless @c_ptr
105
- FFI.leptris_document_free(@c_ptr)
106
- @c_ptr = nil
107
- # The finalizer still holds the old pointer but Document#free
108
- # already freed it. Add a "freed" flag to detect double-free.
109
- end
110
- end
111
- ```
112
-
113
- **IMPORTANT**: The finalizer must capture the POINTER VALUE, not the
114
- Document object (which would prevent GC). Use `FFI::Pointer` directly
115
- in the finalizer closure.
116
-
117
- ### Prevent use-after-free
118
-
119
- ```ruby
120
- class Leptris::XML::Node
121
- def c_ptr
122
- raise UseAfterFreeError, "document has been freed" unless @document.c_ptr
123
- @c_ptr
124
- end
125
- end
126
- ```
127
-
128
- ## Specs
129
-
130
- ### Structure
131
-
132
- ```
133
- spec/
134
- spec_helper.rb
135
- xml/
136
- parse_spec.rb
137
- document_spec.rb
138
- node_spec.rb
139
- element_spec.rb
140
- node_set_spec.rb
141
- xpath_spec.rb
142
- sax_spec.rb
143
- serialize_spec.rb
144
- c14n_spec.rb
145
- memory_spec.rb
146
- fixtures/
147
- basic.xml
148
- catalog.xml
149
- namespaces.xml
150
- ```
151
-
152
- ### Test against Nokogiri behavior
153
-
154
- Where Nokogiri's behavior is well-defined, match it exactly. The
155
- specs should test:
156
-
157
- ```ruby
158
- # Parse
159
- doc = Leptris::XML.parse('<root><child id="1">text</child></root>')
160
- expect(doc.root.name).to eq('root')
161
- expect(doc.root.children.first['id']).to eq('1')
162
-
163
- # XPath
164
- doc = Leptris::XML.parse('<lib><book/><book/></lib>')
165
- expect(doc.xpath('count(//book)')).to eq(2.0)
166
- expect(doc.xpath('//book').length).to eq(2)
167
- expect(doc.at_xpath('//book')).to be_a(Leptris::XML::Element)
168
-
169
- # Search
170
- doc = Leptris::XML.parse('<root><a class="x"/><a class="y"/></root>')
171
- expect(doc.search('a').length).to eq(2)
172
- expect(doc.at('a')['class']).to eq('x')
173
-
174
- # SAX
175
- class Handler < Leptris::XML::SAX::Document
176
- attr_reader :elements
177
- def initialize; @elements = []; end
178
- def start_element(name, attrs = []); @elements << name; end
179
- end
180
-
181
- h = Handler.new
182
- Leptris::XML::SAX::Parser.new(h).parse('<r><a/><b/></r>')
183
- expect(h.elements).to eq(['r', 'a', 'b'])
184
-
185
- # Serialize
186
- doc = Leptris::XML.parse('<r/>')
187
- expect(doc.to_xml).to match(/<r\/>/)
188
-
189
- # C14N
190
- expect(doc.canonicalize).to include('<r></r>')
191
-
192
- # Memory
193
- doc = Leptris::XML.parse('<r/>')
194
- doc.free
195
- expect { doc.root }.to raise_error(Leptris::XML::UseAfterFreeError)
196
- ```
197
-
198
- ### Conformance
199
-
200
- Run Nokogiri's own test suite against the Leptris binding where
201
- possible. Skip tests for features Leptris doesn't support (HTML5,
202
- XSLT, RelaxNG, DTD validation beyond what libleptris provides).
203
-
204
- ## CSS-to-XPath converter (minimal)
205
-
206
- ```ruby
207
- # lib/leptris/xml/css_to_xpath.rb
208
- module Leptris::XML
209
- module CssToXPath
210
- def self.convert(rule)
211
- parts = rule.strip.split(/\s+/)
212
- xpath_parts = parts.map { |p| convert_part(p) }
213
- '//' + xpath_parts.join('/')
214
- end
215
-
216
- def self.convert_part(part)
217
- # tag → tag
218
- # .class → *[contains(concat(' ', @class,' '),' class ')]
219
- # #id → *[@id='id']
220
- # [attr] → *[@attr]
221
- # [attr=val] → *[@attr='val']
222
- # > child handled by split
223
- # :first-child → *[position()=1]
224
- # :last-child → *[position()=last()]
225
- return '*' if part == '*'
226
-
227
- if part.start_with?('.')
228
- cls = part[1..]
229
- "*[contains(concat(' ',normalize-space(@class),' '),' #{cls} ')]"
230
- elsif part.start_with?('#')
231
- id = part[1..]
232
- "*[@id='#{id}']"
233
- elsif match = part.match(/^(\w+)\[(\w+)='?([^'\]]+)'?\]$/i)
234
- "#{match[1]}[@#{match[2]}='#{match[3]}']"
235
- elsif match = part.match(/^(\w+)\[(\w+)\]$/i)
236
- "#{match[1]}[@#{match[2]}]"
237
- elsif match = part.match(/^(\w+):first-child$/i)
238
- "#{match[1]}[position()=1]"
239
- elsif match = part.match(/^(\w+):last-child$/i)
240
- "#{match[1]}[position()=last()]"
241
- else
242
- part # pass through as tag name
243
- end
244
- end
245
- end
246
- end
247
- ```
248
-
249
- This is a minimal converter. For full CSS3 support, integrate the
250
- `css_parser` gem or port Nokogiri's CSS parser.
251
-
252
- ## File layout summary
253
-
254
- ```
255
- lib/leptris.rb
256
- lib/leptris/xml.rb
257
- lib/leptris/xml/
258
- ffi.rb
259
- document.rb
260
- node.rb
261
- element.rb
262
- text.rb
263
- comment.rb
264
- cdata.rb
265
- processing_instruction.rb
266
- attr.rb
267
- node_set.rb
268
- searchable.rb
269
- parse_options.rb
270
- serialize_options.rb
271
- css_to_xpath.rb
272
- sax.rb
273
- sax/
274
- parser.rb
275
- document.rb
276
- ```