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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +23 -4
  3. data/README.adoc +193 -12
  4. data/lib/prosereflect/attribute/base.rb +34 -0
  5. data/lib/prosereflect/attribute/bold.rb +20 -0
  6. data/lib/prosereflect/attribute/href.rb +24 -0
  7. data/lib/prosereflect/attribute/id.rb +24 -0
  8. data/lib/prosereflect/attribute.rb +13 -0
  9. data/lib/prosereflect/blockquote.rb +85 -0
  10. data/lib/prosereflect/bullet_list.rb +83 -0
  11. data/lib/prosereflect/code_block.rb +135 -0
  12. data/lib/prosereflect/code_block_wrapper.rb +66 -0
  13. data/lib/prosereflect/document.rb +99 -24
  14. data/lib/prosereflect/hard_break.rb +11 -9
  15. data/lib/prosereflect/heading.rb +64 -0
  16. data/lib/prosereflect/horizontal_rule.rb +70 -0
  17. data/lib/prosereflect/image.rb +126 -0
  18. data/lib/prosereflect/input/html.rb +505 -0
  19. data/lib/prosereflect/list_item.rb +65 -0
  20. data/lib/prosereflect/mark/base.rb +49 -0
  21. data/lib/prosereflect/mark/bold.rb +15 -0
  22. data/lib/prosereflect/mark/code.rb +14 -0
  23. data/lib/prosereflect/mark/italic.rb +15 -0
  24. data/lib/prosereflect/mark/link.rb +18 -0
  25. data/lib/prosereflect/mark/strike.rb +15 -0
  26. data/lib/prosereflect/mark/subscript.rb +15 -0
  27. data/lib/prosereflect/mark/superscript.rb +15 -0
  28. data/lib/prosereflect/mark/underline.rb +15 -0
  29. data/lib/prosereflect/mark.rb +11 -0
  30. data/lib/prosereflect/node.rb +181 -32
  31. data/lib/prosereflect/ordered_list.rb +85 -0
  32. data/lib/prosereflect/output/html.rb +374 -0
  33. data/lib/prosereflect/paragraph.rb +26 -15
  34. data/lib/prosereflect/parser.rb +111 -24
  35. data/lib/prosereflect/table.rb +40 -9
  36. data/lib/prosereflect/table_cell.rb +33 -8
  37. data/lib/prosereflect/table_header.rb +92 -0
  38. data/lib/prosereflect/table_row.rb +31 -8
  39. data/lib/prosereflect/text.rb +13 -17
  40. data/lib/prosereflect/user.rb +63 -0
  41. data/lib/prosereflect/version.rb +1 -1
  42. data/lib/prosereflect.rb +6 -0
  43. data/prosereflect.gemspec +1 -0
  44. data/spec/prosereflect/document_spec.rb +436 -36
  45. data/spec/prosereflect/hard_break_spec.rb +218 -22
  46. data/spec/prosereflect/input/html_spec.rb +797 -0
  47. data/spec/prosereflect/node_spec.rb +258 -89
  48. data/spec/prosereflect/output/html_spec.rb +369 -0
  49. data/spec/prosereflect/paragraph_spec.rb +424 -49
  50. data/spec/prosereflect/parser_spec.rb +304 -91
  51. data/spec/prosereflect/table_cell_spec.rb +268 -57
  52. data/spec/prosereflect/table_row_spec.rb +210 -40
  53. data/spec/prosereflect/table_spec.rb +392 -61
  54. data/spec/prosereflect/text_spec.rb +206 -48
  55. data/spec/prosereflect/user_spec.rb +73 -0
  56. data/spec/prosereflect_spec.rb +5 -0
  57. data/spec/support/shared_examples.rb +44 -15
  58. metadata +47 -3
  59. data/debug_loading.rb +0 -34
@@ -11,41 +11,237 @@ RSpec.describe Prosereflect::HardBreak do
11
11
  end
12
12
 
13
13
  describe '.create' do
14
- it 'creates a hard break' do
14
+ it 'creates a simple hard break' do
15
15
  break_node = described_class.create
