editorjs_renderer 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb8e368f0d8a52e6ced1d5bad069494aab8be619209b76e7adb845bfe0025b8a
4
- data.tar.gz: 5265f195ae17da0ac8c596d713b0eda5d11df7072f70aee64d975c866eb946c3
3
+ metadata.gz: 5b121c4cae0462b209cc6a06a97d20b604f64532ecde7d0ac17f49590b9071f5
4
+ data.tar.gz: de06caddb9899d96f371cdae6356d9c62b40aa54082634316e0d6c699e95529d
5
5
  SHA512:
6
- metadata.gz: 627849905b767eb411b6a65744d68f5f57cd620748ebc609d269698e4721ba3d86764178ba22733d0a09aec647ed04cc015749c0ff5b276bb957b9040fac0a55
7
- data.tar.gz: b2c39951c1fc4152f410219657507d363e395cd0889329e9b1a11820a3a4449eee1fe2ed9de7b91553c98f3e0ff83d3246803548e8818b0067b8be6a3ab643a2
6
+ metadata.gz: '00615381d173edec22850e3baee788a845c429fd2e368cb38912ed8da6dca136fa5d21adeff211cf1309fa0f9505675b0e9d218c2d7c68b899af2dbb57cc8c72'
7
+ data.tar.gz: fd934f5aa5f525ad06aaba16d2dd7671e19c34f1b32e41f95ddd15a49fdca4be7d5723581081bc1546a10f704ea4789281dedf1a00f06ae17df274ae4104d0f3
data/CHANGELOG.md CHANGED
@@ -10,8 +10,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10
10
  ## [Unreleased]
11
11
 
12
12
  ---
13
+ ## [0.3.0] - 2025-04-24
13
14
 
14
- ## [0.2.0] - 2025-04-23
15
+ ### Added
16
+ - Zeitwerk autoloader support: removed all `require_relative` statements.
17
+ - New block: `Image` – renders `<img>` tag with optional `<figure>` and `<figcaption>`.
18
+ - New block: `List` – renders unordered and ordered lists (`<ul>` and `<ol>`).
19
+ - New block: `Attaches` – renders a download link with file size information.
20
+ - New block: `Checklist` – renders a checklist with checkboxes (readonly).
21
+ - New block: `Code` – renders multiline code block as `<pre><code>`.
22
+ - New block: `Delimiter` – renders horizontal rule (`<hr>`).
23
+ - Tests for all new blocks: structure validation, HTML output, plain output.
24
+ - Extended `document_spec.rb` to verify full document rendering with all blocks.
25
+
26
+ ### Changed
27
+ - Replaced manual file loading with Zeitwerk's automatic constant loading.
28
+
29
+ ---
30
+
31
+ ## [0.2.1] - 2025-04-23
15
32
 
16
33
  ### Added
17
34
  - New block: `Spoiler` – supports nested content via recursive rendering of inner `Document`.
data/README.md CHANGED
@@ -13,6 +13,8 @@ It allows rendering JSON data generated by Editor.js into safe HTML and plain te
13
13
  - Built-in validation using JSON Schema
14
14
  - Secure HTML output via escaping
15
15
  - Configurable block rendering system
16
+ - Support for nested blocks (blocks within blocks)
17
+ - Blocks: `Spoiler`, `Table`, `Checklist`, `Attaches`, `Code`, `Delimiter`, etc.
16
18
  - No JavaScript dependencies required on the server side
17
19
 
18
20
  ---
@@ -39,7 +41,12 @@ bundle install
39
41
  data = {
40
42
  "time" => "123456789",
41
43
  "blocks" => [
42
- { "type" => "paragraph", "data" => { "text" => "Hello <b>world</b>" } }
44
+ { "type" => "paragraph", "data" => { "text" => "Hello <b>world</b>" } },
45
+ { "type" => "checklist", "data" => { "items" => [
46
+ { "text" => "Buy milk", "checked" => true },
47
+ { "text" => "Read book", "checked" => false }
48
+ ]}
49
+ }
43
50
  ]
44
51
  }
45
52
  ```
@@ -47,10 +54,10 @@ data = {
47
54
  ```bash
48
55
  document = EditorjsRenderer::Document.new(data)
49
56
  document.render(format: :html)
50
- # => "<p>Hello &lt;b&gt;world&lt;/b&gt;</p>"
57
+ # => "<p>Hello &lt;b&gt;world&lt;/b&gt;</p><ul class=\"checklist-block\"><li><input type=\"checkbox\" checked disabled> Buy milk</li><li><input type=\"checkbox\" disabled> Read book</li></ul>"
51
58
 
