prosereflect 0.1.0 → 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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +4 -0
  3. data/.github/workflows/release.yml +5 -0
  4. data/.rubocop.yml +19 -1
  5. data/.rubocop_todo.yml +143 -174
  6. data/CLAUDE.md +78 -0
  7. data/Gemfile +8 -4
  8. data/README.adoc +193 -12
  9. data/Rakefile +3 -3
  10. data/lib/prosereflect/attribute/base.rb +32 -0
  11. data/lib/prosereflect/attribute/bold.rb +18 -0
  12. data/lib/prosereflect/attribute/href.rb +22 -0
  13. data/lib/prosereflect/attribute/id.rb +24 -0
  14. data/lib/prosereflect/attribute.rb +10 -0
  15. data/lib/prosereflect/blockquote.rb +84 -0
  16. data/lib/prosereflect/bullet_list.rb +84 -0
  17. data/lib/prosereflect/code_block.rb +135 -0
  18. data/lib/prosereflect/code_block_wrapper.rb +65 -0
  19. data/lib/prosereflect/document.rb +93 -26
  20. data/lib/prosereflect/hard_break.rb +13 -11
  21. data/lib/prosereflect/heading.rb +63 -0
  22. data/lib/prosereflect/horizontal_rule.rb +70 -0
  23. data/lib/prosereflect/image.rb +126 -0
  24. data/lib/prosereflect/input/html.rb +484 -0
  25. data/lib/prosereflect/input.rb +7 -0
  26. data/lib/prosereflect/list_item.rb +64 -0
  27. data/lib/prosereflect/mark/base.rb +47 -0
  28. data/lib/prosereflect/mark/bold.rb +13 -0
  29. data/lib/prosereflect/mark/code.rb +12 -0
  30. data/lib/prosereflect/mark/italic.rb +13 -0
  31. data/lib/prosereflect/mark/link.rb +16 -0
  32. data/lib/prosereflect/mark/strike.rb +13 -0
  33. data/lib/prosereflect/mark/subscript.rb +13 -0
  34. data/lib/prosereflect/mark/superscript.rb +13 -0
  35. data/lib/prosereflect/mark/underline.rb +13 -0
  36. data/lib/prosereflect/mark.rb +15 -0
  37. data/lib/prosereflect/node.rb +181 -32
  38. data/lib/prosereflect/ordered_list.rb +86 -0
  39. data/lib/prosereflect/output/html.rb +376 -0
  40. data/lib/prosereflect/output.rb +7 -0
  41. data/lib/prosereflect/paragraph.rb +29 -20
  42. data/lib/prosereflect/parser.rb +101 -33
  43. data/lib/prosereflect/table.rb +42 -12
  44. data/lib/prosereflect/table_cell.rb +36 -11
  45. data/lib/prosereflect/table_header.rb +92 -0
  46. data/lib/prosereflect/table_row.rb +34 -11
  47. data/lib/prosereflect/text.rb +15 -19
  48. data/lib/prosereflect/user.rb +63 -0
  49. data/lib/prosereflect/version.rb +1 -1
  50. data/lib/prosereflect.rb +27 -11
  51. data/prosereflect.gemspec +17 -15
  52. data/spec/prosereflect/document_spec.rb +477 -75
  53. data/spec/prosereflect/hard_break_spec.rb +226 -30
  54. data/spec/prosereflect/input/html_spec.rb +797 -0
  55. data/spec/prosereflect/node_spec.rb +307 -137
  56. data/spec/prosereflect/output/html_spec.rb +369 -0
  57. data/spec/prosereflect/paragraph_spec.rb +458 -82
  58. data/spec/prosereflect/parser_spec.rb +311 -93
  59. data/spec/prosereflect/table_cell_spec.rb +282 -71
  60. data/spec/prosereflect/table_row_spec.rb +218 -48
  61. data/spec/prosereflect/table_spec.rb +415 -82
  62. data/spec/prosereflect/text_spec.rb +231 -72
  63. data/spec/prosereflect/user_spec.rb +76 -0
  64. data/spec/prosereflect_spec.rb +30 -23
  65. data/spec/spec_helper.rb +6 -6
  66. data/spec/support/matchers.rb +6 -6
  67. data/spec/support/shared_examples.rb +79 -50
  68. metadata +53 -6
  69. data/debug_loading.rb +0 -34
  70. data/spec/prosereflect/version_spec.rb +0 -11
