htx 0.0.1 → 0.0.2
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 +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
|