16
- expect(break_node).to be_a(described_class)
17
- expect(break_node.type).to eq('hard_break')
16
+
17
+ expected = {
18
+ 'type' => 'hard_break'
19
+ }
20
+
21
+ expect(break_node.to_h).to eq(expected)
22
+ end
23
+
24
+ it 'creates a hard break with a single mark' do
25
+ break_node = described_class.create
26
+ break_node.marks = [{ 'type' => 'bold' }]
27
+
28
+ expected = {
29
+ 'type' => 'hard_break',
30
+ 'marks' => [{
31
+ 'type' => 'bold'
32
+ }]
33
+ }
34
+
35
+ expect(break_node.to_h).to eq(expected)
36
+ end
37
+
38
+ it 'creates a hard break with multiple marks' do
39
+ break_node = described_class.create
40
+ break_node.marks = [
41
+ { 'type' => 'bold' },
42
+ { 'type' => 'italic' },
43
+ { 'type' => 'strike' }
44
+ ]
45
+
46
+ expected = {
47
+ 'type' => 'hard_break',
48
+ 'marks' => [{
49
+ 'type' => 'bold'
50
+ }, {
51
+ 'type' => 'italic'
52
+ }, {
53
+ 'type' => 'strike'
54
+ }]
55
+ }
56
+
57
+ expect(break_node.to_h).to eq(expected)
58
+ end
59
+ end
60
+
61
+ describe 'in document context' do
62
+ it 'works in a paragraph with mixed content' do
63
+ paragraph = Prosereflect::Paragraph.new
64
+ paragraph.add_text('First line')
65
+ paragraph.add_hard_break
66
+ paragraph.add_text('Second line with ')
67
+ paragraph.add_text('bold', [Prosereflect::Mark::Bold.new])
68
+ paragraph.add_hard_break
69
+ paragraph.add_text('Third line')
70
+
71
+ expected = {
72
+ 'type' => 'paragraph',
73
+ 'content' => [{
74
+ 'type' => 'text',
75
+ 'text' => 'First line'
76
+ }, {
77
+ 'type' => 'hard_break'
78
+ }, {
79
+ 'type' => 'text',
80
+ 'text' => 'Second line with '
81
+ }, {
82
+ 'type' => 'text',
83
+ 'text' => 'bold',
84
+ 'marks' => [{
85
+ 'type' => 'bold'
86
+ }]
87
+ }, {
88
+ 'type' => 'hard_break'
89
+ }, {
90
+ 'type' => 'text',
91
+ 'text' => 'Third line'
92
+ }]
93
+ }
94
+
95
+ expect(paragraph.to_h).to eq(expected)
96
+ end
97
+
98
+ it 'works in a list item with multiple breaks' do
99
+ list = Prosereflect::BulletList.new
100
+ item = list.add_item('First part')
101
+ item.add_hard_break([{ 'type' => 'strike' }])
102
+ item.add_text('Second part')
103
+ item.add_hard_break
104
+ item.add_text('Third part')
105
+
106
+ expected = {
107
+ 'type' => 'bullet_list',
108
+ 'attrs' => {
109
+ 'bullet_style' => nil
110
+ },
111
+ 'content' => [{
112
+ 'type' => 'list_item',
113
+ 'content' => [{
114
+ 'type' => 'paragraph',
115
+ 'content' => [{
116
+ 'type' => 'text',
117
+ 'text' => 'First part'
118
+ }, {
119
+ 'type' => 'hard_break',
120
+ 'marks' => [{
121
+ 'type' => 'strike'
122
+ }]
123
+ }, {
124
+ 'type' => 'text',
125
+ 'text' => 'Second part'
126
+ }, {
127
+ 'type' => 'hard_break'
128
+ }, {
129
+ 'type' => 'text',
130
+ 'text' => 'Third part'
131
+ }]
132
+ }]
133
+ }]
134
+ }
135
+
136
+ expect(list.to_h).to eq(expected)
18
137
  end
19
138
 