@@ -1,38 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "spec_helper"
4
+
3
5
  RSpec.describe Prosereflect::Node do
4
- describe 'initialization' do
5
- it 'initializes with empty data' do
6
+ describe "initialization" do
7
+ it "initializes with empty data" do
6
8
  node = described_class.new
7
9
  expect(node.type).to be_nil
8
10
  expect(node.attrs).to be_nil
9
- expect(node.content).to eq([])
11
+ expect(node.content).to be_nil
10
12
  expect(node.marks).to be_nil
11
13
  end
12
14
 
13
- it 'initializes with provided data' do
15
+ # TODO: Update to lutaml-model
16
+ it "initializes with provided data" do
14
17
  data = {
15
- 'type' => 'test_node',
16
- 'attrs' => { 'key' => 'value' },
17
- 'marks' => [{ 'type' => 'bold' }]
18
+ "type" => "test_node",
19
+ "attrs" => { "key" => "value" },
20
+ "marks" => [{ "type" => "bold" }],
18
21
  }
19
22
  node = described_class.new(data)
20
- expect(node.type).to eq('test_node')
21
- expect(node.attrs).to eq({ 'key' => 'value' })
22
- expect(node.marks).to eq([{ 'type' => 'bold' }])
23
+ expect(node.type).to eq("test_node")
24
+ expect(node.attrs).to eq({ "key" => "value" })
25
+ expect(node.marks).to eq([{ "type" => "bold" }])
23
26
  end
24
27
  end
25
28
 
26
- describe '#parse_content' do
27
- it 'returns empty array for nil content' do
29
+ describe "#parse_content" do
30
+ it "returns empty array for nil content" do
28
31
  node = described_class.new
29
32
  expect(node.parse_content(nil)).to eq([])
30
33
  end
31
34
 
32
- it 'parses content items using Parser' do
35
+ it "parses content items using Parser" do
33
36
  content_data = [
34
- { 'type' => 'text', 'text' => 'Hello' },
35
- { 'type' => 'hard_break' }
37
+ { "type" => "text", "text" => "Hello" },
38
+ { "type" => "hard_break" },
36
39
  ]
37
40
 
38
41
  node = described_class.new
@@ -44,51 +47,52 @@ RSpec.describe Prosereflect::Node do
44
47
  end
45
48
  end
46
49
 
47
- describe '#to_h' do
48
- it 'creates a hash representation with basic properties' do
49
- node = described_class.new({ 'type' => 'test_node' })
50
- hash = node.to_h
50
+ describe "#to_h" do
51
+ it "creates a hash representation with basic properties" do
52
+ node = described_class.new({ "type" => "test_node" })
53
+ hash = node.to_hash
51
54
 
52
55
  expect(hash).to be_a(Hash)
53
- expect(hash['type']).to eq('test_node')
56
+ expect(hash["type"]).to eq("test_node")
54
57
  end
55
58
 
56
- it 'includes attrs when present' do
57
- node = described_class.new({
58
- 'type' => 'test_node',
59
- 'attrs' => { 'key' => 'value' }
60
- })
59
+ it "includes attrs when present" do
60
+ node = described_class.new(
61
+ type: Prosereflect::Text.new(text: "Hello"),
62
+ attrs: [Prosereflect::Attribute::Href.new("https://example.com")],
63
+ )
61
64
 
62
- hash = node.to_h
63
- expect(hash['attrs']).to eq({ 'key' => 'value' })
65
+ hash = node.to_hash
66
+ expect(hash["attrs"]).to eq([{ "href" => "https://example.com" }])
64
67
  end
65
68
 
66
- it 'includes marks when present' do
67
- node = described_class.new({
68
- 'type' => 'test_node',
69
- 'marks' => [{ 'type' => 'bold' }]
70
- })
69
+ it "includes marks when present" do
70
+ node = described_class.new(
71
+ type: Prosereflect::Text.new(text: "Hello"),
72
+ marks: [Prosereflect::Mark::Bold.new],
73
+ )
71
74
 
72
- hash = node.to_h
73
- expect(hash['marks']).to eq([{ 'type' => 'bold' }])
75
+ hash = node.to_hash
76
+ expect(hash["marks"]).to eq([{ "type" => "bold" }])
74
77
  end
