portable_text 0.1.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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +28 -0
  3. data/.rubocop_todo.yml +85 -0
  4. data/LICENSE +21 -0
  5. data/README.md +357 -0
  6. data/Rakefile +15 -0
  7. data/lib/portable_text/block_types/base.rb +19 -0
  8. data/lib/portable_text/block_types/block.rb +6 -0
  9. data/lib/portable_text/block_types/image.rb +6 -0
  10. data/lib/portable_text/block_types/list.rb +64 -0
  11. data/lib/portable_text/block_types/null.rb +6 -0
  12. data/lib/portable_text/block_types/span.rb +12 -0
  13. data/lib/portable_text/config.rb +27 -0
  14. data/lib/portable_text/errors/unimplemented_error.rb +9 -0
  15. data/lib/portable_text/errors/unknown_serializer_error.rb +9 -0
  16. data/lib/portable_text/html/base_component.rb +19 -0
  17. data/lib/portable_text/html/block_types/block.rb +32 -0
  18. data/lib/portable_text/html/block_types/image.rb +17 -0
  19. data/lib/portable_text/html/block_types/list.rb +29 -0
  20. data/lib/portable_text/html/block_types/null.rb +13 -0
  21. data/lib/portable_text/html/block_types/span.rb +84 -0
  22. data/lib/portable_text/html/config.rb +48 -0
  23. data/lib/portable_text/html/configured.rb +11 -0
  24. data/lib/portable_text/html/mark_defs/base.rb +14 -0
  25. data/lib/portable_text/html/mark_defs/link.rb +13 -0
  26. data/lib/portable_text/html/mark_defs/null.rb +13 -0
  27. data/lib/portable_text/html/rendering.rb +7 -0
  28. data/lib/portable_text/html/serializer.rb +17 -0
  29. data/lib/portable_text/mark_defs/base.rb +10 -0
  30. data/lib/portable_text/mark_defs/link.rb +7 -0
  31. data/lib/portable_text/mark_defs/null.rb +6 -0
  32. data/lib/portable_text/plain/serializer.rb +34 -0
  33. data/lib/portable_text/serializer.rb +97 -0
  34. data/lib/portable_text/version.rb +5 -0
  35. data/lib/portable_text.rb +20 -0
  36. data/sig/portable_text.rbs +4 -0
  37. metadata +196 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 86981539153c16fb832e1221ed7d068fbb7fe986f807963c78cc0091f1921970