52
59
  document.render(format: :plain)
53
- # => "Hello <b>world</b>"
60
+ # => "Hello <b>world</b>\n[x] Buy milk\n[ ] Read book"
54
61
  ```
55
62
 
56
63
  ---
@@ -75,6 +82,20 @@ end
75
82
  Schemas should follow the JSON Schema format and be stored in YAML files.
76
83
  Each block must have a schema named like paragraph.yml, header.yml, etc.
77
84
 
85
+ Example:
86
+ ```yml
87
+ type: object
88
+ required:
89
+ - text
90
+ properties:
91
+ text:
92
+ type: string
93
+ description: "The main content of the header block"
94
+ ```
95
+
96
+ In this schema:
97
+ - `text` is a required field of type string, which represents the header text.
98
+
78
99
  ---
79
100
 
80
101
  ## Development
@@ -110,6 +131,16 @@ module EditorjsRenderer
110
131
  end
111
132
  ```
112
133
 
134
+ #### Autoloading with Zeitwerk
135
+
136
+ This gem uses Zeitwerk to handle autoloading. Ensure you have Zeitwerk set up in your environment:
137
+
138
+ ```ruby
139
+ require "zeitwerk"
140
+
141
+ loader = Zeitwerk::Loader.for_gem
142
+ loader.setup
143
+ ```
113
144
  ---
114
145
 
115
146
  ## Contributing
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/attaches.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # Attaches block: renders a file download link with title and optional size.
7
+ class Attaches < Base
8
+ def to_html
9
+ url = ERB::Util.html_escape(block_data.dig("file", "url"))
10
+ title = ERB::Util.html_escape(block_data["title"].to_s)
11
+ size = block_data["size"]
12
+
13
+ size_str = size ? " (#{format_size(size)})" : ""
14
+ "<div class=\"attachment-block\"><a href=\"#{url}\" download>#{title}#{size_str}</a></div>"
15
+ end
16
+
17
+ def to_plain
18
+ url = block_data.dig("file", "url")
19
+ title = block_data["title"].to_s
20
+ size = block_data["size"]
21
+ size_str = size ? " (#{format_size(size)})" : ""
22
+ "[Attachment] #{title} — #{url}#{size_str}".strip
23
+ end
24
+
25
+ private
26
+
27
+ def format_size(bytes)
28
+ return unless bytes.respond_to?(:to_f) && bytes.to_f.positive?
29
+
30
+ kb = bytes.to_f / 1024
31
+ mb = kb / 1024
32
+ return "#{format("%.1f", mb)} MB" if mb >= 1
33
+
34
+ "#{format("%.1f", kb)} KB"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/checklist.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # Checklist block: renders a list of checkboxes (readonly)
7
+ class Checklist < Base
8
+ def to_html
9
+ items = block_data["items"].map do |item|
10
+ text = ERB::Util.html_escape(item["text"].to_s)
11
+ checked_attr = item["checked"] ? " checked" : ""
12
+ "<li><input type=\"checkbox\"#{checked_attr} disabled> #{text}</li>"
13
+ end
14
+
15
+ "<ul class=\"checklist-block\">#{items.join}</ul>"
16
+ end
17
+
18
+ def to_plain
19
+ block_data["items"].map do |item|
20
+ marker = item["checked"] ? "[x]" : "[ ]"
21
+ "#{marker} #{item["text"]}"
22
+ end.join("\n")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/code.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # Code block: renders a block of code inside <pre><code>
7
+ class Code < Base
8
+ def to_html
9
+ code = ERB::Util.html_escape(block_data["code"].to_s)
10
+ "<pre><code>#{code}</code></pre>"
11
+ end
12
+
13
+ def to_plain
14
+ block_data["code"].to_s
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/delimiter.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # Delimiter block: renders a visual separator line (horizontal rule)
7
+ #
8
+ # Used to separate content sections, similar to <hr> or "---" in text.
9
+ #
10
+ # @example
11
+ # Delimiter.new({}).to_html
12
+ # # => '<hr class="delimiter-block">'
13
+ #
14
+ # Delimiter.new({}).to_plain
15
+ # # => "---"
16
+ class Delimiter < Base
17
+ def to_html
18
+ '<hr class="delimiter-block">'
19
+ end
20
+
21
+ def to_plain
22
+ "---"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/header.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # Header block renders a heading tag (<h1>–<h6>) based on level.
7
+ #
8
+ # @example
9
+ # data = { "text" => "Title", "level" => 2 }
10
+ # Header.new(data).to_html # => "<h2>Title</h2>"
11
+ class Header < Base
12
+ def to_html
13
+ level = block_data["level"].to_i.clamp(1, 6)
14
+ text = ERB::Util.html_escape(block_data["text"])
15
+ "<h#{level}>#{text}</h#{level}>"
16
+ end
17
+
18
+ def to_plain
19
+ block_data["text"].to_s
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/image.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # Image block: renders an <img> tag with optional caption
7
+ class Image < Base
8
+ def to_html
9
+ url = ERB::Util.html_escape(block_data["url"])
10
+ caption = ERB::Util.html_escape(block_data["caption"].to_s)
11
+ figure = "<img src=\"#{url}\" alt=\"#{caption}\">"
12
+ caption.empty? ? figure : "<figure>#{figure}<figcaption>#{caption}</figcaption></figure>"
13
+ end
14
+
15
+ def to_plain
16
+ caption = block_data["caption"].to_s
17
+ "[Image] #{caption}".strip
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/editorjs_renderer/blocks/list.rb
4
+ module EditorjsRenderer
5
+ module Blocks
6
+ # List block: renders a list as <ul>/<ol> with <li> elements.
7
+ #
8
+ # Example block data:
9
+ # {
10
+ # "style": "ordered",
11
+ # "items": ["First", "Second"]
12
+ # }
13
+ #
14
+ # Renders to:
15
+ # <ol><li>First</li><li>Second</li></ol>
16
+ #
17
+ # Or in plain text:
18
+ # 1. First
19
+ # 2. Second
20
+ class List < Base
21
+ def to_html
22
+ style = block_data["style"] == "ordered" ? "ol" : "ul"
23
+ items = block_data["items"].map do |item|
24
+ "<li>#{ERB::Util.html_escape(item)}</li>"
25
+ end
26
+ "<#{style}>#{items.join}</#{style}>"
27
+ end
28
+
29
+ def to_plain
30
+ if block_data["style"] == "ordered"
31
+ block_data["items"].each_with_index.map { |item, i| "#{i + 1}. #{item}" }.join("\n")
32
+ else
33
+ block_data["items"].map { |item| "- #{item}" }.join("\n")
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -11,7 +11,7 @@ module EditorjsRenderer
11
11
 