75
78
 
76
- it 'includes content when present' do
79
+ it "includes content when present" do
77
80
  node = described_class.new({
78
- 'type' => 'test_node',
79
- 'content' => [{ 'type' => 'text', 'text' => 'Hello' }]
81
+ "type" => "test_node",
82
+ "content" => [{ "type" => "text",
83
+ "text" => "Hello" }],
80
84
  })
81
85
 
82
- hash = node.to_h
83
- expect(hash['content']).to be_an(Array)
84
- expect(hash['content'][0]['type']).to eq('text')
86
+ hash = node.to_hash
87
+ expect(hash["content"]).to be_an(Array)
88
+ expect(hash["content"][0]["type"]).to eq("text")
85
89
  end
86
90
  end
87
91
 
88
- describe '#add_child' do
89
- it 'adds a child node to content' do
90
- parent = described_class.new({ 'type' => 'parent' })
91
- child = described_class.new({ 'type' => 'child' })
92
+ describe "#add_child" do
93
+ it "adds a child node to content" do
94
+ parent = described_class.new({ "type" => "parent" })
95
+ child = described_class.new({ "type" => "child" })
92
96
 
93
97
  parent.add_child(child)
94
98
 
@@ -96,9 +100,9 @@ RSpec.describe Prosereflect::Node do
96
100
  expect(parent.content[0]).to eq(child)
97
101
  end
98
102
 
99
- it 'returns the added child' do
100
- parent = described_class.new({ 'type' => 'parent' })
101
- child = described_class.new({ 'type' => 'child' })
103
+ it "returns the added child" do
104
+ parent = described_class.new({ "type" => "parent" })
105
+ child = described_class.new({ "type" => "child" })
102
106
 
103
107
  result = parent.add_child(child)
104
108
 
@@ -106,151 +110,317 @@ RSpec.describe Prosereflect::Node do
106
110
  end
107
111
  end
108
112
 
109
- describe '#find_first' do
113
+ describe "#find_first" do
110
114
  let(:node) do
111
- root = described_class.new({ 'type' => 'root' })
112
- para = Prosereflect::Paragraph.new({ 'type' => 'paragraph' })
113
- text = Prosereflect::Text.new({ 'type' => 'text', 'text' => 'Hello' })
115
+ root = described_class.new({ "type" => "root" })
116
+ para = Prosereflect::Paragraph.new({ "type" => "paragraph" })
117
+ text = Prosereflect::Text.new({ "type" => "text", "text" => "Hello" })
114
118
 
115
119
  para.add_child(text)
116
120
  root.add_child(para)
117
121
  root
118
122
  end
119
123
 
120
- it 'returns self if type matches' do
121
- result = node.find_first('root')
124
+ it "returns self if type matches" do
125
+ result = node.find_first("root")
122
126
  expect(result).to eq(node)
123
127
  end
124
128
 
125
- it 'finds a child node by type' do
126
- result = node.find_first('paragraph')
129
+ it "finds a child node by type" do
130
+ result = node.find_first("paragraph")
127
131
  expect(result).to be_a(Prosereflect::Paragraph)
128
132
  end
129
133
 
130
- it 'finds a nested node by type' do
131
- result = node.find_first('text')
134
+ it "finds a nested node by type" do
135
+ result = node.find_first("text")
132
136
  expect(result).to be_a(Prosereflect::Text)
133
137
  end
134
138
 
135
- it 'returns nil if no matching node is found' do
136
- result = node.find_first('nonexistent')
139
+ it "returns nil if no matching node is found" do
140
+ result = node.find_first("nonexistent")
137
141
  expect(result).to be_nil
138
142
  end
139
143
  end
140
144
 
141
- describe '.create' do
142
- it 'creates a node with the specified type' do
143
- node = described_class.create('test_node')
144
- expect(node.type).to eq('test_node')
145
- end
145
+ describe ".create" do
146
+ it "creates a simple node" do
147
+ node = described_class.create("test_node")
146
148
 
147
- it 'creates a node with attributes' do
148
- attrs = { 'key' => 'value' }
149
- node = described_class.create('test_node', attrs)
149
+ expected = {
150
+ "type" => "test_node",
151
+ }
150
152
 
