guileless 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.
- checksums.yaml +15 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +17 -0
- data/LICENSE +19 -0
- data/README.md +42 -0
- data/guileless.gemspec +24 -0
- data/lib/guileless.rb +15 -0
- data/lib/guileless/input_stream.rb +43 -0
- data/lib/guileless/output_buffer.rb +33 -0
- data/lib/guileless/parse_methods.rb +158 -0
- data/lib/guileless/parser.rb +96 -0
- data/lib/guileless/state_machine.rb +33 -0
- data/lib/guileless/tag_library.rb +33 -0
- data/lib/guileless/version.rb +5 -0
- data/spec/guileless_spec.rb +69 -0
- data/spec/spec_helper.rb +20 -0
- metadata +64 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YTk5NzVjNzdhY2JhMGVlNGQzYjY3OWQyYjdiY2VjNTJhM2Y5YTI0NQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YTcxMzkzNGIwODYxZTkzZWRiMDdkY2Q4ZTY3NWMwYTZiMjY5MjFjOQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTY5N2UwYzg3YTQ0Yzk4OGJlMDQwZWQ1ZGM3NGY4YjE1MjBjNTRhZDBiODM3
|
10
|
+
YmIwMWI1MzY4ZGRkMDE5ZDE4ZTQwNDgwYWFlZDFiMTVlZThiZTk1ODhjOTUw
|
11
|
+
NTdkZmJlMjY4MTJhMDE5NjdkYTM0MzExZTVhMGEzZWMyNTQzNDQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzgwYWY1ZWY2M2U2OTBmYTkyNTI5NTUwMzk0MDAwMTNmM2Q2ZDViOThjNDlj
|
14
|
+
YTU3YjNiYWJiODAxNjk5ZjBhZDVhZjg1NjgxMDhjZjAxYmQ5MDZkZjVlN2Q4
|
15
|
+
NDIxYmRmMTY3MjIyZjVmZWIxN2RiMGQwYmRmZDQwMDg5ODA3Nzk=
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
GEM
|
2
|
+
specs:
|
3
|
+
diff-lcs (1.2.4)
|
4
|
+
rspec (2.14.1)
|
5
|
+
rspec-core (~> 2.14.0)
|
6
|
+
rspec-expectations (~> 2.14.0)
|
7
|
+
rspec-mocks (~> 2.14.0)
|
8
|
+
rspec-core (2.14.5)
|
9
|
+
rspec-expectations (2.14.3)
|
10
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
11
|
+
rspec-mocks (2.14.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2013 Inge Jørgensen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Guileless [](https://travis-ci.org/elektronaut/guileless) [](https://codeclimate.com/github/elektronaut/guileless)
|
2
|
+
|
3
|
+
Guileless is a naive HTML preprocessor. It does three things:
|
4
|
+
|
5
|
+
1. Single line breaks are converted to `<br>`
|
6
|
+
2. Several consecutive line breaks are treated as paragraphs and wrapped in `<p>`
|
7
|
+
3. Converts stray `<`, `>`, and `&`s to HTML entities.
|
8
|
+
|
9
|
+
Why is this more useful than, say, Rails' built in `simple_format`?
|
10
|
+
|
11
|
+
Well, it's actually a real (if simplistic) HTML parser. It understands nested
|
12
|
+
tags, and will happily format text nodes inside `div`s and `blockquote`s.
|
13
|
+
|
14
|
+
However, it does **NOT** do any sanitation on the input.
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
Guileless.format("<div>foo</div>") # => "<div><p>foo</p></div>"
|
20
|
+
```
|
21
|
+
|
22
|
+
## License
|
23
|
+
|
24
|
+
Copyright (c) 2013 Inge Jørgensen
|
25
|
+
|
26
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
27
|
+
of this software and associated documentation files (the "Software"), to deal
|
28
|
+
in the Software without restriction, including without limitation the rights
|
29
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
30
|
+
copies of the Software, and to permit persons to whom the Software is
|
31
|
+
furnished to do so, subject to the following conditions:
|
32
|
+
|
33
|
+
The above copyright notice and this permission notice shall be included in
|
34
|
+
all copies or substantial portions of the Software.
|
35
|
+
|
36
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
37
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
38
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
39
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
40
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
41
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
42
|
+
THE SOFTWARE.
|
data/guileless.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.push File.expand_path("../lib", __FILE__)
|
4
|
+
require "guileless/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'guileless'
|
8
|
+
s.version = Guileless::VERSION
|
9
|
+
s.date = '2013-10-20'
|
10
|
+
s.summary = "Naive HTML preprocessor"
|
11
|
+
s.description = "Naive HTML preprocessor"
|
12
|
+
s.authors = ["Inge Jørgensen"]
|
13
|
+
s.email = 'inge@elektronaut.no'
|
14
|
+
s.files = ["lib/hola.rb"]
|
15
|
+
s.homepage = 'http://github.com/elektronaut/guileless'
|
16
|
+
s.license = 'MIT'
|
17
|
+
s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
|
24
|
+
end
|
data/lib/guileless.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "guileless/input_stream"
|
2
|
+
require "guileless/output_buffer"
|
3
|
+
require "guileless/parse_methods"
|
4
|
+
require "guileless/state_machine"
|
5
|
+
require "guileless/tag_library"
|
6
|
+
require "guileless/parser"
|
7
|
+
require "guileless/version"
|
8
|
+
|
9
|
+
module Guileless
|
10
|
+
class << self
|
11
|
+
def format(str)
|
12
|
+
Parser.new(str).to_html
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Guileless
|
2
|
+
class InputStream
|
3
|
+
def initialize(input)
|
4
|
+
@buffer = input.chars.to_a
|
5
|
+
end
|
6
|
+
|
7
|
+
def reinject(char)
|
8
|
+
@buffer.unshift(char)
|
9
|
+
end
|
10
|
+
|
11
|
+
def empty?
|
12
|
+
@buffer.length == 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch
|
16
|
+
@buffer.shift
|
17
|
+
end
|
18
|
+
|
19
|
+
def discard(count=1)
|
20
|
+
count.times { @buffer.shift }
|
21
|
+
end
|
22
|
+
|
23
|
+
def strip_whitespace
|
24
|
+
@buffer.shift while @buffer.first == "\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
def peek?(patterns)
|
28
|
+
match = false
|
29
|
+
Array(patterns).each do |pattern|
|
30
|
+
if pattern.kind_of?(Regexp)
|
31
|
+
match = true if self.to_s =~ pattern
|
32
|
+
elsif pattern.kind_of?(String)
|
33
|
+
match = true if self.to_s[0...(pattern.length)] == pattern
|
34
|
+
end
|
35
|
+
end
|
36
|
+
match
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
@buffer.join
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Guileless
|
2
|
+
class OutputBuffer
|
3
|
+
def initialize
|
4
|
+
@output_buffer = []
|
5
|
+
@output = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(str)
|
9
|
+
str = str.chars.to_a if str.kind_of?(String)
|
10
|
+
@output_buffer += Array(str)
|
11
|
+
str
|
12
|
+
end
|
13
|
+
|
14
|
+
def buffered?
|
15
|
+
@output_buffer.length > 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def flush
|
19
|
+
@output += @output_buffer
|
20
|
+
@output_buffer = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def wrap(prefix, postfix)
|
24
|
+
prefix = prefix.chars.to_a if prefix.kind_of?(String)
|
25
|
+
postfix = postfix.chars.to_a if postfix.kind_of?(String)
|
26
|
+
@output_buffer = Array(prefix) + @output_buffer + Array(postfix)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
@output.join
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Guileless
|
2
|
+
module ParseMethods
|
3
|
+
|
4
|
+
def parse_attribute_name(char)
|
5
|
+
case
|
6
|
+
when char !=~ /[\w\-]/
|
7
|
+
stream.reinject char
|
8
|
+
[false, :tag]
|
9
|
+
when char == "=" && stream.peek?("'")
|
10
|
+
stream.discard
|
11
|
+
["='", :attribute_value_single_quote]
|
12
|
+
when char == "=" && stream.peek?("\"")
|
13
|
+
stream.discard
|
14
|
+
["=\"", :attribute_value_double_quote]
|
15
|
+
when char == "="
|
16
|
+
[char, :attribute_value]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_attribute_value(char)
|
21
|
+
case
|
22
|
+
when char !=~ /[\w\d]/
|
23
|
+
stream.reinject char
|
24
|
+
[false, :tag]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_attribute_value_single_quote(char)
|
29
|
+
case
|
30
|
+
when char == "'"
|
31
|
+
[char, :tag]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_attribute_value_double_quote(char)
|
36
|
+
case
|
37
|
+
when char == "\""
|
38
|
+
[char, :tag]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_comment(char)
|
43
|
+
case
|
44
|
+
when char == "-" && stream.peek?("->")
|
45
|
+
stream.discard(2)
|
46
|
+
["-->", :text]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_tag(char)
|
51
|
+
case
|
52
|
+
when char =~ /\w/
|
53
|
+
[char, :attribute_name]
|
54
|
+
when char == ">"
|
55
|
+
[char, :text]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_closing_tag(char)
|
60
|
+
case
|
61
|
+
when char == ">"
|
62
|
+
[char, :text]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_tag_name(char)
|
67
|
+
case
|
68
|
+
when char =~ /\w/
|
69
|
+
@tag_name += char
|
70
|
+
char
|
71
|
+
else
|
72
|
+
stream.reinject char
|
73
|
+
[false, :tag]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_closing_tag_name(char)
|
78
|
+
case
|
79
|
+
when char =~ /\w/
|
80
|
+
@tag_name += char
|
81
|
+
char
|
82
|
+
else
|
83
|
+
stream.reinject char
|
84
|
+
[false, :closing_tag]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_left_angled_quote(char)
|
89
|
+
case
|
90
|
+
|
91
|
+
# Comment
|
92
|
+
when stream.peek?("!--")
|
93
|
+
stream.discard(3)
|
94
|
+
["<!--", :comment]
|
95
|
+
|
96
|
+
# Opening block tag
|
97
|
+
when stream.peek?(block_level_tags)
|
98
|
+
flush_buffer
|
99
|
+
[char, :tag_name]
|
100
|
+
|
101
|
+
# Opening tag
|
102
|
+
when stream.peek?(html_tags)
|
103
|
+
[char, :tag_name]
|
104
|
+
|
105
|
+
# Closing block level tag
|
106
|
+
when stream.peek?(closing(block_level_tags))
|
107
|
+
flush_buffer
|
108
|
+
stream.discard
|
109
|
+
["</", :closing_tag_name]
|
110
|
+
|
111
|
+
# Closing tag
|
112
|
+
when stream.peek?(closing(html_tags))
|
113
|
+
stream.discard
|
114
|
+
["</", :closing_tag_name]
|
115
|
+
|
116
|
+
# Escape left angled bracket
|
117
|
+
else
|
118
|
+
@char_count += 4
|
119
|
+
"<"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def parse_text(char)
|
124
|
+
case
|
125
|
+
|
126
|
+
# Comment
|
127
|
+
when char == "<"
|
128
|
+
parse_left_angled_quote(char)
|
129
|
+
|
130
|
+
# Escape right angled bracket
|
131
|
+
when char == ">"
|
132
|
+
@char_count += 4
|
133
|
+
">"
|
134
|
+
|
135
|
+
# Escape ampersands
|
136
|
+
when char == "&" && !stream.peek?("amp;")
|
137
|
+
@char_count += 5
|
138
|
+
"&"
|
139
|
+
|
140
|
+
# Paragraph break
|
141
|
+
when char == "\n" && stream.peek?("\n")
|
142
|
+
flush_buffer
|
143
|
+
stream.strip_whitespace
|
144
|
+
false
|
145
|
+
|
146
|
+
# Line break
|
147
|
+
when char == "\n"
|
148
|
+
"<br>"
|
149
|
+
|
150
|
+
when char !=~ /\s/
|
151
|
+
@char_count += 1
|
152
|
+
char
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Guileless
|
2
|
+
class Parser < Guileless::StateMachine
|
3
|
+
include Guileless::TagLibrary
|
4
|
+
include Guileless::ParseMethods
|
5
|
+
|
6
|
+
attr_reader :input, :stream, :tag_stack, :buffer, :tag_name, :char_count
|
7
|
+
|
8
|
+
before_transition :reset_tag_name, [:tag_name, :closing_tag_name]
|
9
|
+
before_transition :add_tag_to_stack, :text, from: [:tag]
|
10
|
+
before_transition :close_tag, :text, from: [:closing_tag]
|
11
|
+
before_transition :finish_tag, :text, from: [:tag, :closing_tag]
|
12
|
+
before_transition :flush_buffer, :end
|
13
|
+
|
14
|
+
def initialize(input)
|
15
|
+
@input = input
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_html
|
19
|
+
parse!
|
20
|
+
buffer.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse!
|
24
|
+
reset!
|
25
|
+
read while !stream.empty?
|
26
|
+
transition(:end)
|
27
|
+
end
|
28
|
+
|
29
|
+
def read
|
30
|
+
char = stream.fetch
|
31
|
+
value, next_state = Array(self.send("parse_#{state}".to_sym, char))
|
32
|
+
|
33
|
+
if value === nil
|
34
|
+
buffer.add char
|
35
|
+
elsif value
|
36
|
+
buffer.add value
|
37
|
+
end
|
38
|
+
|
39
|
+
transition(next_state) if next_state
|
40
|
+
end
|
41
|
+
|
42
|
+
def wrap_in_paragraph?
|
43
|
+
state == :text &&
|
44
|
+
char_count > 0 &&
|
45
|
+
buffer.buffered? &&
|
46
|
+
(!last_block_level_tag || paragraph_container_tags.include?(last_block_level_tag))
|
47
|
+
end
|
48
|
+
|
49
|
+
def flush_buffer
|
50
|
+
if wrap_in_paragraph?
|
51
|
+
if buffer.buffered? && char_count > 0
|
52
|
+
buffer.wrap("<p>", "</p>")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@char_count = 0
|
56
|
+
buffer.flush
|
57
|
+
end
|
58
|
+
|
59
|
+
def finish_tag
|
60
|
+
if block_level_tags.include?(tag_name)
|
61
|
+
flush_buffer
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_tag_to_stack
|
66
|
+
@tag_stack << tag_name
|
67
|
+
end
|
68
|
+
|
69
|
+
def close_tag
|
70
|
+
unwind_tag_stack(tag_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def unwind_tag_stack(tag)
|
74
|
+
if tag_stack.include?(tag)
|
75
|
+
last_tag = tag_stack.pop while last_tag != tag
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def last_block_level_tag
|
80
|
+
tag_stack.reverse.select{|t| block_level_tags.include?(t) }.first
|
81
|
+
end
|
82
|
+
|
83
|
+
def reset_tag_name
|
84
|
+
@tag_name = ""
|
85
|
+
end
|
86
|
+
|
87
|
+
def reset!
|
88
|
+
@char_count = 0
|
89
|
+
@buffer = Guileless::OutputBuffer.new
|
90
|
+
@stream = Guileless::InputStream.new(input)
|
91
|
+
@tag_stack = []
|
92
|
+
reset_tag_name
|
93
|
+
@state = :text
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Guileless
|
2
|
+
class StateMachine
|
3
|
+
class NoStateError < StandardError; end
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def transitions
|
7
|
+
@transitions ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def before_transition(name, states, options={})
|
11
|
+
transitions << [name, Array(states), options]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def state
|
16
|
+
raise NoStateError unless @state
|
17
|
+
@state
|
18
|
+
end
|
19
|
+
|
20
|
+
def transition(new_state)
|
21
|
+
self.class.transitions.each do |callback, callback_states, options|
|
22
|
+
if callback_states.include?(new_state)
|
23
|
+
if !options[:from] || options[:from].include?(state)
|
24
|
+
self.send("#{callback}".to_sym)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@state = new_state
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Guileless
|
2
|
+
module TagLibrary
|
3
|
+
def closing(tags)
|
4
|
+
tags.map{|t| "/#{t}" }
|
5
|
+
end
|
6
|
+
|
7
|
+
def html_tags
|
8
|
+
%w{
|
9
|
+
a abbr address area article aside audio b base bdi bdo blockquote
|
10
|
+
body br button canvas caption cite code col colgroup data datalist
|
11
|
+
dd del details dfn div dl dt em embed fieldset figcaption figure
|
12
|
+
footer form h1 h2 h3 h4 h5 h6 head header hr html i iframe img
|
13
|
+
input ins kbd keygen label legend li link main map mark math menu
|
14
|
+
menuitem meta meter nav noscript object ol optgroup option output
|
15
|
+
p param pre progress q rp rt ruby s samp section select small source
|
16
|
+
span strong style sub summary svg table tbody td textarea tfoot th
|
17
|
+
thead time title tr track u ul var video wbr
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def block_level_tags
|
22
|
+
%w{
|
23
|
+
address article aside audio blockquote canvas dd div dl fieldset
|
24
|
+
figcaption figure footer form h1 h2 h3 h4 h5 h6 header hgroup hr
|
25
|
+
noscript ol output p pre section table tfoot ul video
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def paragraph_container_tags
|
30
|
+
%w{article aside blockquote div footer header}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Guileless do
|
4
|
+
describe ".format" do
|
5
|
+
it "allows comments" do
|
6
|
+
Guileless.format("foo <!-- <b>comment</b> --> bar").should == "<p>foo <!-- <b>comment</b> --> bar</p>"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "doesn't wrap comments" do
|
10
|
+
Guileless.format("<!-- <b>comment</b> -->").should == "<!-- <b>comment</b> -->"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "doesn't wrap empty block tags" do
|
14
|
+
Guileless.format("<div></div>").should == "<div></div>"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "ignores empty tags" do
|
18
|
+
Guileless.format("<b></b>").should == "<b></b>"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "converts single breaks to <br>" do
|
22
|
+
Guileless.format("foo\nbar").should == "<p>foo<br>bar</p>"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "converts double breaks to <br>" do
|
26
|
+
Guileless.format("foo\n\nbar").should == "<p>foo</p><p>bar</p>"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "escapes left angled brackets" do
|
30
|
+
Guileless.format("<").should == "<p><</p>"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "escapes right angled brackets" do
|
34
|
+
Guileless.format(">").should == "<p>></p>"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "escapes ampersands" do
|
38
|
+
Guileless.format("&").should == "<p>&</p>"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "doesn't escape already escaped ampersands" do
|
42
|
+
Guileless.format("&").should == "<p>&</p>"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "understands empty attributes" do
|
46
|
+
Guileless.format("<blockquote data-foo>stuff</blockquote>").should == "<blockquote data-foo><p>stuff</p></blockquote>"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "understands single quoted attributes" do
|
50
|
+
Guileless.format("<blockquote data-foo='bar'>stuff</blockquote>").should == "<blockquote data-foo='bar'><p>stuff</p></blockquote>"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "understands double quoted attributes" do
|
54
|
+
Guileless.format("<blockquote data-foo=\"bar\">stuff</blockquote>").should == "<blockquote data-foo=\"bar\"><p>stuff</p></blockquote>"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "ignores non-closed tags" do
|
58
|
+
Guileless.format("<blockquote><b>stuff</blockquote>").should == "<blockquote><p><b>stuff</p></blockquote>"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "nests tags properly" do
|
62
|
+
Guileless.format("foo<blockquote>bar</blockquote>baz").should == "<p>foo</p><blockquote><p>bar</p></blockquote><p>baz</p>"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "doesn't wrap existing paragraphs" do
|
66
|
+
Guileless.format("<p>foo</p>").should == "<p>foo</p>"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require_relative '../lib/guileless'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: guileless
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Inge Jørgensen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-20 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Naive HTML preprocessor
|
14
|
+
email: inge@elektronaut.no
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- .gitignore
|
20
|
+
- .rspec
|
21
|
+
- .travis.yml
|
22
|
+
- Gemfile
|
23
|
+
- Gemfile.lock
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
- guileless.gemspec
|
27
|
+
- lib/guileless.rb
|
28
|
+
- lib/guileless/input_stream.rb
|
29
|
+
- lib/guileless/output_buffer.rb
|
30
|
+
- lib/guileless/parse_methods.rb
|
31
|
+
- lib/guileless/parser.rb
|
32
|
+
- lib/guileless/state_machine.rb
|
33
|
+
- lib/guileless/tag_library.rb
|
34
|
+
- lib/guileless/version.rb
|
35
|
+
- spec/guileless_spec.rb
|
36
|
+
- spec/spec_helper.rb
|
37
|
+
homepage: http://github.com/elektronaut/guileless
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.9.2
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 2.1.4
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: Naive HTML preprocessor
|
61
|
+
test_files:
|
62
|
+
- spec/guileless_spec.rb
|
63
|
+
- spec/spec_helper.rb
|
64
|
+
has_rdoc:
|