12
12
  def initialize
13
13
  @schemas_path = File.join(EditorjsRenderer.root, "lib", "editorjs_renderer", "schemas")
14
- @enabled_blocks = %w[paragraph spoiler]
14
+ @enabled_blocks = %w[paragraph spoiler table header image list attaches checklist code delimiter]
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,18 @@
1
+ # lib/editorjs_renderer/schemas/attaches.yml
2
+
3
+ type: object
4
+ required:
5
+ - file
6
+ - title
7
+ properties:
8
+ file:
9
+ type: object
10
+ required:
11
+ - url
12
+ properties:
13
+ url:
14
+ type: string
15
+ title:
16
+ type: string
17
+ size:
18
+ type: integer
@@ -0,0 +1,18 @@
1
+ # lib/editorjs_renderer/schemas/checklist.yml
2
+
3
+ type: object
4
+ required:
5
+ - items
6
+ properties:
7
+ items:
8
+ type: array
9
+ items:
10
+ type: object
11
+ required:
12
+ - text
13
+ - checked
14
+ properties:
15
+ text:
16
+ type: string
17
+ checked:
18
+ type: boolean
@@ -0,0 +1,8 @@
1
+ # lib/editorjs_renderer/schemas/code.yml
2
+
3
+ type: object
4
+ required:
5
+ - code
6
+ properties:
7
+ code:
8
+ type: string
@@ -0,0 +1,3 @@
1
+ # lib/editorjs_renderer/delimiter.yml
2
+ type: object
3
+ properties: {}
@@ -0,0 +1,13 @@
1
+ # lib/editorjs_renderer/schemas/header.yml
2
+
3
+ type: object
4
+ required:
5
+ - text
6
+ - level
7
+ properties:
8
+ text:
9
+ type: string
10
+ level:
11
+ type: integer
12
+ minimum: 1
13
+ maximum: 6
@@ -0,0 +1,16 @@
1
+ # lib/editorjs_renderer/schemas/image.yml
2
+
3
+ type: object
4
+ required:
5
+ - url
6
+ properties:
7
+ url:
8
+ type: string
9
+ caption:
10
+ type: string
11
+ withBorder:
12
+ type: boolean
13
+ withBackground:
14
+ type: boolean
15
+ stretched:
16
+ type: boolean
@@ -0,0 +1,16 @@
1
+ # lib/editorjs_renderer/schemas/list.yml
2
+
3
+ type: object
4
+ required:
5
+ - style
6
+ - items
7
+ properties:
8
+ style:
9
+ type: string
10
+ enum:
11
+ - unordered
12
+ - ordered
13
+ items:
14
+ type: array
15
+ items:
16
+ type: string
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EditorjsRenderer
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -5,6 +5,10 @@ require "yaml"
5
5
  require "active_support/all"