151
- expect(node.type).to eq('test_node')
152
- expect(node.attrs).to eq(attrs)
153
+ expect(node.to_h).to eq(expected)
153
154
  end
154
155
 
155
- it 'initializes with empty content' do
156
- node = described_class.create('test_node')
157
- expect(node.content).to eq([])
156
+ it "creates a node with attributes" do
157
+ node = described_class.create("test_node", {
158
+ "key" => "value",
159
+ "number" => 42,
160
+ "flag" => true,
161
+ })
162
+
163
+ expected = {
164
+ "type" => "test_node",
165
+ "attrs" => {
166
+ "key" => "value",
167
+ "number" => 42,
168
+ "flag" => true,
169
+ },
170
+ }
171
+
172
+ expect(node.to_h).to eq(expected)
158
173
  end
159
174
  end
160
175
 
161
- describe '#find_all' do
162
- let(:node) do
163
- root = described_class.new({ 'type' => 'root' })
176
+ describe "node structure" do
177
+ it "creates a node with content" do
178
+ node = described_class.create("parent")
179
+ node.add_child(Prosereflect::Text.create("First child"))
180
+ node.add_child(Prosereflect::Text.create("Second child"))
181
+
182
+ expected = {
183
+ "type" => "parent",
184
+ "content" => [
185
+ {
186
+ "type" => "text",
187
+ "text" => "First child",
188
+ },
189
+ {
190
+ "type" => "text",
191
+ "text" => "Second child",
192
+ },
193
+ ],
194
+ }
164
195
 
165
- para1 = Prosereflect::Paragraph.new({ 'type' => 'paragraph' })
166
- para1.add_child(Prosereflect::Text.new({ 'type' => 'text', 'text' => 'Text 1' }))
196
+ expect(node.to_h).to eq(expected)
197
+ end
167
198
 
168
- para2 = Prosereflect::Paragraph.new({ 'type' => 'paragraph' })
169
- para2.add_child(Prosereflect::Text.new({ 'type' => 'text', 'text' => 'Text 2' }))
199
+ it "creates a node with complex content" do
200
+ node = described_class.create("root")
170
201
 
171
- root.add_child(para1)
172
- root.add_child(para2)
173
- root
174
- end
202
+ # Add a paragraph with formatted text
203
+ para = Prosereflect::Paragraph.create
204
+ para.add_child(Prosereflect::Text.create("Bold", [Prosereflect::Mark::Bold.create]))
205
+ para.add_child(Prosereflect::Text.create(" and "))
206
+ para.add_child(Prosereflect::Text.create("italic", [Prosereflect::Mark::Italic.create]))
207
+ node.add_child(para)
175
208
 
176
- it 'finds all nodes of a specific type' do
177
- paragraphs = node.find_all('paragraph')
178
- expect(paragraphs.size).to eq(2)
179
- expect(paragraphs).to all(be_a(Prosereflect::Paragraph))
209
+ # Add a list
210
+ list = Prosereflect::BulletList.create
211
+ list_item = Prosereflect::ListItem.create
212
+ list_item.add_child(Prosereflect::Paragraph.create)
213
+ list_item.content.first.add_child(Prosereflect::Text.create("List item"))
214
+ list.add_child(list_item)
215
+ node.add_child(list)
216
+
217
+ expected = {
218
+ "type" => "root",
219
+ "content" => [
220
+ {
221
+ "type" => "paragraph",
222
+ "content" => [
223
+ {
224
+ "type" => "text",
225
+ "text" => "Bold",
226
+ "marks" => [{ "type" => "bold" }],
227
+ },
228
+ {
229
+ "type" => "text",
230
+ "text" => " and ",
231
+ },
232
+ {
233
+ "type" => "text",
234
+ "text" => "italic",
235
+ "marks" => [{ "type" => "italic" }],
236
+ },
237
+ ],
238
+ },
239
+ {
240
+ "type" => "bullet_list",
241
+ "attrs" => {
242
+ "bullet_style" => nil,
243
+ },
244
+ "content" => [
245
+ {
246
+ "type" => "list_item",
247
+ "content" => [
248
+ {
249
+ "type" => "paragraph",
250
+ "content" => [
251
+ {
252
+ "type" => "text",
253
+ "text" => "List item",
254
+ },
255
+ ],
256
+ },
257
+ ],
258
+ },
259
+ ],
260
+ },
261
+ ],
262
+ }
263
+
264
+ expect(node.to_h).to eq(expected)
180
265
  end