20
- it 'creates a hard break with marks' do
21
- marks = [{ 'type' => 'bold' }]
22
- break_node = described_class.create(marks)
23
- expect(break_node.marks).to eq(marks)
139
+ it 'works in a table cell with multiple paragraphs' do
140
+ cell = Prosereflect::TableCell.new
141
+ para1 = cell.add_paragraph('First paragraph')
142
+ para1.add_hard_break
143
+ para1.add_text('continues here')
144
+
145
+ para2 = cell.add_paragraph('Second paragraph')
146
+ para2.add_hard_break([Prosereflect::Mark::Italic.new])
147
+ para2.add_text('with style')
148
+
149
+ expected = {
150
+ 'type' => 'table_cell',
151
+ 'content' => [{
152
+ 'type' => 'paragraph',
153
+ 'content' => [{
154
+ 'type' => 'text',
155
+ 'text' => 'First paragraph'
156
+ }, {
157
+ 'type' => 'hard_break'
158
+ }, {
159
+ 'type' => 'text',
160
+ 'text' => 'continues here'
161
+ }]
162
+ }, {
163
+ 'type' => 'paragraph',
164
+ 'content' => [{
165
+ 'type' => 'text',
166
+ 'text' => 'Second paragraph'
167
+ }, {
168
+ 'type' => 'hard_break',
169
+ 'marks' => [{
170
+ 'type' => 'italic'
171
+ }]
172
+ }, {
173
+ 'type' => 'text',
174
+ 'text' => 'with style'
175
+ }]
176
+ }]
177
+ }
178
+
179
+ expect(cell.to_h).to eq(expected)
24
180
  end
25
181
  end
26
182
 
27
183
  describe '#text_content' do
28
184
  it 'returns a newline character' do
29
- break_node = described_class.create
185
+ break_node = described_class.new
30
186
  expect(break_node.text_content).to eq("\n")
31
187
  end
188
+
189
+ it 'returns a newline character regardless of marks' do
190
+ break_node = described_class.create(marks: [
191
+ Prosereflect::Mark::Bold.new,
192
+ Prosereflect::Mark::Italic.new
193
+ ])
194
+ expect(break_node.text_content).to eq("\n")
195
+ end
196
+
197
+ it 'properly formats text in a paragraph with multiple breaks' do
198
+ paragraph = Prosereflect::Paragraph.new
199
+ paragraph.add_text('Line 1')
200
+ paragraph.add_hard_break
201
+ paragraph.add_text('Line 2')
202
+ paragraph.add_hard_break
203
+ paragraph.add_text('Line 3')
204
+
205
+ expect(paragraph.text_content).to eq("Line 1\nLine 2\nLine 3")
206
+ end
32
207
  end
33
208
 
34
- describe '#to_h' do
35
- it 'generates hash representation' do
209
+ describe 'serialization' do
210
+ it 'preserves mark order in serialization' do
211
+ break_node = described_class.create
212
+ break_node.marks = [
213
+ { 'type' => 'bold' },
214
+ { 'type' => 'italic' },
215
+ { 'type' => 'strike' },
216
+ { 'type' => 'underline' }
217
+ ]
218
+
219
+ expected = {
220
+ 'type' => 'hard_break',
221
+ 'marks' => [{
222
+ 'type' => 'bold'
223
+ }, {
224
+ 'type' => 'italic'
225
+ }, {
226
+ 'type' => 'strike'
227
+ }, {
228
+ 'type' => 'underline'
229
+ }]
230
+ }
231
+
232
+ expect(break_node.to_h).to eq(expected)
233
+ end
234
+
235
+ it 'handles empty marks array' do
236
+ break_node = described_class.create
237
+ break_node.marks = []
238
+ expect(break_node.to_h).to eq({ 'type' => 'hard_break' })
239
+ end
240
+
241
+ it 'excludes marks when nil' do
36
242
  break_node = described_class.create
37
- hash = break_node.to_h
38
- expect(hash).to eq({ 'type' => 'hard_break' })
39
- end
40
-
41
- it 'includes marks in hash representation' do
42
- marks = [{ 'type' => 'italic' }]
43
- break_node = described_class.create(marks)
44
- hash = break_node.to_h
45
- expect(hash).to eq({
46
- 'type' => 'hard_break',
47
- 'marks' => marks
48
- })
243
+ break_node.marks = nil
244
+ expect(break_node.to_h).to eq({ 'type' => 'hard_break' })
49
245
  end
50
246
  end
51
247
  end