4
+ data.tar.gz: 65547bf22449bc8318e89f5cc462bed3a8bd48f490913aebeaece3a14fcac329
5
+ SHA512:
6
+ metadata.gz: d04924353a52afe867c49c270cb9c5ed86b1313ac106a4b25200f03e7c87452d30212fa9d2e6da531a2dc7834f6ada62df69d2a40e91ad62824ff9e8ddd9e91f
7
+ data.tar.gz: 7d41d5138c9d7b830e7d2d9af3d7ad391a0de562b00c1df62d8d04031c1742df5e650f1d8ba2d21f16e50705506c029adec5f83502d37db51d2316cc83833e20
data/.rubocop.yml ADDED
@@ -0,0 +1,28 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 3.0
5
+
6
+ Style/StringLiterals:
7
+ EnforcedStyle: double_quotes
8
+
9
+ Style/StringLiteralsInInterpolation:
10
+ EnforcedStyle: double_quotes
11
+
12
+ Style/FrozenStringLiteralComment:
13
+ Enabled: false
14
+
15
+ Metrics/MethodLength:
16
+ Enabled: false
17
+
18
+ Style/Documentation:
19
+ Enabled: false
20
+
21
+ Style/ClassAndModuleChildren:
22
+ Enabled: false
23
+
24
+ Metrics/AbcSize:
25
+ Enabled: false
26
+
27
+ Style/WordArray:
28
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,85 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2024-04-11 12:20:23 UTC using RuboCop version 1.63.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # This cop supports safe autocorrection (--autocorrect).
11
+ # Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals.
12
+ # SupportedStylesForExponentOperator: space, no_space
13
+ # SupportedStylesForRationalLiterals: space, no_space
14
+ Layout/SpaceAroundOperators:
15
+ Exclude:
16
+ - 'portable_text.gemspec'
17
+
18
+ # Offense count: 1
19
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
20
+ Metrics/AbcSize:
21
+ Max: 21
22
+
23
+ # Offense count: 1
24
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
25
+ Metrics/MethodLength:
26
+ Max: 13
27
+
28
+ # Offense count: 14
29
+ # Configuration parameters: AllowedConstants.
30
+ Style/Documentation:
31
+ Exclude:
32
+ - 'spec/**/*'
33
+ - 'test/**/*'
34
+ - 'lib/portable_text.rb'
35
+ - 'lib/portable_text/block_types/base.rb'
36
+ - 'lib/portable_text/block_types/list.rb'
37
+ - 'lib/portable_text/block_types/span.rb'
38
+ - 'lib/portable_text/config.rb'
39
+ - 'lib/portable_text/errors/unimpleted_error.rb'
40
+ - 'lib/portable_text/html/configured.rb'
41
+ - 'lib/portable_text/html/content/image.rb'
42
+ - 'lib/portable_text/html/content/list.rb'
43
+ - 'lib/portable_text/html/mark_def/base.rb'
44
+ - 'lib/portable_text/html/serializer.rb'
45
+ - 'lib/portable_text/mark_defs/base.rb'
46
+ - 'lib/portable_text/mark_defs/link.rb'
47
+ - 'lib/portable_text/renderer.rb'
48
+
49
+ # Offense count: 15
50
+ # This cop supports unsafe autocorrection (--autocorrect-all).
51
+ # Configuration parameters: EnforcedStyle.
52
+ # SupportedStyles: always, always_true, never
53
+ Style/FrozenStringLiteralComment:
54
+ Exclude:
55
+ - 'lib/portable_text/block_types/base.rb'
56
+ - 'lib/portable_text/block_types/block.rb'
57
+ - 'lib/portable_text/block_types/image.rb'
58
+ - 'lib/portable_text/block_types/list.rb'
59
+ - 'lib/portable_text/block_types/span.rb'
60
+ - 'lib/portable_text/config.rb'
61
+ - 'lib/portable_text/errors/unimpleted_error.rb'
62
+ - 'lib/portable_text/html/configured.rb'
63
+ - 'lib/portable_text/html/content/image.rb'
64
+ - 'lib/portable_text/html/content/list.rb'
65
+ - 'lib/portable_text/html/mark_def/base.rb'
66
+ - 'lib/portable_text/html/serializer.rb'
67
+ - 'lib/portable_text/mark_defs/base.rb'
68
+ - 'lib/portable_text/mark_defs/link.rb'
69
+ - 'lib/portable_text/renderer.rb'
70
+
71
+ # Offense count: 2
72
+ # This cop supports safe autocorrection (--autocorrect).
73
+ # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
74
+ # SupportedStyles: single_quotes, double_quotes
75
+ Style/StringLiterals:
76
+ Exclude:
77
+ - 'lib/portable_text/block_types/list.rb'
78
+ - 'lib/portable_text/html/content/image.rb'
79
+
80
+ # Offense count: 1
81
+ # This cop supports safe autocorrection (--autocorrect).
82
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
83
+ # URISchemes: http, https
84
+ Layout/LineLength:
85
+ Max: 126
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Maxime Souillat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,357 @@
1
+ # Ruby Portable Text
2
+
3
+ A ruby library to render [Portable text](https://www.sanity.io/docs/presenting-block-text)
4
+
5
+
6
+ This gem is meant to be easy to use but is also highly configurable and extensible to match many use cases. By default, it can serialize Portable Text to HTML.
7
+
8
+ You can:
9
+
10
+ - easily render default PortableText blocks in html without any configuration
11
+ - create custom block types, mark_defs. Add them or replace existing ones.
12
+ - create custom HTML serializers for each block type or mark def. Add them or replace existing ones.
13
+ - customize each HTML node with custom attributes
14
+ - create a new serializer
15
+
16
+ This is a very early release so please open issues if something doesn't work as intended.
17
+
18
+
19
+ ## Installation
20
+
21
+ ```other
22
+ gem install portable_text
23
+ ```
24
+
25
+
26
+
27
+ ## Usage
28
+
29
+ See [Rails usage](#rails-usage) for usage in rails
30
+
31
+ `PortableText::Serializer` takes 2 parameters:
32
+
33
+ - `content:` , the portable text Array
34
+ - `to:` , the rendering format. It defaults to: `:html`
35
+
36
+ > You can also use the `:plain` rendering format to show the text without any formatting. The plain serializer is very basic and does not support any configuration, but it can be used as a starting point to create a new serializer.
37
+
38
+ PortableText accepts 2 methods, `render` and `convert!`.
39
+ - `render` renders the content to the specified format defined in the `to` parameter. See [How to render html ?](#how-to-render-html) for more information.
40
+ - `convert!` converts the content to be used by the library.
41
+ - It is useful for debugging purposes.
42
+ - It transforms the keys to ruby format.
43
+ - It creates the block types and mark definitions as objects, along with their children and marks, and creates a new data structure for list items.
44
+
45
+ ### How to render html?
46
+
47
+ Under the hood, the html renderer uses [Phlex](https://www.phlex.fun), a templating language which allows to create html in plain ruby.
48
+
49
+ ```ruby
50
+ content = [
51
+ {
52
+ "_key": "12345ffxx",
53
+ "_type": "block",
54
+ "children": [{
55
+ "_key": "78910xxyy",
56
+ "_type": "span",
57
+ "marks": [],
58
+ "text": "Hello world!"
59
+ }],
60
+ "markDefs": [],
61
+ "style": "h1"
62
+ }
63
+ ]
64
+
65
+ portable_text = PortableText::Serializer.new(content: content, to: :html)
66
+
67
+ # Since the HTML renderer uses Phlex, you can either include the rendering module
68
+ # and use the render method...
69
+ include PortableText::Html::Rendering
70
+ render portable_text.render
71
+ # => <h1>Hello world!</h1>
72
+
73
+ # ... Or you can directly call the Phlex template
74
+ portable_text.render.call
75
+ # => <h1>Hello world!</h1>
76
+ ```
77
+
78
+
79
+ ### Rails usage
80
+
81
+ To use the `PortableText` HTML serializer in rails, you need to add `phlex-rails` to the Gemfile.
82
+
83
+ You don’t need to do the whole phlex installation (as described in the Phlex documentation) if you don’t intend to use Phlex to replace your usual templating language.
84
+
85
+ ```ruby
86
+ gem 'portable_text'
87
+ gem 'phlex-rails'
88
+ ```
89
+
90
+ Then run `bundle install`
91
+
92
+ Then, in a controller or a view, just use `render` as usual.
93
+
94
+ ```ruby
95
+ portable_text = PortableText::Serializer.new(content: content, to: :html)
96
+ render portable_text.render
97
+ ```
98
+
99
+
100
+
101
+ ## Configuration
102
+
103
+ This library is highly customizable through configuration. This is very straightforward as configuration is just a bunch of hashes that either define classes or key-value pairs.
104
+
105
+ Since this library is meant to be used for multiple use cases, and possibly several serializers at once, the type definitions are independent from the rendering.
106
+
107
+ So, in order to use a block type or a mark definition, one has to:
108
+
109
+ - register it in the PortableText configuration, so it can be passed as an object to the serializer
110
+ - create the template in the serializer (see HTML configuration)
111
+
112
+
113
+
114
+ ### Registering block types
115
+
116
+ ```ruby
117
+ content = [
118
+ {
119
+ "_key": "12345ffxx",
120
+ "_type": "myType",
121
+ ...,
122
+ "url": "https://www.github.com",
123
+ "image_url": "https://www.myimage.com/my_image.jpg",
124
+ "children": [{
125
+ "_key": "78910xxyy",
126
+ "_type": "span",
127
+ "marks": [],
128
+ "text": "Github"
129
+ }]
130
+ }
131
+ ]
132
+
133
+ # Under the hood, this library uses dry-initializer.
134
+ # You can use the option method to configure it easily
135
+ class MyBlock < PortableText::BlockTypes::Base
136
+ option :url, default: proc { "" }
137
+ option :image_url, default: proc { "" }
138
+ # children is an inherited option so it does not need to be added here
139
+ end
140
+
141
+ # Or use plain old ruby. It needs to have attr_readers!
142
+ class MyBlock < PortableText::BlockTypes::Base
143
+ attr_reader :url, :image_url
144
+
145
+ def initialize(url: "", image_url:, **)
146
+ super
147
+ @url = url
148
+ @image_url = image_url
149
+ end
150
+ end
151
+
152
+ # PortableText transforms keys to ruby format so use conventional ruby!
153
+ # myType becomes my_type.
154
+ PortableText.config.block.types.merge! { my_block: MyBlock }
155
+ ```
156
+
157
+
158
+ #### Default block types
159
+
160
+ It’s probably a good idea to leave the `list` block type untouched. Change at your own risk.
161
+
162
+ ```ruby
163
+ {
164
+ block: BlockTypes::Block,
165
+ image: BlockTypes::Image,
166
+ list: BlockTypes::List,
167
+ span: BlockTypes::Span
168
+ }
169
+ ```
170
+
171
+
172
+ ### Registering mark definitions
173
+
174
+ It’s very similar to registering blocks. In case of doubt, refer to the block documentation.
175
+
176
+ ```ruby
177
+ content = [
178
+ {
179
+ "_key": "12345ffxx",
180
+ "_type": "block",
181
+ ...,
182
+ "markDefs": [{ "_key" => "456", "_type" => "newMarkDef" }],
183
+ }
184
+ ]
185
+
186
+ class NewMarkDef < PortableText::MarkDefs::Base
187
+ option :label, default: proc { "" }
188
+ end
189
+
190
+ PortableText.config.block.mark_defs.merge! { new_mark_def: NewMarkDef }
191
+ ```
192
+
193
+
194
+
195
+ ## Html Serializer configuration
196
+
197
+ After registering your block type or mark definition, you need to create its template.
198
+
199
+ Each template takes one argument, a block.
200
+
201
+
202
+ ### Block Type Template
203
+
204
+ ```ruby
205
+ # Let's use the block defined earlier in Registering block types
206
+
207
+ class Html::MyBlock < PortableText::Html::BaseComponent
208
+ # You can include PortableText::Html::Configured
209
+ # to get access to the html serializer configuration helpers
210
+ # The #config method allows you to access config values
211
+ # The #block_type(:key) method is a shortcut to the relevant block_type
212
+ include PortableText::Html::Configured
213
+
214
+ # This library uses dry-initializer
215
+ # so you can use `param` to create a simple parameter
216
+
217
+ # There is no attribute_reader so `param :my_block` generates `@my_block`
218
+ # This is recommended because some common HTML method names could conflict with
219
+ # Phlex methods, like `title`.
220
+ param :my_block
221
+
222
+ def view_template
223
+ div do
224
+ img(src: @my_block.image_url)
225
+ link
226
+ end
227
+ end
228
+
229
+ private
230
+
231
+ def link
232
+ a(href: @my_block.url) do
233
+ @my_block.children.each do |child|
234
+ render block_type(:span).new(child, mark_defs: nil)
235
+ end
236
+ end
237
+ end
238
+ end
239
+
240
+ # It needs to have the same key as the one registered before.
241
+ PortableText::Html.config.block.types.merge! { my_block: Html::MyBlock }
242
+ ```
243
+
244
+
245
+ ### Mark Definition template
246
+
247
+ Each mark definition takes one argument, a mark definition registered in the configuration.
248
+
249
+ ```ruby
250
+ # Let's use the mark definition defined earlier in Registering mark definition
251
+
252
+ class Html::NewMarkDef < PortableText::Html::BaseComponent
253
+ param :mark_def
254
+
255
+ # &block is mandatory because mark definitions always contain other nodes
256
+ def view_template(&block)
257
+ a(href: @mark_def.url) { block.call }
258
+ end
259
+ end
260
+
261
+ # It needs to have the same key as the one registered before.
262
+ PortableText::Html.config.block.mark_defs.merge! { new_mark_def: Html::NewMarkDef }
263
+ ```
264
+
265
+
266
+ ### Customizing html nodes
267
+
268
+ Every HTML node is customizable through config and looks this way:
269
+
270
+ `h1: { node: :h1 }`
271
+
272
+ You can add HTML attributes by appending them. For example:
273
+
274
+ ```ruby
275
+ h1: { node: :h1, class: "header" }
276
+ ```
277
+
278
+
279
+ ### Configuring marks
280
+
281
+ You can configure marks by updating the marks setting.
282
+
283
+ ```ruby
284
+ PortableText::Html.config.span.marks.merge! { strong: { node: :b, }}
285
+
286
+ # Defaults
287
+ {
288
+ strong: { node: :strong },
289
+ em: { node: :em }
290
+ }
291
+ ```
292
+
293
+
294
+ ### Configuring styles
295
+
296
+ ```ruby
297
+ PortableText::Html.config.block.styles.merge! { h1: { node: :h3, class: "header" }}
298
+
299
+
300
+ # Defaults
301
+ {
302
+ h1: { node: :h1 },
303
+ h2: { node: :h2 },
304
+ h3: { node: :h3 },
305
+ h4: { node: :h4 },
306
+ h5: { node: :h5 },
307
+ h6: { node: :h6 },
308
+ blockquote: { node: :blockquote },
309
+ normal: { node: :p },
310
+ li: { node: :li }
311
+ }
312
+ ```
313
+
314
+
315
+ ### Configuring list types
316
+
317
+ ```ruby
318
+ PortableText::Html.config.block.list_types.merge! { bullet: { node: :div }}
319
+
320
+ # Defaults
321
+ {
322
+ bullet: { node: :ul },
323
+ numeric: { node: :ol }
324
+ }
325
+ ```
326
+
327
+
328
+ ### Adding a new serializer
329
+
330
+ You can add a new serializer by creating a new class. You then need to add it the the config.
331
+
332
+ The serializer needs to have a `content` method and takes a list of `blocks` as only parameter.
333
+
334
+ ```ruby
335
+ class MySerializer
336
+ def initialize(blocks)
337
+ @blocks = blocks
338
+ end
339
+
340
+ def content(**options)
341
+ blocks.map |block|
342
+ block.type + " - " + block.key + " - " + options[:context]
343
+ end.join(" ")
344
+ end
345
+ end
346
+
347
+ PortableText.config.serializers.merge! { my_serializer: MySerializer }
348
+
349
+ content = [{ "_key": "12345ffxx", "_type": "block", ... }]
350
+ serializer = PortableText::Serializer.new(content: content, to: :my_serializer)
351
+
352
+ # render forwards any keyword argument to the content method in the serializer
353
+ serializer.render(context: "readme")
354
+ # => block - 12345ffxx - readme
355
+ ```
356
+
357
+
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+ require "rake/testtask"
6
+
7
+ RuboCop::RakeTask.new
8
+
9
+ Rake::TestTask.new do |t|
10
+ t.libs << "test"
11
+ t.test_files = FileList["test/**/*_test.rb"]
12
+ t.verbose = true
13
+ end
14
+
15
+ task default: %i[test rubocop]
@@ -0,0 +1,19 @@
1
+ module PortableText
2
+ module BlockTypes
3
+ class Base
4
+ extend Dry::Initializer
5
+
6
+ option :_key, as: :key
7
+ option :_type, as: :type
8
+ option :markDefs, as: :mark_defs, default: proc { [] }
9
+ option :children, default: proc { [] }
10
+ option :style, optional: true
11
+ option :listItem, as: :list_item, optional: true
12
+ option :level, optional: true
13
+ option :asset, optional: true
14
+
15
+ def list? = false
16
+ def list_item? = list_item.present?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ module PortableText
2
+ module BlockTypes
3
+ class Block < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PortableText
2
+ module BlockTypes
3
+ class Image < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,64 @@
1
+ # A list can contain blocks and child lists.
2
+ # items: [Block, List, Block, List, Block]
3
+
4
+ module PortableText
5
+ module BlockTypes
6
+ class List
7
+ extend Dry::Initializer
8
+
9
+ option :list_type, default: proc { 'bullet' }
10
+ option :items, default: proc { [] }
11
+ option :level, default: proc { 1 }
12
+ option :parent, default: proc { nil }
13
+
14
+ def list? = true
15
+ def type = "list"
16
+
17
+ # Adds a block to the list.
18
+ # If the block is on same level as the list, it will be added to the list.
19
+ # If the block is on a higher level, it will be added to a child list
20
+ # Else it will be added to the nearest ancestor list.
21
+ def add(block)
22
+ if block.level == level
23
+ items << block
24
+ elsif block.level > level
25
+ add_child(block)
26
+ else
27
+ ancestor = find_matching_ancestor(block)
28
+ ancestor.items << block
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def find_matching_ancestor(block)
35
+ return self if block.level == level
36
+
37
+ parent.find_matching_ancestor(block) if block.level != level
38
+ end
39
+
40
+ def add_child(block)
41
+ sub_list = find_sub_list(block, level)
42
+
43
+ if sub_list.present?
44
+ sub_list.add(block)
45
+ else
46
+ items << List.new(items: [block], level: block.level, parent: self)
47
+ end
48
+ end
49
+
50
+ def find_sub_list(block, current_level)
51
+ target = block.level - 1
52
+
53
+ sub_list = items.reverse.find do |item|
54
+ item.list? && item.level == current_level + 1
55
+ end
56
+
57
+ return unless sub_list
58
+ return sub_list if sub_list.level == target
59
+
60
+ sub_list.find_sub_list(block, current_level + 1)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,6 @@
1
+ module PortableText
2
+ module BlockTypes
3
+ class Null < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module PortableText
2
+ module BlockTypes
3
+ class Span
4
+ extend Dry::Initializer
5
+
6
+ option :marks, default: proc { [] }
7
+ option :_key, as: :key
8
+ option :_type, as: :type
9
+ option :text, default: proc { nil }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ module PortableText
2
+ class Config
3
+ extend Dry::Configurable
4
+
5
+ # Default settings
6
+ # These can be overridden
7
+ # Example: PortableText.config.block.types.merge!({ block: MyCustomBlock })
8
+
9
+ setting :block do
10
+ setting :types, default: {
11
+ block: BlockTypes::Block,
12
+ image: BlockTypes::Image,
13
+ list: BlockTypes::List,
14
+ span: BlockTypes::Span
15
+ }
16
+
17
+ setting :mark_defs, default: {
18
+ link: MarkDefs::Link
19
+ }
20
+ end
21
+
22
+ setting :serializers, default: {
23
+ html: Html::Serializer,
24
+ plain: Plain::Serializer
25
+ }
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ module PortableText
2
+ module Errors
3
+ class UnimplementedError < StandardError
4
+ def initialize(msg = "Please implement this method")
5
+ super
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module PortableText
2
+ module Errors
3
+ class UnknownSerializerError < StandardError
4
+ def initialize(msg = "This serializer is not recognized by PortableText::Config.serializers")
5
+ super
6
+ end
7
+ end
8
+ end
9
+ end