266
+ end
181
267
 
182
- it 'finds all nested nodes of a specific type' do
183
- texts = node.find_all('text')
184
- expect(texts.size).to eq(2)
185
- expect(texts).to all(be_a(Prosereflect::Text))
268
+ describe "node operations" do
269
+ describe "#add_child" do
270
+ it "adds a child node and returns it" do
271
+ parent = described_class.create("parent")
272
+ child = Prosereflect::Text.create("Child node")
273
+
274
+ result = parent.add_child(child)
275
+ expect(result).to eq(child)
276
+ expect(parent.content).to eq([child])
277
+ end
278
+
279
+ it "maintains child order" do
280
+ parent = described_class.create("parent")
281
+ first = Prosereflect::Text.create("First")
282
+ second = Prosereflect::Text.create("Second")
283
+ third = Prosereflect::Text.create("Third")
284
+
285
+ parent.add_child(first)
286
+ parent.add_child(second)
287
+ parent.add_child(third)
288
+
289
+ expect(parent.content).to eq([first, second, third])
290
+ expect(parent.text_content).to eq("FirstSecondThird")
291
+ end
186
292
  end
187
293
 
188
- it 'returns empty array if no matching nodes are found' do
189
- result = node.find_all('nonexistent')
190
- expect(result).to eq([])
294
+ describe "#find_first" do
295
+ let(:node) do
296
+ root = described_class.create("root")
297
+ para = Prosereflect::Paragraph.create
298
+ text = Prosereflect::Text.create("Hello")
299
+ para.add_child(text)
300
+ root.add_child(para)
301
+ root
302
+ end
303
+
304
+ it "finds nodes by type" do
305
+ expect(node.find_first("root")).to eq(node)
306
+ expect(node.find_first("paragraph")).to be_a(Prosereflect::Paragraph)
307
+ expect(node.find_first("text")).to be_a(Prosereflect::Text)
308
+ expect(node.find_first("nonexistent")).to be_nil
309
+ end
191
310
  end
192
- end
193
311
 
194
- describe '#find_children' do
195
- let(:node) do
196
- root = described_class.new({ 'type' => 'root' })
312
+ describe "#find_all" do
313
+ let(:node) do
314
+ root = described_class.create("root")
197
315
 
198
- root.add_child(Prosereflect::Paragraph.new({ 'type' => 'paragraph' }))
199
- root.add_child(Prosereflect::Table.new({ 'type' => 'table' }))
200
- root.add_child(Prosereflect::Paragraph.new({ 'type' => 'paragraph' }))
316
+ # First paragraph
317
+ para1 = Prosereflect::Paragraph.create
318
+ para1.add_child(Prosereflect::Text.create("First"))
319
+ root.add_child(para1)
201
320
 
202
- root
203
- end
321
+ # Second paragraph
322
+ para2 = Prosereflect::Paragraph.create
323
+ para2.add_child(Prosereflect::Text.create("Second"))
324
+ root.add_child(para2)
204
325
 
205
- it 'finds direct children of a specific type' do
206
- paragraphs = node.find_children('paragraph')
207
- expect(paragraphs.size).to eq(2)
208
- expect(paragraphs).to all(be_a(Prosereflect::Paragraph))
209
- end
326
+ root
327
+ end
210
328
 
211
- it 'returns empty array if no matching children are found' do
212
- result = node.find_children('nonexistent')
213
- expect(result).to eq([])
329
+ it "finds all nodes of a type" do
330
+ expect(node.find_all("paragraph").size).to eq(2)
331
+ expect(node.find_all("text").size).to eq(2)
332
+ expect(node.find_all("nonexistent")).to eq([])
333
+ end
214
334
  end
215
- end
216
335
 
