lwe_slate_serializer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1e1afc95f11d60edc3272a0097520e1bddca78ee9a8c37cd6908ff63ed0563bd
4
+ data.tar.gz: 98c0ee15eebb1e2e5e7537419c4144d2985121487c8fa65cc26064da3871b02f
5
+ SHA512:
6
+ metadata.gz: 4d84ccba0d9b4027b1888696aa01a34de921d51826c0665671497c640b9d559ddbfa739b09a1d5c0a946671a5539b29b26149ad4056466ae44404351109f4f9b
7
+ data.tar.gz: e5f8ff256e04ef82167592b755699ebe1fa80506edcb0d4f99bf46ccc5474f4454011cb32488b50fb08a8882034ae36d7a1d8bcd1a78614af96bac7d4a62dbb9
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.2
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.2
7
+ before_install: gem install bundler -v 1.17.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in slate_serializer.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,41 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lwe_slate_serializer (1.0.0)
5
+ nokogiri (~> 1.11)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.4.4)
11
+ mini_portile2 (2.8.0)
12
+ nokogiri (1.13.3)
13
+ mini_portile2 (~> 2.8.0)
14
+ racc (~> 1.4)
15
+ racc (1.6.0)
16
+ rake (13.0.3)
17
+ rspec (3.10.0)
18
+ rspec-core (~> 3.10.0)
19
+ rspec-expectations (~> 3.10.0)
20
+ rspec-mocks (~> 3.10.0)
21
+ rspec-core (3.10.1)
22
+ rspec-support (~> 3.10.0)
23
+ rspec-expectations (3.10.1)
24
+ diff-lcs (>= 1.2.0, < 2.0)
25
+ rspec-support (~> 3.10.0)
26
+ rspec-mocks (3.10.2)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.10.0)
29
+ rspec-support (3.10.2)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ bundler (~> 2.2)
36
+ lwe_slate_serializer!
37
+ rake (~> 13.0)
38
+ rspec (~> 3.0)
39
+
40
+ BUNDLED WITH
41
+ 2.2.22
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # SlateSerializer
2
+
3
+ SlateSerializer de- and serializer text and html to Slate document values in Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'slate_serializer'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install slate_serializer
20
+
21
+ ## Usage
22
+
23
+ To convert between plain text and Slate document use:
24
+
25
+ $ SlateSerializer::Plain.serializer([...]) => text
26
+ $ SlateSerializer::Plain.deserializer(text) => [...]
27
+
28
+ To convert between html and Slate document use:
29
+
30
+ $ SlateSerializer::Html.deserializer(html) => [...]
31
+
32
+ ## Contributing
33
+
34
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wesleystam/slate_serializer.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'slate_serializer'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,188 @@
1
+ require 'nokogiri'
2
+
3
+ module SlateSerializer
4
+ # Html de- and serializer
5
+ class Html
6
+ # Default lookup list to convert html tags to object types
7
+ ELEMENTS = {
8
+ 'a': 'link',
9
+ 'img': 'image',
10
+ 'li': 'list-item',
11
+ 'p': 'paragraph',
12
+ 'div': 'paragraph',
13
+ 'ol1': 'ordered-list',
14
+ 'ola': 'alpha-ordered-list',
15
+ 'ol': 'ordered-list',
16
+ 'ul': 'unordered-list',
17
+ 'table': 'table',
18
+ 'tbody': 'tbody',
19
+ 'tr': 'tr',
20
+ 'td': 'td',
21
+ 'text': 'text',
22
+ 'hr': 'hr',
23
+ 'figure': 'figure',
24
+ 'figcaption': 'figcaption'
25
+ }.freeze
26
+ # Default block types list
27
+ BLOCK_ELEMENTS = %w[figure figcaption hr img li p ol ul table tbody tr td].freeze
28
+ # Default inline types list
29
+ INLINE_ELEMENTS = %w[a].freeze
30
+ # Default mark types list
31
+ MARK_ELEMENTS = {
32
+ 'em': 'italic',
33
+ 'strong': 'bold',
34
+ 'u': 'underline'
35
+ }.freeze
36
+
37
+ class << self
38
+ # Convert html to a Slate document
39
+ #
40
+ # @param html format [String] the HTML
41
+ # @param options [Hash]
42
+ # @option options [Array] :elements Lookup list to convert html tags to object types
43
+ # @option options [Array] :block_elemnts List of block types
44
+ # @option options [Array] :inline_elemnts List of inline types
45
+ # @option options [Array] :mark_elemnts List of mark types
46
+ def deserializer(html, options = {})
47
+ return empty_state if html.nil? || html == ''
48
+
49
+ self.elements = options[:elements] || ELEMENTS
50
+ self.block_elements = options[:block_elements] || BLOCK_ELEMENTS
51
+ self.inline_elements = options[:inline_elements] || INLINE_ELEMENTS
52
+ self.mark_elements = options[:mark_elements] || MARK_ELEMENTS
53
+
54
+ html = html.gsub('<br>', "\n")
55
+ Nokogiri::HTML.fragment(html).elements.map do |element|
56
+ element_to_node(element)
57
+ end
58
+ end
59
+
60
+ # Convert html to a Slate document
61
+ #
62
+ # @param value format [Hash] the Slate document
63
+ # @return [String] plain text version of the Slate documnent
64
+ def serializer(value)
65
+ return '' unless value.is_a?(Array)
66
+
67
+ value.map { |n| serialize_node(n) }.join
68
+ end
69
+
70
+ private
71
+
72
+ attr_accessor :elements, :block_elements, :inline_elements, :mark_elements
73
+
74
+ def element_to_node(element)
75
+ type = convert_name_to_type(element)
76
+ children = element.children.flat_map do |child|
77
+ if block?(child)
78
+ element_to_node(child)
79
+ elsif inline?(child)
80
+ element_to_inline(child)
81
+ else
82
+ next if child.text.strip == ''
83
+
84
+ element_to_texts(child)
85
+ end
86
+ end.compact
87
+
88
+ children << { text: '' } if children.empty? && type != 'image'
89
+
90
+ node = {
91
+ children: children,
92
+ type: type
93
+ }
94
+
95
+ type.is_a?(Proc) ? type.call(node, element) : node
96
+ end
97
+
98
+ def element_to_inline(element)
99
+ type = convert_name_to_type(element)
100
+ nodes = element.children.flat_map do |child|
101
+ element_to_texts(child)
102
+ end
103
+
104
+ {
105
+ children: nodes,
106
+ type: type
107
+ }
108
+ end
109
+
110
+ def element_to_texts(element)
111
+ nodes = []
112
+ mark = convert_name_to_mark(element.name)
113
+
114
+ if element.class == Nokogiri::XML::Element
115
+ element.children.each do |child|
116
+ nodes << element_to_text(child, mark)
117
+ end
118
+ else
119
+ nodes << element_to_text(element)
120
+ end
121
+
122
+ nodes
123
+ end
124
+
125
+ def element_to_text(element, mark = nil)
126
+ {
127
+ text: element.text
128
+ }.tap do |text|
129
+ [mark, convert_name_to_mark(element.name)].compact.each do |m|
130
+ text[m[:type].to_sym] = true
131
+ end
132
+ end
133
+ end
134
+
135
+ def convert_name_to_type(element)
136
+ type = [element.name, element.attributes['type']&.value].compact.join
137
+ elements[type.to_sym] || elements[:p]
138
+ end
139
+
140
+ def convert_name_to_mark(name)
141
+ type = mark_elements[name.to_sym]
142
+
143
+ return nil unless type
144
+
145
+ {
146
+ type: type
147
+ }
148
+ end
149
+
150
+ def block?(element)
151
+ block_elements.include?(element.name)
152
+ end
153
+
154
+ def inline?(element)
155
+ inline_elements.include?(element.name)
156
+ end
157
+
158
+ def empty_state
159
+ [
160
+ {
161
+ type: 'paragraph',
162
+ children: [
163
+ {
164
+ text: ''
165
+ }
166
+ ]
167
+ }
168
+ ]
169
+ end
170
+
171
+ def serialize_node(node)
172
+ if node[:text]
173
+ node[:text]
174
+ else
175
+ children = node[:children].map { |n| serialize_node(n) }.join
176
+
177
+ element = ELEMENTS.find { |_, v| v == node[:type] }[0]
178
+
179
+ if %i[ol1 ola].include?(element)
180
+ element = :ol
181
+ end
182
+
183
+ "<#{element}>#{children}</#{element}>"
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,69 @@
1
+ module SlateSerializer
2
+ # Text de- and serializer
3
+ class Plain
4
+ class << self
5
+ # Convert text to a Slate document
6
+ #
7
+ # @param text format [String] the text
8
+ # return [Hash] Slate document
9
+ def deserializer(text)
10
+ text = '' if text.nil?
11
+
12
+ lines = split_text_into_lines(text)
13
+ convert_lines_into_nodes(lines)
14
+ end
15
+
16
+ # Convert a Slate Document to plain text
17
+ #
18
+ # @param value format [Hash] the Slate document
19
+ # @param options format [Hash] options for the serializer, delimitter defaults to "\n"
20
+ # @return [String] plain text version of the Slate documnent
21
+ def serializer(value, options = {})
22
+ return '' unless value.is_a?(Array)
23
+
24
+ options[:delimiter] = "\n" unless options.key?(:delimiter)
25
+
26
+ value.map { |n| serialize_node(n, options) }.join(options[:delimiter])
27
+ end
28
+
29
+ private
30
+
31
+ def split_text_into_lines(text)
32
+ lines = text.strip.split("\n").map(&:strip)
33
+ blocks = []
34
+
35
+ loop do
36
+ index = lines.find_index('')
37
+ if index.nil?
38
+ blocks << lines.join("\n")
39
+ break
40
+ end
41
+
42
+ blocks << lines[0...index].join("\n")
43
+ lines.shift(index + 1)
44
+ end
45
+
46
+ blocks.length == 1 ? blocks : blocks.reject { |block| block == '' }
47
+ end
48
+
49
+ def convert_lines_into_nodes(lines)
50
+ lines.map do |line|
51
+ {
52
+ type: 'paragraph',
53
+ children: [
54
+ text: line
55
+ ]
56
+ }
57
+ end
58
+ end
59
+
60
+ def serialize_node(node, options)
61
+ if node[:text]
62
+ node[:text]
63
+ else
64
+ node[:children].map { |n| serialize_node(n, options) }.join(options[:delimiter])
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module SlateSerializer
2
+ VERSION = '1.0.0'.freeze
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'slate_serializer/html'
2
+ require 'slate_serializer/plain'
3
+ require 'slate_serializer/version'
4
+
5
+ # Main module
6
+ module SlateSerializer
7
+ end
@@ -0,0 +1,28 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'slate_serializer/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'lwe_slate_serializer'
7
+ spec.version = SlateSerializer::VERSION
8
+ spec.authors = ['Wesley Stam', 'Paul Crabtree']
9
+ spec.email = ['wesley@stam.me', 'paul@learningwithexperts.com']
10
+ spec.license = 'MIT'
11
+
12
+ spec.summary = 'Serializer for Slate documents written in Ruby'
13
+ spec.homepage = 'https://github.com/learningwithexperts/slate_serializer'
14
+
15
+ # Specify which files should be added to the gem when it is released.
16
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ end
20
+ spec.bindir = 'exe'
21
+ #spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'nokogiri', '~> 1.11'
25
+ spec.add_development_dependency 'bundler', '~> 2.2'
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lwe_slate_serializer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Wesley Stam
8
+ - Paul Crabtree
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2022-03-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.11'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.11'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '2.2'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '2.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '13.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '13.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
70
+ description:
71
+ email:
72
+ - wesley@stam.me
73
+ - paul@learningwithexperts.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".rspec"
80
+ - ".ruby-version"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - Gemfile.lock
84
+ - README.md
85
+ - Rakefile
86
+ - bin/console
87
+ - bin/setup
88
+ - lib/slate_serializer.rb
89
+ - lib/slate_serializer/html.rb
90
+ - lib/slate_serializer/plain.rb
91
+ - lib/slate_serializer/version.rb
92
+ - slate_serializer.gemspec
93
+ homepage: https://github.com/learningwithexperts/slate_serializer
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubygems_version: 3.3.8
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Serializer for Slate documents written in Ruby
116
+ test_files: []