prosereflect 0.1.0 → 0.1.1
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/.rubocop_todo.yml +23 -4
- data/README.adoc +193 -12
- data/lib/prosereflect/attribute/base.rb +34 -0
- data/lib/prosereflect/attribute/bold.rb +20 -0
- data/lib/prosereflect/attribute/href.rb +24 -0
- data/lib/prosereflect/attribute/id.rb +24 -0
- data/lib/prosereflect/attribute.rb +13 -0
- data/lib/prosereflect/blockquote.rb +85 -0
- data/lib/prosereflect/bullet_list.rb +83 -0
- data/lib/prosereflect/code_block.rb +135 -0
- data/lib/prosereflect/code_block_wrapper.rb +66 -0
- data/lib/prosereflect/document.rb +99 -24
- data/lib/prosereflect/hard_break.rb +11 -9
- data/lib/prosereflect/heading.rb +64 -0
- data/lib/prosereflect/horizontal_rule.rb +70 -0
- data/lib/prosereflect/image.rb +126 -0
- data/lib/prosereflect/input/html.rb +505 -0
- data/lib/prosereflect/list_item.rb +65 -0
- data/lib/prosereflect/mark/base.rb +49 -0
- data/lib/prosereflect/mark/bold.rb +15 -0
- data/lib/prosereflect/mark/code.rb +14 -0
- data/lib/prosereflect/mark/italic.rb +15 -0
- data/lib/prosereflect/mark/link.rb +18 -0
- data/lib/prosereflect/mark/strike.rb +15 -0
- data/lib/prosereflect/mark/subscript.rb +15 -0
- data/lib/prosereflect/mark/superscript.rb +15 -0
- data/lib/prosereflect/mark/underline.rb +15 -0
- data/lib/prosereflect/mark.rb +11 -0
- data/lib/prosereflect/node.rb +181 -32
- data/lib/prosereflect/ordered_list.rb +85 -0
- data/lib/prosereflect/output/html.rb +374 -0
- data/lib/prosereflect/paragraph.rb +26 -15
- data/lib/prosereflect/parser.rb +111 -24
- data/lib/prosereflect/table.rb +40 -9
- data/lib/prosereflect/table_cell.rb +33 -8
- data/lib/prosereflect/table_header.rb +92 -0
- data/lib/prosereflect/table_row.rb +31 -8
- data/lib/prosereflect/text.rb +13 -17
- data/lib/prosereflect/user.rb +63 -0
- data/lib/prosereflect/version.rb +1 -1
- data/lib/prosereflect.rb +6 -0
- data/prosereflect.gemspec +1 -0
- data/spec/prosereflect/document_spec.rb +436 -36
- data/spec/prosereflect/hard_break_spec.rb +218 -22
- data/spec/prosereflect/input/html_spec.rb +797 -0
- data/spec/prosereflect/node_spec.rb +258 -89
- data/spec/prosereflect/output/html_spec.rb +369 -0
- data/spec/prosereflect/paragraph_spec.rb +424 -49
- data/spec/prosereflect/parser_spec.rb +304 -91
- data/spec/prosereflect/table_cell_spec.rb +268 -57
- data/spec/prosereflect/table_row_spec.rb +210 -40
- data/spec/prosereflect/table_spec.rb +392 -61
- data/spec/prosereflect/text_spec.rb +206 -48
- data/spec/prosereflect/user_spec.rb +73 -0
- data/spec/prosereflect_spec.rb +5 -0
- data/spec/support/shared_examples.rb +44 -15
- metadata +47 -3
- data/debug_loading.rb +0 -34
@@ -8,26 +8,320 @@ RSpec.describe Prosereflect::Paragraph do
|
|
8
8
|
paragraph = described_class.new({ 'type' => 'paragraph' })
|
9
9
|
expect(paragraph.type).to eq('paragraph')
|
10
10
|
end
|
11
|
+
|
12
|
+
it 'initializes with content' do
|
13
|
+
text_node = Prosereflect::Text.new(text: 'Hello')
|
14
|
+
paragraph = described_class.new
|
15
|
+
paragraph.add_child(text_node)
|
16
|
+
|
17
|
+
expect(paragraph.content.first).to be_a(Prosereflect::Text)
|
18
|
+
expect(paragraph.content.first.text).to eq('Hello')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'initializes with complex content' do
|
22
|
+
content = [
|
23
|
+
{ 'type' => 'text', 'text' => 'Hello', 'marks' => [{ 'type' => 'bold' }] }
|
24
|
+
]
|
25
|
+
paragraph = described_class.new(content: content)
|
26
|
+
|
27
|
+
expect(paragraph.content[0].raw_marks.first.type).to eq('bold')
|
28
|
+
end
|
11
29
|
end
|
12
30
|
|
13
31
|
describe '.create' do
|
14
|
-
it 'creates
|
15
|
-
paragraph = described_class.
|
16
|
-
|
17
|
-
|
18
|
-
|
32
|
+
it 'creates a simple paragraph with text' do
|
33
|
+
paragraph = described_class.new
|
34
|
+
paragraph.add_text('This is a test paragraph.')
|
35
|
+
|
36
|
+
expected = {
|
37
|
+
'type' => 'paragraph',
|
38
|
+
'content' => [{
|
39
|
+
'type' => 'text',
|
40
|
+
'text' => 'This is a test paragraph.'
|
41
|
+
}]
|
42
|
+
}
|
43
|
+
|
44
|
+
expect(paragraph.to_h).to eq(expected)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'creates a paragraph with styled text' do
|
48
|
+
paragraph = described_class.new
|
49
|
+
paragraph.add_text('This is ')
|
50
|
+
paragraph.add_text('bold', [Prosereflect::Mark::Bold.new])
|
51
|
+
paragraph.add_text(' and ')
|
52
|
+
paragraph.add_text('italic', [Prosereflect::Mark::Italic.new])
|
53
|
+
paragraph.add_text(' text.')
|
54
|
+
|
55
|
+
expected = {
|
56
|
+
'type' => 'paragraph',
|
57
|
+
'content' => [{
|
58
|
+
'type' => 'text',
|
59
|
+
'text' => 'This is '
|
60
|
+
}, {
|
61
|
+
'type' => 'text',
|
62
|
+
'text' => 'bold',
|
63
|
+
'marks' => [{
|
64
|
+
'type' => 'bold'
|
65
|
+
}]
|
66
|
+
}, {
|
67
|
+
'type' => 'text',
|
68
|
+
'text' => ' and '
|
69
|
+
}, {
|
70
|
+
'type' => 'text',
|
71
|
+
'text' => 'italic',
|
72
|
+
'marks' => [{
|
73
|
+
'type' => 'italic'
|
74
|
+
}]
|
75
|
+
}, {
|
76
|
+
'type' => 'text',
|
77
|
+
'text' => ' text.'
|
78
|
+
}]
|
79
|
+
}
|
80
|
+
|
81
|
+
expect(paragraph.to_h).to eq(expected)
|
19
82
|
end
|
20
83
|
|
21
|
-
it 'creates a paragraph with
|
22
|
-
|
23
|
-
paragraph
|
24
|
-
|
84
|
+
it 'creates a paragraph with multiple text styles' do
|
85
|
+
paragraph = described_class.new
|
86
|
+
paragraph.add_text('This is ')
|
87
|
+
paragraph.add_text('struck', [Prosereflect::Mark::Strike.new])
|
88
|
+
paragraph.add_text(' and ')
|
89
|
+
paragraph.add_text('underlined', [Prosereflect::Mark::Underline.new])
|
90
|
+
paragraph.add_text(' and ')
|
91
|
+
paragraph.add_text('sub', [Prosereflect::Mark::Subscript.new])
|
92
|
+
paragraph.add_text(' and ')
|
93
|
+
paragraph.add_text('super', [Prosereflect::Mark::Superscript.new])
|
94
|
+
paragraph.add_text(' text.')
|
95
|
+
|
96
|
+
expected = {
|
97
|
+
'type' => 'paragraph',
|
98
|
+
'content' => [{
|
99
|
+
'type' => 'text',
|
100
|
+
'text' => 'This is '
|
101
|
+
}, {
|
102
|
+
'type' => 'text',
|
103
|
+
'text' => 'struck',
|
104
|
+
'marks' => [{
|
105
|
+
'type' => 'strike'
|
106
|
+
}]
|
107
|
+
}, {
|
108
|
+
'type' => 'text',
|
109
|
+
'text' => ' and '
|
110
|
+
}, {
|
111
|
+
'type' => 'text',
|
112
|
+
'text' => 'underlined',
|
113
|
+
'marks' => [{
|
114
|
+
'type' => 'underline'
|
115
|
+
}]
|
116
|
+
}, {
|
117
|
+
'type' => 'text',
|
118
|
+
'text' => ' and '
|
119
|
+
}, {
|
120
|
+
'type' => 'text',
|
121
|
+
'text' => 'sub',
|
122
|
+
'marks' => [{
|
123
|
+
'type' => 'subscript'
|
124
|
+
}]
|
125
|
+
}, {
|
126
|
+
'type' => 'text',
|
127
|
+
'text' => ' and '
|
128
|
+
}, {
|
129
|
+
'type' => 'text',
|
130
|
+
'text' => 'super',
|
131
|
+
'marks' => [{
|
132
|
+
'type' => 'superscript'
|
133
|
+
}]
|
134
|
+
}, {
|
135
|
+
'type' => 'text',
|
136
|
+
'text' => ' text.'
|
137
|
+
}]
|
138
|
+
}
|
139
|
+
|
140
|
+
expect(paragraph.to_h).to eq(expected)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'creates a paragraph with mixed text styles' do
|
144
|
+
paragraph = described_class.new
|
145
|
+
paragraph.add_text('Bold and italic', [
|
146
|
+
Prosereflect::Mark::Bold.new,
|
147
|
+
Prosereflect::Mark::Italic.new
|
148
|
+
])
|
149
|
+
paragraph.add_text(' and ')
|
150
|
+
paragraph.add_text('underlined and struck', [
|
151
|
+
Prosereflect::Mark::Underline.new,
|
152
|
+
Prosereflect::Mark::Strike.new
|
153
|
+
])
|
154
|
+
|
155
|
+
expected = {
|
156
|
+
'type' => 'paragraph',
|
157
|
+
'content' => [{
|
158
|
+
'type' => 'text',
|
159
|
+
'text' => 'Bold and italic',
|
160
|
+
'marks' => [{
|
161
|
+
'type' => 'bold'
|
162
|
+
}, {
|
163
|
+
'type' => 'italic'
|
164
|
+
}]
|
165
|
+
}, {
|
166
|
+
'type' => 'text',
|
167
|
+
'text' => ' and '
|
168
|
+
}, {
|
169
|
+
'type' => 'text',
|
170
|
+
'text' => 'underlined and struck',
|
171
|
+
'marks' => [{
|
172
|
+
'type' => 'underline'
|
173
|
+
}, {
|
174
|
+
'type' => 'strike'
|
175
|
+
}]
|
176
|
+
}]
|
177
|
+
}
|
178
|
+
|
179
|
+
expect(paragraph.to_h).to eq(expected)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'creates a paragraph with line breaks' do
|
183
|
+
paragraph = described_class.new
|
184
|
+
paragraph.add_text('First line')
|
185
|
+
paragraph.add_hard_break
|
186
|
+
paragraph.add_text('Second line')
|
187
|
+
paragraph.add_hard_break
|
188
|
+
paragraph.add_text('Third line')
|
189
|
+
|
190
|
+
expected = {
|
191
|
+
'type' => 'paragraph',
|
192
|
+
'content' => [{
|
193
|
+
'type' => 'text',
|
194
|
+
'text' => 'First line'
|
195
|
+
}, {
|
196
|
+
'type' => 'hard_break'
|
197
|
+
}, {
|
198
|
+
'type' => 'text',
|
199
|
+
'text' => 'Second line'
|
200
|
+
}, {
|
201
|
+
'type' => 'hard_break'
|
202
|
+
}, {
|
203
|
+
'type' => 'text',
|
204
|
+
'text' => 'Third line'
|
205
|
+
}]
|
206
|
+
}
|
207
|
+
|
208
|
+
expect(paragraph.to_h).to eq(expected)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'creates a paragraph with alignment' do
|
212
|
+
paragraph = described_class.new(attrs: { 'align' => 'center' })
|
213
|
+
paragraph.add_text('Centered text')
|
214
|
+
|
215
|
+
expected = {
|
216
|
+
'type' => 'paragraph',
|
217
|
+
'attrs' => {
|
218
|
+
'align' => 'center'
|
219
|
+
},
|
220
|
+
'content' => [{
|
221
|
+
'type' => 'text',
|
222
|
+
'text' => 'Centered text'
|
223
|
+
}]
|
224
|
+
}
|
225
|
+
|
226
|
+
expect(paragraph.to_h).to eq(expected)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'creates a paragraph with complex content' do
|
230
|
+
paragraph = described_class.new
|
231
|
+
paragraph.add_text('A formula: ')
|
232
|
+
paragraph.add_text('H', [Prosereflect::Mark::Bold.new])
|
233
|
+
paragraph.add_text('2', [Prosereflect::Mark::Subscript.new])
|
234
|
+
paragraph.add_text('O + 2H')
|
235
|
+
paragraph.add_text('2', [Prosereflect::Mark::Subscript.new])
|
236
|
+
paragraph.add_text(' → 2H')
|
237
|
+
paragraph.add_text('2', [Prosereflect::Mark::Subscript.new])
|
238
|
+
paragraph.add_text('O')
|
239
|
+
|
240
|
+
expected = {
|
241
|
+
'type' => 'paragraph',
|
242
|
+
'content' => [{
|
243
|
+
'type' => 'text',
|
244
|
+
'text' => 'A formula: '
|
245
|
+
}, {
|
246
|
+
'type' => 'text',
|
247
|
+
'text' => 'H',
|
248
|
+
'marks' => [{
|
249
|
+
'type' => 'bold'
|
250
|
+
}]
|
251
|
+
}, {
|
252
|
+
'type' => 'text',
|
253
|
+
'text' => '2',
|
254
|
+
'marks' => [{
|
255
|
+
'type' => 'subscript'
|
256
|
+
}]
|
257
|
+
}, {
|
258
|
+
'type' => 'text',
|
259
|
+
'text' => 'O + 2H'
|
260
|
+
}, {
|
261
|
+
'type' => 'text',
|
262
|
+
'text' => '2',
|
263
|
+
'marks' => [{
|
264
|
+
'type' => 'subscript'
|
265
|
+
}]
|
266
|
+
}, {
|
267
|
+
'type' => 'text',
|
268
|
+
'text' => ' → 2H'
|
269
|
+
}, {
|
270
|
+
'type' => 'text',
|
271
|
+
'text' => '2',
|
272
|
+
'marks' => [{
|
273
|
+
'type' => 'subscript'
|
274
|
+
}]
|
275
|
+
}, {
|
276
|
+
'type' => 'text',
|
277
|
+
'text' => 'O'
|
278
|
+
}]
|
279
|
+
}
|
280
|
+
|
281
|
+
expect(paragraph.to_h).to eq(expected)
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'creates a paragraph with mathematical expressions' do
|
285
|
+
paragraph = described_class.new
|
286
|
+
paragraph.add_text('The quadratic formula: x = -b ± ')
|
287
|
+
paragraph.add_text('√', [Prosereflect::Mark::Bold.new])
|
288
|
+
paragraph.add_text('(b')
|
289
|
+
paragraph.add_text('2', [Prosereflect::Mark::Superscript.new])
|
290
|
+
paragraph.add_text(' - 4ac) / 2a')
|
291
|
+
|
292
|
+
expected = {
|
293
|
+
'type' => 'paragraph',
|
294
|
+
'content' => [{
|
295
|
+
'type' => 'text',
|
296
|
+
'text' => 'The quadratic formula: x = -b ± '
|
297
|
+
}, {
|
298
|
+
'type' => 'text',
|
299
|
+
'text' => '√',
|
300
|
+
'marks' => [{
|
301
|
+
'type' => 'bold'
|
302
|
+
}]
|
303
|
+
}, {
|
304
|
+
'type' => 'text',
|
305
|
+
'text' => '(b'
|
306
|
+
}, {
|
307
|
+
'type' => 'text',
|
308
|
+
'text' => '2',
|
309
|
+
'marks' => [{
|
310
|
+
'type' => 'superscript'
|
311
|
+
}]
|
312
|
+
}, {
|
313
|
+
'type' => 'text',
|
314
|
+
'text' => ' - 4ac) / 2a'
|
315
|
+
}]
|
316
|
+
}
|
317
|
+
|
318
|
+
expect(paragraph.to_h).to eq(expected)
|
25
319
|
end
|
26
320
|
end
|
27
321
|
|
28
322
|
describe '#text_nodes' do
|
29
323
|
it 'returns all text nodes in the paragraph' do
|
30
|
-
paragraph = described_class.
|
324
|
+
paragraph = described_class.new
|
31
325
|
paragraph.add_text('First text')
|
32
326
|
paragraph.add_text('Second text')
|
33
327
|
|
@@ -36,27 +330,42 @@ RSpec.describe Prosereflect::Paragraph do
|
|
36
330
|
end
|
37
331
|
|
38
332
|
it 'returns empty array for paragraph with no text nodes' do
|
39
|
-
paragraph = described_class.
|
333
|
+
paragraph = described_class.new
|
40
334
|
expect(paragraph.text_nodes).to eq([])
|
41
335
|
end
|
42
|
-
end
|
43
336
|
|
44
|
-
|
45
|
-
|
46
|
-
paragraph
|
47
|
-
paragraph.add_text('First text')
|
48
|
-
paragraph.add_text(' Second text')
|
337
|
+
it 'returns text nodes with marks' do
|
338
|
+
paragraph = described_class.new
|
339
|
+
paragraph.add_text('Hello', [Prosereflect::Mark::Bold.new])
|
49
340
|
|
50
|
-
expect(paragraph.
|
341
|
+
expect(paragraph.text_nodes[0].raw_marks.first.type).to eq('bold')
|
51
342
|
end
|
52
343
|
|
53
|
-
it '
|
54
|
-
paragraph = described_class.
|
55
|
-
|
344
|
+
it 'ignores non-text nodes' do
|
345
|
+
paragraph = described_class.new
|
346
|
+
paragraph.add_text('Text')
|
347
|
+
paragraph.add_hard_break
|
348
|
+
paragraph.add_text('More text')
|
349
|
+
|
350
|
+
expect(paragraph.text_nodes.size).to eq(2)
|
351
|
+
expect(paragraph.text_nodes.map(&:text)).to eq(['Text', 'More text'])
|
56
352
|
end
|
353
|
+
end
|
57
354
|
|
58
|
-
|
59
|
-
|
355
|
+
describe '#text_content' do
|
356
|
+
it 'returns plain text content without marks' do
|
357
|
+
paragraph = described_class.new
|
358
|
+
paragraph.add_text('This is ')
|
359
|
+
paragraph.add_text('bold', [Prosereflect::Mark::Bold.new])
|
360
|
+
paragraph.add_text(' and ')
|
361
|
+
paragraph.add_text('italic', [Prosereflect::Mark::Italic.new])
|
362
|
+
paragraph.add_text(' text.')
|
363
|
+
|
364
|
+
expect(paragraph.text_content).to eq('This is bold and italic text.')
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'handles line breaks in text content' do
|
368
|
+
paragraph = described_class.new
|
60
369
|
paragraph.add_text('First line')
|
61
370
|
paragraph.add_hard_break
|
62
371
|
paragraph.add_text('Second line')
|
@@ -64,26 +373,15 @@ RSpec.describe Prosereflect::Paragraph do
|
|
64
373
|
expect(paragraph.text_content).to eq("First line\nSecond line")
|
65
374
|
end
|
66
375
|
|
67
|
-
it 'handles
|
68
|
-
paragraph = described_class.
|
69
|
-
paragraph.
|
70
|
-
|
71
|
-
# Add a custom node that is neither text nor hard_break
|
72
|
-
custom_node = Prosereflect::Node.create('custom_node')
|
73
|
-
custom_node.instance_eval do
|
74
|
-
def text_content
|
75
|
-
'custom content'
|
76
|
-
end
|
77
|
-
end
|
78
|
-
paragraph.add_child(custom_node)
|
79
|
-
|
80
|
-
expect(paragraph.text_content).to eq('Text with custom content')
|
376
|
+
it 'handles empty paragraphs' do
|
377
|
+
paragraph = described_class.new
|
378
|
+
expect(paragraph.text_content).to eq('')
|
81
379
|
end
|
82
380
|
end
|
83
381
|
|
84
382
|
describe '#add_text' do
|
85
383
|
it 'adds text to the paragraph' do
|
86
|
-
paragraph = described_class.
|
384
|
+
paragraph = described_class.new
|
87
385
|
text_node = paragraph.add_text('Hello world')
|
88
386
|
|
89
387
|
expect(paragraph.content.size).to eq(1)
|
@@ -92,15 +390,27 @@ RSpec.describe Prosereflect::Paragraph do
|
|
92
390
|
end
|
93
391
|
|
94
392
|
it 'adds text with marks' do
|
95
|
-
paragraph = described_class.
|
96
|
-
marks = [
|
97
|
-
text_node = paragraph.add_text('
|
393
|
+
paragraph = described_class.new
|
394
|
+
marks = [Prosereflect::Mark::Bold.new]
|
395
|
+
text_node = paragraph.add_text('Hello', marks)
|
98
396
|
|
99
|
-
expect(text_node.
|
397
|
+
expect(text_node.raw_marks).to eq(marks)
|
398
|
+
end
|
399
|
+
|
400
|
+
it 'adds text with multiple marks' do
|
401
|
+
paragraph = described_class.new
|
402
|
+
marks = [
|
403
|
+
Prosereflect::Mark::Bold.new,
|
404
|
+
Prosereflect::Mark::Italic.new,
|
405
|
+
Prosereflect::Mark::Underline.new
|
406
|
+
]
|
407
|
+
text_node = paragraph.add_text('Hello', marks)
|
408
|
+
|
409
|
+
expect(text_node.raw_marks.map(&:type)).to eq(%w[bold italic underline])
|
100
410
|
end
|
101
411
|
|
102
412
|
it 'does not add empty text' do
|
103
|
-
paragraph = described_class.
|
413
|
+
paragraph = described_class.new
|
104
414
|
result = paragraph.add_text('')
|
105
415
|
|
106
416
|
expect(paragraph.content).to be_empty
|
@@ -108,17 +418,27 @@ RSpec.describe Prosereflect::Paragraph do
|
|
108
418
|
end
|
109
419
|
|
110
420
|
it 'does not add nil text' do
|
111
|
-
paragraph = described_class.
|
421
|
+
paragraph = described_class.new
|
112
422
|
result = paragraph.add_text(nil)
|
113
423
|
|
114
424
|
expect(paragraph.content).to be_empty
|
115
425
|
expect(result).to be_nil
|
116
426
|
end
|
427
|
+
|
428
|
+
it 'preserves existing content when adding text' do
|
429
|
+
paragraph = described_class.new
|
430
|
+
paragraph.add_text('First')
|
431
|
+
paragraph.add_hard_break
|
432
|
+
paragraph.add_text('Second')
|
433
|
+
|
434
|
+
expect(paragraph.content.size).to eq(3)
|
435
|
+
expect(paragraph.text_content).to eq("First\nSecond")
|
436
|
+
end
|
117
437
|
end
|
118
438
|
|
119
439
|
describe '#add_hard_break' do
|
120
440
|
it 'adds a hard break to the paragraph' do
|
121
|
-
paragraph = described_class.
|
441
|
+
paragraph = described_class.new
|
122
442
|
hard_break = paragraph.add_hard_break
|
123
443
|
|
124
444
|
expect(paragraph.content.size).to eq(1)
|
@@ -126,17 +446,37 @@ RSpec.describe Prosereflect::Paragraph do
|
|
126
446
|
end
|
127
447
|
|
128
448
|
it 'adds a hard break with marks' do
|
129
|
-
paragraph = described_class.
|
130
|
-
marks = [
|
449
|
+
paragraph = described_class.new
|
450
|
+
marks = [Prosereflect::Mark::Italic.new]
|
131
451
|
hard_break = paragraph.add_hard_break(marks)
|
132
452
|
|
133
|
-
expect(hard_break.
|
453
|
+
expect(hard_break.raw_marks).to eq(marks)
|
454
|
+
end
|
455
|
+
|
456
|
+
it 'adds multiple hard breaks' do
|
457
|
+
paragraph = described_class.new
|
458
|
+
paragraph.add_hard_break
|
459
|
+
paragraph.add_hard_break
|
460
|
+
paragraph.add_hard_break
|
461
|
+
|
462
|
+
expect(paragraph.content.size).to eq(3)
|
463
|
+
expect(paragraph.content).to all(be_a(Prosereflect::HardBreak))
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'preserves existing content when adding hard breaks' do
|
467
|
+
paragraph = described_class.new
|
468
|
+
paragraph.add_text('Text')
|
469
|
+
paragraph.add_hard_break
|
470
|
+
paragraph.add_text('More')
|
471
|
+
|
472
|
+
expect(paragraph.content.size).to eq(3)
|
473
|
+
expect(paragraph.text_content).to eq("Text\nMore")
|
134
474
|
end
|
135
475
|
end
|
136
476
|
|
137
477
|
describe 'serialization' do
|
138
478
|
it 'converts to hash representation' do
|
139
|
-
paragraph = described_class.
|
479
|
+
paragraph = described_class.new
|
140
480
|
paragraph.add_text('Hello')
|
141
481
|
paragraph.add_hard_break
|
142
482
|
paragraph.add_text('World')
|
@@ -148,5 +488,40 @@ RSpec.describe Prosereflect::Paragraph do
|
|
148
488
|
expect(hash['content'][1]['type']).to eq('hard_break')
|
149
489
|
expect(hash['content'][2]['type']).to eq('text')
|
150
490
|
end
|
491
|
+
|
492
|
+
it 'converts to hash with marks' do
|
493
|
+
paragraph = described_class.new
|
494
|
+
paragraph.add_text('Bold', [Prosereflect::Mark::Bold.new])
|
495
|
+
paragraph.add_text(' and ')
|
496
|
+
paragraph.add_text('italic', [Prosereflect::Mark::Italic.new])
|
497
|
+
|
498
|
+
hash = paragraph.to_h
|
499
|
+
expect(hash['content'][0]['marks'][0]['type']).to eq('bold')
|
500
|
+
expect(hash['content'][2]['marks'][0]['type']).to eq('italic')
|
501
|
+
end
|
502
|
+
|
503
|
+
it 'converts to hash with attributes' do
|
504
|
+
paragraph = described_class.new(attrs: { 'align' => 'center' })
|
505
|
+
paragraph.add_text('Centered text')
|
506
|
+
|
507
|
+
hash = paragraph.to_h
|
508
|
+
expect(hash['attrs']).to eq({ 'align' => 'center' })
|
509
|
+
end
|
510
|
+
|
511
|
+
it 'converts complex content to hash' do
|
512
|
+
paragraph = described_class.new
|
513
|
+
paragraph.add_text('Mixed', [
|
514
|
+
Prosereflect::Mark::Bold.new,
|
515
|
+
Prosereflect::Mark::Italic.new
|
516
|
+
])
|
517
|
+
paragraph.add_hard_break([Prosereflect::Mark::Strike.new])
|
518
|
+
paragraph.add_text('Styles')
|
519
|
+
|
520
|
+
hash = paragraph.to_h
|
521
|
+
expect(hash['content'].size).to eq(3)
|
522
|
+
expect(hash['content'][0]['marks'].size).to eq(2)
|
523
|
+
expect(hash['content'][1]['marks'].size).to eq(1)
|
524
|
+
expect(hash['content'][2]['marks']).to be_nil
|
525
|
+
end
|
151
526
|
end
|
152
527
|
end
|