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
@@ -13,96 +13,307 @@ RSpec.describe Prosereflect::TableCell do
|
|
13
13
|
describe '.create' do
|
14
14
|
it 'creates an empty table cell' do
|
15
15
|
cell = described_class.create
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
|
17
|
+
expected = {
|
18
|
+
'type' => 'table_cell',
|
19
|
+
'content' => []
|
20
|
+
}
|
21
|
+
|
22
|
+
expect(cell.to_h).to eq(expected)
|
19
23
|
end
|
20
24
|
|
21
25
|
it 'creates a table cell with attributes' do
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
cell = described_class.create(attrs: {
|
27
|
+
'colspan' => 2,
|
28
|
+
'rowspan' => 1,
|
29
|
+
'background' => '#f5f5f5',
|
30
|
+
'align' => 'center',
|
31
|
+
'valign' => 'middle'
|
32
|
+
})
|
33
|
+
|
34
|
+
expected = {
|
35
|
+
'type' => 'table_cell',
|
36
|
+
'attrs' => {
|
37
|
+
'colspan' => 2,
|
38
|
+
'rowspan' => 1,
|
39
|
+
'background' => '#f5f5f5',
|
40
|
+
'align' => 'center',
|
41
|
+
'valign' => 'middle'
|
42
|
+
},
|
43
|
+
'content' => []
|
44
|
+
}
|
45
|
+
|
46
|
+
expect(cell.to_h).to eq(expected)
|
25
47
|
end
|
26
48
|
end
|
27
49
|
|
28
|
-
describe '
|
29
|
-
it '
|
50
|
+
describe 'cell structure' do
|
51
|
+
it 'creates a cell with simple text content' do
|
30
52
|
cell = described_class.create
|
31
|
-
cell.add_paragraph('
|
32
|
-
cell.add_paragraph('Para 2')
|
53
|
+
cell.add_paragraph('Simple text')
|
33
54
|
|
34
|
-
|
35
|
-
|
36
|
-
|
55
|
+
expected = {
|
56
|
+
'type' => 'table_cell',
|
57
|
+
'content' => [{
|
58
|
+
'type' => 'paragraph',
|
59
|
+
'content' => [{
|
60
|
+
'type' => 'text',
|
61
|
+
'text' => 'Simple text'
|
62
|
+
}]
|
63
|
+
}]
|
64
|
+
}
|
37
65
|
|
38
|
-
|
39
|
-
cell = described_class.create
|
40
|
-
expect(cell.paragraphs).to eq([])
|
66
|
+
expect(cell.to_h).to eq(expected)
|
41
67
|
end
|
42
|
-
end
|
43
68
|
|
44
|
-
|
45
|
-
it 'returns concatenated text from all paragraphs with newlines' do
|
69
|
+
it 'creates a cell with complex content' do
|
46
70
|
cell = described_class.create
|
47
|
-
cell.add_paragraph('First paragraph')
|
48
|
-
cell.add_paragraph('Second paragraph')
|
49
71
|
|
50
|
-
|
51
|
-
|
72
|
+
# First paragraph with mixed formatting
|
73
|
+
para = cell.add_paragraph('This is ')
|
74
|
+
para.add_text('bold', [Prosereflect::Mark::Bold.new])
|
75
|
+
para.add_text(' and ')
|
76
|
+
para.add_text('italic', [Prosereflect::Mark::Italic.new])
|
77
|
+
para.add_hard_break
|
78
|
+
para.add_text('with a line break')
|
52
79
|
|
53
|
-
|
54
|
-
|
55
|
-
|
80
|
+
# Second paragraph with more formatting
|
81
|
+
para = cell.add_paragraph
|
82
|
+
para.add_text('Status: ', [Prosereflect::Mark::Bold.new])
|
83
|
+
para.add_text('Done', [Prosereflect::Mark::Strike.new])
|
84
|
+
para.add_text(' → ')
|
85
|
+
para.add_text('In Progress', [Prosereflect::Mark::Italic.new])
|
86
|
+
|
87
|
+
expected = {
|
88
|
+
'type' => 'table_cell',
|
89
|
+
'content' => [{
|
90
|
+
'type' => 'paragraph',
|
91
|
+
'content' => [{
|
92
|
+
'type' => 'text',
|
93
|
+
'text' => 'This is '
|
94
|
+
}, {
|
95
|
+
'type' => 'text',
|
96
|
+
'text' => 'bold',
|
97
|
+
'marks' => [{
|
98
|
+
'type' => 'bold'
|
99
|
+
}]
|
100
|
+
}, {
|
101
|
+
'type' => 'text',
|
102
|
+
'text' => ' and '
|
103
|
+
}, {
|
104
|
+
'type' => 'text',
|
105
|
+
'text' => 'italic',
|
106
|
+
'marks' => [{
|
107
|
+
'type' => 'italic'
|
108
|
+
}]
|
109
|
+
}, {
|
110
|
+
'type' => 'hard_break'
|
111
|
+
}, {
|
112
|
+
'type' => 'text',
|
113
|
+
'text' => 'with a line break'
|
114
|
+
}]
|
115
|
+
}, {
|
116
|
+
'type' => 'paragraph',
|
117
|
+
'content' => [{
|
118
|
+
'type' => 'text',
|
119
|
+
'text' => 'Status: ',
|
120
|
+
'marks' => [{
|
121
|
+
'type' => 'bold'
|
122
|
+
}]
|
123
|
+
}, {
|
124
|
+
'type' => 'text',
|
125
|
+
'text' => 'Done',
|
126
|
+
'marks' => [{
|
127
|
+
'type' => 'strike'
|
128
|
+
}]
|
129
|
+
}, {
|
130
|
+
'type' => 'text',
|
131
|
+
'text' => ' → '
|
132
|
+
}, {
|
133
|
+
'type' => 'text',
|
134
|
+
'text' => 'In Progress',
|
135
|
+
'marks' => [{
|
136
|
+
'type' => 'italic'
|
137
|
+
}]
|
138
|
+
}]
|
139
|
+
}]
|
140
|
+
}
|
141
|
+
|
142
|
+
expect(cell.to_h).to eq(expected)
|
56
143
|
end
|
57
144
|
end
|
58
145
|
|
59
|
-
describe '
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
146
|
+
describe 'cell operations' do
|
147
|
+
let(:cell) do
|
148
|
+
c = described_class.create
|
149
|
+
c.add_paragraph('First paragraph')
|
150
|
+
c.add_paragraph('Second paragraph')
|
151
|
+
c.add_paragraph('Third paragraph')
|
152
|
+
c
|
66
153
|
end
|
67
154
|
|
68
|
-
|
69
|
-
cell
|
70
|
-
|
155
|
+
describe '#paragraphs' do
|
156
|
+
it 'returns all paragraphs in the cell' do
|
157
|
+
expect(cell.paragraphs.size).to eq(3)
|
158
|
+
expect(cell.paragraphs).to all(be_a(Prosereflect::Paragraph))
|
159
|
+
expect(cell.paragraphs.map(&:text_content)).to eq([
|
160
|
+
'First paragraph',
|
161
|
+
'Second paragraph',
|
162
|
+
'Third paragraph'
|
163
|
+
])
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'returns empty array for cell with no paragraphs' do
|
167
|
+
empty_cell = described_class.create
|
168
|
+
expect(empty_cell.paragraphs).to eq([])
|
169
|
+
end
|
71
170
|
end
|
72
171
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
172
|
+
describe '#text_content' do
|
173
|
+
it 'returns concatenated text from all paragraphs with newlines' do
|
174
|
+
expect(cell.text_content).to eq("First paragraph\nSecond paragraph\nThird paragraph")
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns empty string for empty cell' do
|
178
|
+
empty_cell = described_class.create
|
179
|
+
expect(empty_cell.text_content).to eq('')
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'handles complex formatting and line breaks' do
|
183
|
+
cell = described_class.create
|
184
|
+
para = cell.add_paragraph('Line 1')
|
185
|
+
para.add_hard_break
|
186
|
+
para.add_text('Line 2', [Prosereflect::Mark::Bold.new])
|
187
|
+
para.add_hard_break
|
188
|
+
para.add_text('Line 3', [Prosereflect::Mark::Italic.new])
|
78
189
|
|
79
|
-
|
190
|
+
expect(cell.text_content).to eq("Line 1\nLine 2\nLine 3")
|
191
|
+
end
|
80
192
|
end
|
81
|
-
end
|
82
193
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
194
|
+
describe '#lines' do
|
195
|
+
it 'splits text content into lines' do
|
196
|
+
expect(cell.lines).to eq([
|
197
|
+
'First paragraph',
|
198
|
+
'Second paragraph',
|
199
|
+
'Third paragraph'
|
200
|
+
])
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'returns empty array for empty cell' do
|
204
|
+
empty_cell = described_class.create
|
205
|
+
expect(empty_cell.lines).to eq([])
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'handles hard breaks within paragraphs' do
|
209
|
+
cell = described_class.create
|
210
|
+
para = cell.add_paragraph('First line')
|
211
|
+
para.add_hard_break
|
212
|
+
para.add_text('Second line')
|
213
|
+
cell.add_paragraph('Third line')
|
87
214
|
|
88
|
-
|
89
|
-
|
90
|
-
|
215
|
+
expect(cell.lines).to eq([
|
216
|
+
'First line',
|
217
|
+
'Second line',
|
218
|
+
'Third line'
|
219
|
+
])
|
220
|
+
end
|
91
221
|
end
|
92
222
|
|
93
|
-
|
94
|
-
|
95
|
-
|
223
|
+
describe '#add_paragraph' do
|
224
|
+
it 'adds a paragraph with text and formatting' do
|
225
|
+
cell = described_class.create
|
226
|
+
para = cell.add_paragraph('Main text')
|
227
|
+
para.add_text(' (', [Prosereflect::Mark::Bold.new])
|
228
|
+
para.add_text('important', [Prosereflect::Mark::Bold.new, Prosereflect::Mark::Italic.new])
|
229
|
+
para.add_text(')', [Prosereflect::Mark::Bold.new])
|
230
|
+
|
231
|
+
expected = {
|
232
|
+
'type' => 'table_cell',
|
233
|
+
'content' => [{
|
234
|
+
'type' => 'paragraph',
|
235
|
+
'content' => [{
|
236
|
+
'type' => 'text',
|
237
|
+
'text' => 'Main text'
|
238
|
+
}, {
|
239
|
+
'type' => 'text',
|
240
|
+
'text' => ' (',
|
241
|
+
'marks' => [{
|
242
|
+
'type' => 'bold'
|
243
|
+
}]
|
244
|
+
}, {
|
245
|
+
'type' => 'text',
|
246
|
+
'text' => 'important',
|
247
|
+
'marks' => [{
|
248
|
+
'type' => 'bold'
|
249
|
+
}, {
|
250
|
+
'type' => 'italic'
|
251
|
+
}]
|
252
|
+
}, {
|
253
|
+
'type' => 'text',
|
254
|
+
'text' => ')',
|
255
|
+
'marks' => [{
|
256
|
+
'type' => 'bold'
|
257
|
+
}]
|
258
|
+
}]
|
259
|
+
}]
|
260
|
+
}
|
261
|
+
|
262
|
+
expect(cell.to_h).to eq(expected)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'adds multiple paragraphs with mixed content' do
|
266
|
+
cell = described_class.create
|
96
267
|
|
97
|
-
|
98
|
-
|
99
|
-
|
268
|
+
# First paragraph with hard break
|
269
|
+
para = cell.add_paragraph('Title')
|
270
|
+
para.add_hard_break
|
271
|
+
para.add_text('Subtitle', [Prosereflect::Mark::Italic.new])
|
272
|
+
|
273
|
+
# Second paragraph with mixed formatting
|
274
|
+
para = cell.add_paragraph
|
275
|
+
para.add_text('Note: ', [Prosereflect::Mark::Bold.new])
|
276
|
+
para.add_text('This is important')
|
277
|
+
|
278
|
+
expected = {
|
279
|
+
'type' => 'table_cell',
|
280
|
+
'content' => [{
|
281
|
+
'type' => 'paragraph',
|
282
|
+
'content' => [{
|
283
|
+
'type' => 'text',
|
284
|
+
'text' => 'Title'
|
285
|
+
}, {
|
286
|
+
'type' => 'hard_break'
|
287
|
+
}, {
|
288
|
+
'type' => 'text',
|
289
|
+
'text' => 'Subtitle',
|
290
|
+
'marks' => [{
|
291
|
+
'type' => 'italic'
|
292
|
+
}]
|
293
|
+
}]
|
294
|
+
}, {
|
295
|
+
'type' => 'paragraph',
|
296
|
+
'content' => [{
|
297
|
+
'type' => 'text',
|
298
|
+
'text' => 'Note: ',
|
299
|
+
'marks' => [{
|
300
|
+
'type' => 'bold'
|
301
|
+
}]
|
302
|
+
}, {
|
303
|
+
'type' => 'text',
|
304
|
+
'text' => 'This is important'
|
305
|
+
}]
|
306
|
+
}]
|
307
|
+
}
|
308
|
+
|
309
|
+
expect(cell.to_h).to eq(expected)
|
310
|
+
end
|
100
311
|
end
|
101
312
|
end
|
102
313
|
|
103
314
|
describe 'serialization' do
|
104
315
|
it 'converts to hash representation' do
|
105
|
-
cell = described_class.
|
316
|
+
cell = described_class.new
|
106
317
|
cell.add_paragraph('Test content')
|
107
318
|
|
108
319
|
hash = cell.to_h
|
@@ -13,65 +13,235 @@ RSpec.describe Prosereflect::TableRow do
|
|
13
13
|
describe '.create' do
|
14
14
|
it 'creates an empty table row' do
|
15
15
|
row = described_class.create
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
|
17
|
+
expected = {
|
18
|
+
'type' => 'table_row',
|
19
|
+
'content' => []
|
20
|
+
}
|
21
|
+
|
22
|
+
expect(row.to_h).to eq(expected)
|
19
23
|
end
|
20
24
|
|
21
25
|
it 'creates a table row with attributes' do
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
row = described_class.create(attrs: {
|
27
|
+
'background' => '#f5f5f5',
|
28
|
+
'height' => '40px',
|
29
|
+
'alignment' => 'center'
|
30
|
+
})
|
31
|
+
|
32
|
+
expected = {
|
33
|
+
'type' => 'table_row',
|
34
|
+
'attrs' => {
|
35
|
+
'background' => '#f5f5f5',
|
36
|
+
'height' => '40px',
|
37
|
+
'alignment' => 'center'
|
38
|
+
},
|
39
|
+
'content' => []
|
40
|
+
}
|
41
|
+
|
42
|
+
expect(row.to_h).to eq(expected)
|
25
43
|
end
|
26
44
|
end
|
27
45
|
|
28
|
-
describe '
|
29
|
-
it '
|
46
|
+
describe 'row structure' do
|
47
|
+
it 'creates a row with simple text cells' do
|
30
48
|
row = described_class.create
|
31
|
-
row.add_cell('
|
32
|
-
row.add_cell('
|
49
|
+
row.add_cell('First')
|
50
|
+
row.add_cell('Second')
|
51
|
+
row.add_cell('Third')
|
33
52
|
|
34
|
-
|
35
|
-
|
36
|
-
|
53
|
+
expected = {
|
54
|
+
'type' => 'table_row',
|
55
|
+
'content' => [{
|
56
|
+
'type' => 'table_cell',
|
57
|
+
'content' => [{
|
58
|
+
'type' => 'paragraph',
|
59
|
+
'content' => [{
|
60
|
+
'type' => 'text',
|
61
|
+
'text' => 'First'
|
62
|
+
}]
|
63
|
+
}]
|
64
|
+
}, {
|
65
|
+
'type' => 'table_cell',
|
66
|
+
'content' => [{
|
67
|
+
'type' => 'paragraph',
|
68
|
+
'content' => [{
|
69
|
+
'type' => 'text',
|
70
|
+
'text' => 'Second'
|
71
|
+
}]
|
72
|
+
}]
|
73
|
+
}, {
|
74
|
+
'type' => 'table_cell',
|
75
|
+
'content' => [{
|
76
|
+
'type' => 'paragraph',
|
77
|
+
'content' => [{
|
78
|
+
'type' => 'text',
|
79
|
+
'text' => 'Third'
|
80
|
+
}]
|
81
|
+
}]
|
82
|
+
}]
|
83
|
+
}
|
37
84
|
|
38
|
-
|
39
|
-
row = described_class.create
|
40
|
-
expect(row.cells).to eq([])
|
85
|
+
expect(row.to_h).to eq(expected)
|
41
86
|
end
|
42
|
-
end
|
43
87
|
|
44
|
-
|
45
|
-
it 'adds a cell with text content' do
|
88
|
+
it 'creates a row with complex cell content' do
|
46
89
|
row = described_class.create
|
47
|
-
cell = row.add_cell('Test content')
|
48
90
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
91
|
+
# First cell with multiple paragraphs
|
92
|
+
cell = row.add_cell
|
93
|
+
para = cell.add_paragraph('Main point:')
|
94
|
+
para.add_hard_break
|
95
|
+
para.add_text('Important', [Prosereflect::Mark::Bold.new])
|
96
|
+
cell.add_paragraph('(details below)')
|
53
97
|
|
54
|
-
|
55
|
-
row = described_class.create
|
98
|
+
# Second cell with mixed formatting
|
56
99
|
cell = row.add_cell
|
100
|
+
para = cell.add_paragraph
|
101
|
+
para.add_text('Status: ', [Prosereflect::Mark::Bold.new])
|
102
|
+
para.add_text('In Progress', [Prosereflect::Mark::Italic.new])
|
103
|
+
para.add_hard_break
|
104
|
+
para.add_text('Updated', [Prosereflect::Mark::Strike.new])
|
105
|
+
|
106
|
+
expected = {
|
107
|
+
'type' => 'table_row',
|
108
|
+
'content' => [{
|
109
|
+
'type' => 'table_cell',
|
110
|
+
'content' => [{
|
111
|
+
'type' => 'paragraph',
|
112
|
+
'content' => [{
|
113
|
+
'type' => 'text',
|
114
|
+
'text' => 'Main point:'
|
115
|
+
}, {
|
116
|
+
'type' => 'hard_break'
|
117
|
+
}, {
|
118
|
+
'type' => 'text',
|
119
|
+
'text' => 'Important',
|
120
|
+
'marks' => [{
|
121
|
+
'type' => 'bold'
|
122
|
+
}]
|
123
|
+
}]
|
124
|
+
}, {
|
125
|
+
'type' => 'paragraph',
|
126
|
+
'content' => [{
|
127
|
+
'type' => 'text',
|
128
|
+
'text' => '(details below)'
|
129
|
+
}]
|
130
|
+
}]
|
131
|
+
}, {
|
132
|
+
'type' => 'table_cell',
|
133
|
+
'content' => [{
|
134
|
+
'type' => 'paragraph',
|
135
|
+
'content' => [{
|
136
|
+
'type' => 'text',
|
137
|
+
'text' => 'Status: ',
|
138
|
+
'marks' => [{
|
139
|
+
'type' => 'bold'
|
140
|
+
}]
|
141
|
+
}, {
|
142
|
+
'type' => 'text',
|
143
|
+
'text' => 'In Progress',
|
144
|
+
'marks' => [{
|
145
|
+
'type' => 'italic'
|
146
|
+
}]
|
147
|
+
}, {
|
148
|
+
'type' => 'hard_break'
|
149
|
+
}, {
|
150
|
+
'type' => 'text',
|
151
|
+
'text' => 'Updated',
|
152
|
+
'marks' => [{
|
153
|
+
'type' => 'strike'
|
154
|
+
}]
|
155
|
+
}]
|
156
|
+
}]
|
157
|
+
}]
|
158
|
+
}
|
57
159
|
|
58
|
-
expect(row.
|
59
|
-
expect(cell).to be_a(Prosereflect::TableCell)
|
60
|
-
expect(cell.text_content).to eq('')
|
160
|
+
expect(row.to_h).to eq(expected)
|
61
161
|
end
|
62
162
|
end
|
63
163
|
|
64
|
-
describe '
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
164
|
+
describe 'row operations' do
|
165
|
+
let(:row) do
|
166
|
+
r = described_class.create
|
167
|
+
r.add_cell('First')
|
168
|
+
r.add_cell('Second')
|
169
|
+
r.add_cell('Third')
|
170
|
+
r
|
171
|
+
end
|
172
|
+
|
173
|
+
describe '#cells' do
|
174
|
+
it 'returns all cells in the row' do
|
175
|
+
expect(row.cells.size).to eq(3)
|
176
|
+
expect(row.cells).to all(be_a(Prosereflect::TableCell))
|
177
|
+
expect(row.cells.map(&:text_content)).to eq(%w[First Second Third])
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'returns empty array for row with no cells' do
|
181
|
+
empty_row = described_class.create
|
182
|
+
expect(empty_row.cells).to eq([])
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe '#add_cell' do
|
187
|
+
it 'adds a cell with text content and attributes' do
|
188
|
+
cell = row.add_cell('Test', attrs: {
|
189
|
+
'colspan' => 2,
|
190
|
+
'rowspan' => 1,
|
191
|
+
'background' => '#eee'
|
192
|
+
})
|
193
|
+
|
194
|
+
expected = {
|
195
|
+
'type' => 'table_cell',
|
196
|
+
'attrs' => {
|
197
|
+
'colspan' => 2,
|
198
|
+
'rowspan' => 1,
|
199
|
+
'background' => '#eee'
|
200
|
+
},
|
201
|
+
'content' => [{
|
202
|
+
'type' => 'paragraph',
|
203
|
+
'content' => [{
|
204
|
+
'type' => 'text',
|
205
|
+
'text' => 'Test'
|
206
|
+
}]
|
207
|
+
}]
|
208
|
+
}
|
209
|
+
|
210
|
+
expect(cell.to_h).to eq(expected)
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'adds a cell with formatted content' do
|
214
|
+
cell = row.add_cell
|
215
|
+
para = cell.add_paragraph
|
216
|
+
para.add_text('Bold', [Prosereflect::Mark::Bold.new])
|
217
|
+
para.add_text(' and ')
|
218
|
+
para.add_text('italic', [Prosereflect::Mark::Italic.new])
|
219
|
+
|
220
|
+
expected = {
|
221
|
+
'type' => 'table_cell',
|
222
|
+
'content' => [{
|
223
|
+
'type' => 'paragraph',
|
224
|
+
'content' => [{
|
225
|
+
'type' => 'text',
|
226
|
+
'text' => 'Bold',
|
227
|
+
'marks' => [{
|
228
|
+
'type' => 'bold'
|
229
|
+
}]
|
230
|
+
}, {
|
231
|
+
'type' => 'text',
|
232
|
+
'text' => ' and '
|
233
|
+
}, {
|
234
|
+
'type' => 'text',
|
235
|
+
'text' => 'italic',
|
236
|
+
'marks' => [{
|
237
|
+
'type' => 'italic'
|
238
|
+
}]
|
239
|
+
}]
|
240
|
+
}]
|
241
|
+
}
|
242
|
+
|
243
|
+
expect(cell.to_h).to eq(expected)
|
244
|
+
end
|
75
245
|
end
|
76
246
|
end
|
77
247
|
end
|