htx 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/htx.rb +63 -33
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32fe6cdd2942dae5d197592bc9dbe2248b93bebcfe0d0fb5a82b463b9e953c28
|
4
|
+
data.tar.gz: 36496d0d5395836bb8196f6a1fe2b02af7634c97c2028536e149b7a69d1603d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9c9bf24ca54886e6f4b9ad8e2bd8796436f299b2c0af7a0d742ac1b6ade2e55a30e477e4e5bb5b6d17a766641cd20cac8b3a0140e1fbfa48dda234664bf9c95
|
7
|
+
data.tar.gz: 85640a72d956e08d1f1467b8b3ef609e91f9bbc918e15b5c1faaf9065410b3b1f9324d30f82b65f9b12deae5417132f0aa6fa8fb081b8ccd7cb173f5f5af9360
|
data/lib/htx.rb
CHANGED
@@ -6,7 +6,9 @@ require('nokogiri')
|
|
6
6
|
# A Ruby compiler for HTX templates.
|
7
7
|
#
|
8
8
|
class HTX
|
9
|
-
|
9
|
+
class MalformedTemplateError < StandardError; end
|
10
|
+
|
11
|
+
VERSION = '0.0.2'
|
10
12
|
|
11
13
|
CHILDLESS = 0b01
|
12
14
|
TEXT_NODE = 0b10
|
@@ -33,29 +35,57 @@ class HTX
|
|
33
35
|
CLOSE_STATEMENT = /;?\s*htx\.close\((\d*)\);?(\s*)\z/.freeze
|
34
36
|
|
35
37
|
##
|
36
|
-
#
|
37
|
-
# used, but it can be anything).
|
38
|
+
# Convenience method to create a new instance and immediately call compile on it.
|
38
39
|
#
|
39
40
|
def self.compile(name, template)
|
40
|
-
|
41
|
-
|
41
|
+
new(name, template).compile
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Creates a new HTX instance. Conventionally the path of the template file is used for the name, but it
|
46
|
+
# can be anything.
|
47
|
+
#
|
48
|
+
def initialize(name, template)
|
49
|
+
@name = name
|
50
|
+
@template = template
|
51
|
+
end
|
42
52
|
|
43
|
-
|
44
|
-
|
53
|
+
##
|
54
|
+
# Compiles the HTX template.
|
55
|
+
#
|
56
|
+
def compile
|
57
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(@template)
|
58
|
+
root_nodes = doc.children.select { |n| n.element? || (n.text? && n.text.strip != '') }
|
59
|
+
|
60
|
+
if root_nodes.any?(&:text?)
|
61
|
+
raise(MalformedTemplateError.new('Template contains text at its root level'))
|
62
|
+
elsif root_nodes.size == 0
|
63
|
+
raise(MalformedTemplateError.new('Template does not have a root node'))
|
64
|
+
elsif root_nodes.size > 1
|
65
|
+
raise(MalformedTemplateError.new('Template has more than one node at its root level'))
|
66
|
+
end
|
67
|
+
|
68
|
+
@compiled = ''.dup
|
69
|
+
@static_key = 0
|
70
|
+
|
71
|
+
process(doc)
|
72
|
+
@compiled.rstrip!
|
45
73
|
|
46
74
|
<<~EOS
|
47
|
-
window['#{name}'] = function(htx) {
|
48
|
-
#{
|
75
|
+
window['#{@name}'] = function(htx) {
|
76
|
+
#{@compiled}
|
49
77
|
}
|
50
78
|
EOS
|
51
79
|
end
|
52
80
|
|
81
|
+
private
|
82
|
+
|
53
83
|
##
|
54
|
-
# Processes a DOM node.
|
84
|
+
# Processes a DOM node's descendents.
|
55
85
|
#
|
56
|
-
def
|
86
|
+
def process(base)
|
57
87
|
base.children.each do |node|
|
58
|
-
next
|
88
|
+
next unless node.element? || node.text?
|
59
89
|
|
60
90
|
dynamic_key = process_value(node.attr(DYNAMIC_KEY_ATTR), :attr)
|
61
91
|
|
@@ -63,17 +93,17 @@ class HTX
|
|
63
93
|
text = (node.text? ? node : node.children).text
|
64
94
|
|
65
95
|
if (value = process_value(text))
|
66
|
-
append(
|
96
|
+
append(
|
67
97
|
"#{indent(text[LEADING_WHITESPACE])}"\
|
68
98
|
"htx.node(#{[
|
69
99
|
value,
|
70
100
|
dynamic_key,
|
71
|
-
((
|
101
|
+
((@static_key += 1) << FLAG_BITS) | TEXT_NODE,
|
72
102
|
].compact.join(', ')})"\
|
73
103
|
"#{indent(text[TRAILING_WHITESPACE])}"
|
74
104
|
)
|
75
105
|
else
|
76
|
-
append(
|
106
|
+
append(indent(text))
|
77
107
|
end
|
78
108
|
else
|
79
109
|
attrs = node.attributes.inject([]) do |attrs, (_, attr)|
|
@@ -83,50 +113,50 @@ class HTX
|
|
83
113
|
attrs << process_value(attr.value, :attr)
|
84
114
|
end
|
85
115
|
|
86
|
-
append(
|
116
|
+
append("htx.node(#{[
|
87
117
|
"'#{TAG_MAP[node.name] || node.name}'",
|
88
118
|
attrs,
|
89
119
|
dynamic_key,
|
90
|
-
((
|
120
|
+
((@static_key += 1) << FLAG_BITS) | (node.children.empty? ? CHILDLESS : 0),
|
91
121
|
].compact.flatten.join(', ')})")
|
92
122
|
|
93
123
|
unless node.children.empty?
|
94
|
-
process(node
|
124
|
+
process(node)
|
95
125
|
|
96
126
|
count = ''
|
97
|
-
|
127
|
+
@compiled.sub!(CLOSE_STATEMENT) do
|
98
128
|
count = $1 == '' ? 2 : $1.to_i + 1
|
99
129
|
$2
|
100
130
|
end
|
101
131
|
|
102
|
-
append(
|
132
|
+
append("htx.close(#{count})")
|
103
133
|
end
|
104
134
|
end
|
105
135
|
end
|
106
136
|
end
|
107
137
|
|
108
138
|
##
|
109
|
-
# Appends a string to the compiled template function string with appropriate punctuation and/or
|
110
|
-
#
|
139
|
+
# Appends a string to the compiled template function string with appropriate punctuation and/or whitespace
|
140
|
+
# inserted.
|
111
141
|
#
|
112
|
-
def
|
113
|
-
if
|
142
|
+
def append(text)
|
143
|
+
if @compiled == ''
|
114
144
|
# Do nothing.
|
115
|
-
elsif
|
116
|
-
|
117
|
-
elsif
|
118
|
-
|
119
|
-
elsif
|
120
|
-
|
145
|
+
elsif @compiled !~ END_STATEMENT_END && text !~ BEGIN_STATEMENT_END
|
146
|
+
@compiled << '; '
|
147
|
+
elsif @compiled !~ END_WHITESPACE && text !~ BEGIN_WHITESPACE
|
148
|
+
@compiled << ' '
|
149
|
+
elsif @compiled[-1] == "\n"
|
150
|
+
@compiled << ' '
|
121
151
|
end
|
122
152
|
|
123
|
-
|
153
|
+
@compiled << text
|
124
154
|
end
|
125
155
|
|
126
156
|
##
|
127
157
|
# Indents each line of a string (except the first).
|
128
158
|
#
|
129
|
-
def
|
159
|
+
def indent(text)
|
130
160
|
return '' unless text
|
131
161
|
|
132
162
|
text.gsub!(NEWLINE_NON_BLANK, "\n ")
|
@@ -137,7 +167,7 @@ class HTX
|
|
137
167
|
# Processes, formats, and encodes an attribute or text node value. Returns nil if the value is determined
|
138
168
|
# to be a control statement.
|
139
169
|
#
|
140
|
-
def
|
170
|
+
def process_value(text, is_attr = false)
|
141
171
|
return nil if text.nil? || (!is_attr && text.strip == '')
|
142
172
|
|
143
173
|
if (value = text[RAW_VALUE, 1])
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: htx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Pickens
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|