renshi 0.0.4 → 0.0.5
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.
- data/README +36 -19
- data/lib/renshi/attribute_expressions/each.rb +11 -0
- data/lib/renshi/attribute_expressions/else.rb +1 -1
- data/lib/renshi/attribute_expressions/elsif.rb +1 -3
- data/lib/renshi/attribute_expressions/for.rb +1 -1
- data/lib/renshi/attribute_expressions/if.rb +1 -3
- data/lib/renshi/attribute_expressions/unless.rb +24 -0
- data/lib/renshi/attribute_expressions/while.rb +2 -6
- data/lib/renshi/attribute_expressions.rb +20 -1
- data/lib/renshi/parser.rb +6 -19
- data/lib/renshi.rb +1 -1
- data/spec/data/if_2.ren +10 -0
- data/spec/each_spec.rb +14 -0
- data/spec/unless_spec.rb +11 -0
- data/spec/xml_entities_in_expressions_spec.rb +14 -0
- metadata +6 -2
data/README
CHANGED
@@ -20,23 +20,33 @@ $foo
|
|
20
20
|
Attribute Expressions
|
21
21
|
===================
|
22
22
|
Renshi has a small library of expressions which can be inserted into HTML or XML elements as attributes.
|
23
|
-
Attribute expressions follow the form of
|
23
|
+
Attribute expressions generally follow the form of
|
24
24
|
|
25
25
|
r:expression_name="expression" - the expression value is treated as a Ruby expression .
|
26
26
|
|
27
|
+
Some expressions, such as r:each, use the quoted value to also hold parameter information.
|
28
|
+
|
27
29
|
* Current Attribute Expressions
|
28
|
-
* If
|
29
|
-
*
|
30
|
+
* If
|
31
|
+
* Unless
|
32
|
+
* Elsif
|
30
33
|
* Else
|
31
34
|
* While
|
32
35
|
* For
|
33
|
-
|
36
|
+
* Each
|
34
37
|
|
35
38
|
* If
|
36
|
-
<span r:if="true">hello
|
39
|
+
<span r:if="true">hello</span>
|
40
|
+
would render "<span>hello</span>"
|
37
41
|
|
38
42
|
<span r:if="false">goodbye!</span> will render "".
|
39
43
|
|
44
|
+
* Unless
|
45
|
+
<span r:unless="false">hello</span>
|
46
|
+
would render "<span>hello</span>"
|
47
|
+
|
48
|
+
<span r:unless="true">goodbye!</span> will render "".
|
49
|
+
|
40
50
|
* Elsif
|
41
51
|
|
42
52
|
<span r:if="false">hello!</span>
|
@@ -109,22 +119,32 @@ renders:
|
|
109
119
|
|
110
120
|
<div id="content0">
|
111
121
|
hello0
|
112
|
-
</div
|
113
|
-
|
114
|
-
|
115
|
-
|
122
|
+
</div>
|
123
|
+
...etc
|
124
|
+
<div id="content99">
|
125
|
+
hello99
|
126
|
+
</div>
|
127
|
+
|
128
|
+
* Each
|
129
|
+
<div id="content$foo" r:each="foos, |foo|">
|
130
|
+
hello$foo
|
116
131
|
</div>
|
117
132
|
|
133
|
+
<div id="content0">
|
134
|
+
hello0
|
135
|
+
</div>
|
136
|
+
...etc
|
137
|
+
<div id="content99">
|
138
|
+
hello99
|
139
|
+
</div>
|
140
|
+
|
141
|
+
|
118
142
|
Further elements will appear as I have time to make them or others want to contribute them. There isn't much to making them.
|
119
143
|
|
120
144
|
See renshi/lib/renshi/attribute_expressions for how they work.
|
121
145
|
|
122
146
|
Planned element expressions:
|
123
147
|
|
124
|
-
* r:each
|
125
|
-
* r:unless
|
126
|
-
* r:def - something like genshi's py:def
|
127
|
-
|
128
148
|
Other Rules
|
129
149
|
===========
|
130
150
|
$ values inside of attributes are only interpreted as Renshi variables for regular attributes (not renshi attributes).
|
@@ -152,12 +172,9 @@ There is a Rails 2.3.2 example app in the examples directory. Go there, start up
|
|
152
172
|
I'd welcome integrations for Sinatra and Merb or XYZ framework. See renshi/lib/renshi/frameworks
|
153
173
|
|
154
174
|
|
155
|
-
|
175
|
+
Installation
|
156
176
|
============
|
157
|
-
|
158
|
-
`rake gem`
|
159
|
-
then
|
160
|
-
`sudo gem install pkg/renshi-0.0.2.gem`
|
177
|
+
Renshi is hosted on Rubyforge so 'sudo gem install renshi'. Alternatively, use github to do what you want with it.
|
161
178
|
|
162
179
|
|
163
180
|
Development
|
@@ -173,7 +190,7 @@ Firstly, it doesn't need a reason. It's a fun project.
|
|
173
190
|
But ...
|
174
191
|
|
175
192
|
I've always found ERB to be a bit cumbersome - <%= is quite tiring to type out when you realise it could be much shorter. I used to think that Velocity, in Java,
|
176
|
-
was the
|
193
|
+
was the funnest templating language I'd used, and I had wanted something equally as concise for Ruby.
|
177
194
|
|
178
195
|
A real need for it emerged in a project which relied upon an external design house handing us HTML. Converting it incessantly into HAML was nightmarish. A colleague
|
179
196
|
mentioned Genshi in Python as ideal, which was when the idea of Renshi was conceived.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Renshi
|
2
2
|
module AttributeExpressions
|
3
|
-
class Elsif
|
3
|
+
class Elsif
|
4
4
|
def evaluate(expression, node)
|
5
5
|
node.open_clause("elsif (#{expression})")
|
6
6
|
|
@@ -12,14 +12,12 @@ module Renshi
|
|
12
12
|
if sibling_commands.first
|
13
13
|
expression = sibling_commands.first[0][2..-1]
|
14
14
|
if expression == "else"
|
15
|
-
node.remove_attribute("r:elsif")
|
16
15
|
return
|
17
16
|
end
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
20
|
node.close_clause("end")
|
22
|
-
node.remove_attribute("r:elsif")
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Renshi
|
2
2
|
module AttributeExpressions
|
3
|
-
class If
|
3
|
+
class If
|
4
4
|
def evaluate(expression, node)
|
5
5
|
node.open_clause("if (#{expression})")
|
6
6
|
|
@@ -12,14 +12,12 @@ module Renshi
|
|
12
12
|
if sibling_commands.first
|
13
13
|
expression = sibling_commands.first[0][2..-1]
|
14
14
|
if expression == "else" or expression == "elsif"
|
15
|
-
node.remove_attribute("r:if")
|
16
15
|
return
|
17
16
|
end
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
20
|
node.close_clause("end")
|
22
|
-
node.remove_attribute("r:if")
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Renshi
|
2
|
+
module AttributeExpressions
|
3
|
+
class Unless
|
4
|
+
def evaluate(expression, node)
|
5
|
+
node.open_clause("unless (#{expression})")
|
6
|
+
|
7
|
+
sibling = node.next_real
|
8
|
+
|
9
|
+
if sibling
|
10
|
+
sibling_commands = sibling.commands
|
11
|
+
|
12
|
+
if sibling_commands.first
|
13
|
+
expression = sibling_commands.first[0][2..-1]
|
14
|
+
if expression == "else" or expression == "elsif"
|
15
|
+
return
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
node.close_clause("end")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,13 +1,9 @@
|
|
1
1
|
module Renshi
|
2
2
|
module AttributeExpressions
|
3
|
-
class While
|
4
|
-
|
5
|
-
|
6
|
-
def evaluate(expression, node)
|
7
|
-
expression = encode_xml_entities(expression)
|
3
|
+
class While
|
4
|
+
def evaluate(expression, node)
|
8
5
|
node.open_clause("while (#{expression})")
|
9
6
|
node.close_clause("end")
|
10
|
-
node.remove_attribute("r:while")
|
11
7
|
end
|
12
8
|
end
|
13
9
|
end
|
@@ -3,11 +3,30 @@ require 'renshi/attribute_expressions/elsif'
|
|
3
3
|
require 'renshi/attribute_expressions/else'
|
4
4
|
require 'renshi/attribute_expressions/while'
|
5
5
|
require 'renshi/attribute_expressions/for'
|
6
|
+
require 'renshi/attribute_expressions/unless'
|
7
|
+
require 'renshi/attribute_expressions/each'
|
6
8
|
|
7
9
|
module Renshi
|
8
10
|
module AttributeExpressions
|
9
11
|
|
10
|
-
def
|
12
|
+
def self.perform_expression(node, command)
|
13
|
+
expression = command[0][2..-1]
|
14
|
+
|
15
|
+
obj = nil
|
16
|
+
begin
|
17
|
+
obj = eval "Renshi::AttributeExpressions::#{expression.capitalize}.new"
|
18
|
+
rescue StandardError
|
19
|
+
raise Renshi::SyntaxError, "Could not find attribute expression called #{expression}.rb", caller
|
20
|
+
end
|
21
|
+
|
22
|
+
expression = encode_xml_entities(command[1].to_s)
|
23
|
+
obj.evaluate(expression, node)
|
24
|
+
|
25
|
+
#removes attribute after it's performed so it doesn't appear in end document
|
26
|
+
node.remove_attribute(command[0])
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.encode_xml_entities(expression)
|
11
30
|
expression.gsub!("<", Renshi::Parser::XML_LT)
|
12
31
|
expression.gsub!(">", Renshi::Parser::XML_GT)
|
13
32
|
expression.gsub!("&", Renshi::Parser::XML_AMP)
|
data/lib/renshi/parser.rb
CHANGED
@@ -5,17 +5,17 @@ module Renshi
|
|
5
5
|
# the document, which are finally compiled into Ruby.
|
6
6
|
|
7
7
|
class Parser
|
8
|
-
STRING_END = "R_END" #maybe replace this with a funky unicode char
|
9
|
-
STRING_START = "R_START" #maybe replace this with a funky unicode char
|
8
|
+
STRING_END = "^R_END^" #maybe replace this with a funky unicode char
|
9
|
+
STRING_START = "^R_START^" #maybe replace this with a funky unicode char
|
10
10
|
BUFFER_CONCAT_OPEN = "@output_buffer.concat(\""
|
11
11
|
BUFFER_CONCAT_CLOSE = "\");"
|
12
12
|
NEW_LINE = "@output_buffer.concat('\n');"
|
13
13
|
|
14
14
|
#these symbols cannot be normally escaped, as we need to differentiate between < as an
|
15
15
|
#escaped string, to be left in the document, and < as a boolean operator
|
16
|
-
XML_LT = "R_LT"
|
17
|
-
XML_GT = "R_GT"
|
18
|
-
XML_AMP = "R_AMP"
|
16
|
+
XML_LT = "^R_LT^"
|
17
|
+
XML_GT = "^R_GT^"
|
18
|
+
XML_AMP = "^R_AMP^"
|
19
19
|
|
20
20
|
def self.parse(xhtml)
|
21
21
|
doc = Nokogiri::HTML.fragment(xhtml)
|
@@ -34,7 +34,7 @@ module Renshi
|
|
34
34
|
if node.attributes
|
35
35
|
expressions = node.commands
|
36
36
|
for expression in expressions
|
37
|
-
perform_expression(node, expression)
|
37
|
+
AttributeExpressions.perform_expression(node, expression)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -56,19 +56,6 @@ module Renshi
|
|
56
56
|
|
57
57
|
node.children.each {|child| transform_node(child)}
|
58
58
|
end
|
59
|
-
|
60
|
-
def self.perform_expression(node, command)
|
61
|
-
expression = command[0][2..-1]
|
62
|
-
|
63
|
-
obj = nil
|
64
|
-
begin
|
65
|
-
obj = eval "Renshi::AttributeExpressions::#{expression.capitalize}.new"
|
66
|
-
rescue StandardError
|
67
|
-
raise Renshi::SyntaxError, "Could not find attribute expression called #{expression}.rb", caller
|
68
|
-
end
|
69
|
-
|
70
|
-
obj.evaluate(command[1].to_s, node)
|
71
|
-
end
|
72
59
|
|
73
60
|
def self.compile(text)
|
74
61
|
idx = text.index("$")
|
data/lib/renshi.rb
CHANGED
data/spec/data/if_2.ren
CHANGED
data/spec/each_spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
describe Renshi::Parser do
|
5
|
+
it "should evaluate r:unless(false)" do
|
6
|
+
foos = [0,1,2]
|
7
|
+
doc = Nokogiri::HTML("<span id='red$foo' r:each='foos, |foo|'/>hello$foo</span>")
|
8
|
+
compiled = Renshi::Parser.parse(doc.root.to_s)
|
9
|
+
out = eval(compiled, binding)
|
10
|
+
(doc/"span[@id='red0']").text.strip.should eql "hello0"
|
11
|
+
(doc/"span[@id='red1']").text.strip.should eql "hello1"
|
12
|
+
(doc/"span[@id='red2']").text.strip.should eql "hello2"
|
13
|
+
end
|
14
|
+
end
|
data/spec/unless_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
describe Renshi::Parser do
|
5
|
+
it "should evaluate r:unless(false)" do
|
6
|
+
doc = Nokogiri::HTML("<span id='red' r:unless='false'>hello</span>")
|
7
|
+
compiled = Renshi::Parser.parse(doc.root.to_s)
|
8
|
+
out = eval(compiled, binding)
|
9
|
+
(doc/"span[@id='red']").text.strip.should eql "hello"
|
10
|
+
end
|
11
|
+
end
|
@@ -10,4 +10,18 @@ describe Renshi::Parser do
|
|
10
10
|
(doc/"div[@id='content0']").text.strip.should =~ /hello0/
|
11
11
|
(doc/"div[@id='content1']").text.strip.should =~ /hello1/
|
12
12
|
end
|
13
|
+
|
14
|
+
it "should evaluate r:if(foo < 2)" do
|
15
|
+
doc = Nokogiri::HTML("<span r:if='1 < 2'>hello</div>")
|
16
|
+
body = doc.root.children.first
|
17
|
+
node = body.children.first
|
18
|
+
eval(deliver_compiled(node), binding).should eql "hello"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should evaluate r:elsif(foo < 2)" do
|
22
|
+
doc = Nokogiri::HTML("<span r:if='false'/><span r:elsif='1 < 2'>hello</div>")
|
23
|
+
compiled = deliver_compiled(doc.root)
|
24
|
+
puts compiled
|
25
|
+
eval(compiled, binding).should eql "hello"
|
26
|
+
end
|
13
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: renshi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas Faiz
|
@@ -33,10 +33,12 @@ extra_rdoc_files:
|
|
33
33
|
files:
|
34
34
|
- lib/renshi
|
35
35
|
- lib/renshi/attribute_expressions
|
36
|
+
- lib/renshi/attribute_expressions/each.rb
|
36
37
|
- lib/renshi/attribute_expressions/else.rb
|
37
38
|
- lib/renshi/attribute_expressions/elsif.rb
|
38
39
|
- lib/renshi/attribute_expressions/for.rb
|
39
40
|
- lib/renshi/attribute_expressions/if.rb
|
41
|
+
- lib/renshi/attribute_expressions/unless.rb
|
40
42
|
- lib/renshi/attribute_expressions/while.rb
|
41
43
|
- lib/renshi/attribute_expressions.rb
|
42
44
|
- lib/renshi/frameworks
|
@@ -72,7 +74,7 @@ rubyforge_project:
|
|
72
74
|
rubygems_version: 1.3.1
|
73
75
|
signing_key:
|
74
76
|
specification_version: 2
|
75
|
-
summary: Renshi is a lightweight XHTML template language, inspired by Python's Genshi and build on Nokogiri
|
77
|
+
summary: Renshi is a lightweight XHTML template language, inspired by Python's Genshi and build on Nokogiri.
|
76
78
|
test_files:
|
77
79
|
- spec/data
|
78
80
|
- spec/data/attribute_values_parsed.ren
|
@@ -86,6 +88,7 @@ test_files:
|
|
86
88
|
- spec/data/while.ren
|
87
89
|
- spec/data/while_lt.ren
|
88
90
|
- spec/data/white_space.ren
|
91
|
+
- spec/each_spec.rb
|
89
92
|
- spec/else_spec.rb
|
90
93
|
- spec/elsif_spec.rb
|
91
94
|
- spec/for_spec.rb
|
@@ -95,5 +98,6 @@ test_files:
|
|
95
98
|
- spec/renshi_spec.rb
|
96
99
|
- spec/spec.opts
|
97
100
|
- spec/spec_helper.rb
|
101
|
+
- spec/unless_spec.rb
|
98
102
|
- spec/while_spec.rb
|
99
103
|
- spec/xml_entities_in_expressions_spec.rb
|