6
6
  require "logger"
7
7
  require "json_schemer"
8
+ require "zeitwerk"
9
+
10
+ loader = Zeitwerk::Loader.for_gem
11
+ loader.setup
8
12
 
9
13
  # EditorjsRenderer provides rendering and configuration logic for EditorJS-compatible
10
14
  # data in Ruby applications. It allows transforming structured block-based data
@@ -45,15 +49,3 @@ module EditorjsRenderer
45
49
  end
46
50
  end
47
51
  end
48
-
49
- require_relative "editorjs_renderer/errors"
50
- require_relative "editorjs_renderer/config"
51
- require_relative "editorjs_renderer/document"
52
- require_relative "editorjs_renderer/renderers/html_renderer"
53
- require_relative "editorjs_renderer/renderers/plain_renderer"
54
- require_relative "editorjs_renderer/blocks/base"
55
- require_relative "editorjs_renderer/blocks/paragraph"
56
- require_relative "editorjs_renderer/blocks/spoiler"
57
- require_relative "editorjs_renderer/blocks/table"
58
- require_relative "editorjs_renderer/version"
59
- require_relative "editorjs_renderer/schema_validator"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: editorjs_renderer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georgy Shcherbakov
@@ -9,7 +9,7 @@ authors:
9
9
  - Grigory Paraschevin
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-04-23 00:00:00.000000000 Z
12
+ date: 2025-04-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionview
@@ -53,6 +53,20 @@ dependencies:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: 2.4.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: zeitwerk
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '2.7'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '2.7'
56
70
  description: Library for rendering and validating Editor.js documents in Rails applications
57
71
  email:
58
72
  - lordsynergymail@gmail.com
@@ -70,7 +84,14 @@ files:
70
84
  - README.md
71
85
  - Rakefile
72
86
  - lib/editorjs_renderer.rb
87
+ - lib/editorjs_renderer/blocks/attaches.rb
73
88
  - lib/editorjs_renderer/blocks/base.rb
89
+ - lib/editorjs_renderer/blocks/checklist.rb
90
+ - lib/editorjs_renderer/blocks/code.rb
91
+ - lib/editorjs_renderer/blocks/delimiter.rb
92
+ - lib/editorjs_renderer/blocks/header.rb
93
+ - lib/editorjs_renderer/blocks/image.rb
94
+ - lib/editorjs_renderer/blocks/list.rb
74
95
  - lib/editorjs_renderer/blocks/paragraph.rb
75
96
  - lib/editorjs_renderer/blocks/spoiler.rb
76
97
  - lib/editorjs_renderer/blocks/table.rb
@@ -80,7 +101,14 @@ files:
80
101
  - lib/editorjs_renderer/renderers/html_renderer.rb
81
102
  - lib/editorjs_renderer/renderers/plain_renderer.rb
82
103
  - lib/editorjs_renderer/schema_validator.rb
104
+ - lib/editorjs_renderer/schemas/attaches.yml
105
+ - lib/editorjs_renderer/schemas/checklist.yml
106
+ - lib/editorjs_renderer/schemas/code.yml
107
+ - lib/editorjs_renderer/schemas/delimiter.yml
83
108
  - lib/editorjs_renderer/schemas/document.yml
109
+ - lib/editorjs_renderer/schemas/header.yml
110
+ - lib/editorjs_renderer/schemas/image.yml
111
+ - lib/editorjs_renderer/schemas/list.yml
84
112
  - lib/editorjs_renderer/schemas/paragraph.yml
85
113
  - lib/editorjs_renderer/schemas/spoiler.yml
86
114
  - lib/editorjs_renderer/schemas/table.yml