217
- describe '#text_content' do
218
- it 'returns empty string for node without content' do
219
- node = described_class.new({ 'type' => 'empty' })
220
- expect(node.text_content).to eq('')
336
+ describe "#find_children" do
337
+ let(:node) do
338
+ root = described_class.create("root")
339
+ root.add_child(Prosereflect::Paragraph.create)
340
+ root.add_child(Prosereflect::Table.create)
341
+ root.add_child(Prosereflect::Paragraph.create)
342
+ root
343
+ end
344
+
345
+ it "finds direct children by class" do
346
+ paragraphs = node.find_children(Prosereflect::Paragraph)
347
+ expect(paragraphs.size).to eq(2)
348
+ expect(paragraphs).to all(be_a(Prosereflect::Paragraph))
349
+
350
+ tables = node.find_children(Prosereflect::Table)
351
+ expect(tables.size).to eq(1)
352
+ expect(tables.first).to be_a(Prosereflect::Table)
353
+ end
221
354
  end
222
355
 
223
- it 'concatenates text content from all child nodes' do
224
- node = described_class.new({ 'type' => 'parent' })
356
+ describe "#text_content" do
357
+ it "concatenates text from all children" do
358
+ root = described_class.create("root")
225
359
 
226
- para = Prosereflect::Paragraph.new({ 'type' => 'paragraph' })
227
- para.add_child(Prosereflect::Text.new({ 'type' => 'text', 'text' => 'Hello' }))
228
- para.add_child(Prosereflect::HardBreak.new({ 'type' => 'hard_break' }))
229
- para.add_child(Prosereflect::Text.new({ 'type' => 'text', 'text' => 'World' }))
360
+ para = Prosereflect::Paragraph.create
361
+ para.add_child(Prosereflect::Text.create("Hello"))
362
+ para.add_child(Prosereflect::HardBreak.create)
363
+ para.add_child(Prosereflect::Text.create("World"))
364
+ root.add_child(para)
230
365
 
231
- node.add_child(para)
366
+ expect(root.text_content).to eq("Hello\nWorld")
367
+ end
232
368
 
233
- expect(node.text_content).to eq("Hello\nWorld")
369
+ it "returns empty string for empty node" do
370
+ node = described_class.create("empty")
371
+ expect(node.text_content).to eq("")
372
+ end
234
373
  end
235
374
  end
236
375
 
237
- describe '#text_content_with_breaks' do
238
- it 'returns empty string for node without content' do
239
- node = described_class.new({ 'type' => 'empty' })
240
- expect(node.text_content_with_breaks).to eq('')
241
- end
376
+ describe "serialization" do
377
+ it "serializes a node with all properties" do
378
+ node = described_class.create("test_node", {
379
+ "key" => "value",
380
+ "number" => 42,
381
+ })
382
+
383
+ text = Prosereflect::Text.create("Content", [
384
+ Prosereflect::Mark::Bold.create,
385
+ Prosereflect::Mark::Link.create({ "href" => "https://example.com" }),
386
+ ])
387
+
388
+ node.add_child(text)
389
+
390
+ expected = {
391
+ "type" => "test_node",
392
+ "attrs" => {
393
+ "key" => "value",
394
+ "number" => 42,
395
+ },
396
+ "content" => [
397
+ {
398
+ "type" => "text",
399
+ "text" => "Content",
400
+ "marks" => [
401
+ { "type" => "bold" },
402
+ {
403
+ "type" => "link",
404
+ "attrs" => {
405
+ "href" => "https://example.com",
406
+ },
407
+ },
408
+ ],
409
+ },
410
+ ],
411
+ }
242
412
 
243
- it 'includes newlines for hard breaks' do
244
- node = described_class.new({ 'type' => 'parent' })
413
+ expect(node.to_h).to eq(expected)
414
+ end
245
415
 
246
- para = Prosereflect::Paragraph.new({ 'type' => 'paragraph' })
247
- para.add_child(Prosereflect::Text.new({ 'type' => 'text', 'text' => 'Hello' }))
248
- para.add_child(Prosereflect::HardBreak.new({ 'type' => 'hard_break' }))
249
- para.add_child(Prosereflect::Text.new({ 'type' => 'text', 'text' => 'World' }))
416
+ it "omits optional properties when empty" do
417
+ node = described_class.create("test_node")
250
418
 
251
- node.add_child(para)
419
+ expected = {
420
+ "type" => "test_node",
421
+ }
252
422
 
253
- expect(node.text_content_with_breaks).to eq("Hello\nWorld")
423
+ expect(node.to_h).to eq(expected)
254
424
  end
255
425
  end
256
426
  end