renshi 0.2.8 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +11 -39
- data/lib/renshi/parser.rb +17 -33
- data/lib/renshi.rb +1 -1
- data/spec/each_spec.rb +1 -1
- data/spec/parser_spec.rb +100 -133
- metadata +2 -3
- data/lib/renshi/frameworks/generic.rb +0 -7
data/README
CHANGED
@@ -1,38 +1,20 @@
|
|
1
|
-
Renshi
|
1
|
+
This is the final version of Renshi. I'm now working on my idea of an ideal templating language at http://github.com/biv/cranberry .
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
index.html.ren means you're working with a Renshi file!
|
3
|
+
Renshi is a templating language for Ruby which is versatile and cooperative with HTML. It has a concise syntax and 'attribute expressions', which let you build and combine sets of inline Ruby instructions upon HTML elements.
|
6
4
|
|
5
|
+
Renshi integrates with Rails and Sinatra transparently. Simply 'require renshi'. In Sinatra use 'ren' where you would have used the 'erb'/'haml' methods. Renshi templates are appended with the suffix of .ren, e.g. index.html.ren or index.ren.
|
7
6
|
|
8
7
|
$ Ruby Interpretation
|
9
8
|
=====================
|
10
|
-
|
11
|
-
|
12
|
-
$ interprets everything after it as ruby which will be to_stringed until the next $, a newline character, or the end of the element. Leave a $ with a space after it to switch back into writing regular HTML.
|
13
|
-
|
14
|
-
e.g. you can do this
|
15
|
-
|
16
|
-
$stylesheet_link_tag "atsida"
|
17
|
-
|
18
|
-
e.g. or this
|
19
|
-
<p>$foo $translator("welcome human") $Time.now</p>
|
20
|
-
|
21
|
-
e.g. or this (contrived) example
|
9
|
+
Like ERB, but less typing.
|
22
10
|
|
23
|
-
|
11
|
+
Use $ or ${..} where you would use <%= ... %> . The single $ is used for an unbroken phrase (see below).
|
24
12
|
|
25
|
-
$
|
13
|
+
$foo[0], $1+1, $Time.now - ERB equiv. <%= foo[0] %>, <%= 1+1 %>, <%= Time.now %>
|
26
14
|
|
27
|
-
|
28
|
-
<p>this is normal HTML but ${some_function "takes this string as input or uses a \n or /foo$/ regex"} and now this is normal HTML</p>
|
15
|
+
${some_function "takes this string as input"} (ERB equiv. - <%= some_function "takes this string as input" %>)
|
29
16
|
|
30
|
-
|
31
|
-
e.g.
|
32
|
-
<p>It has been $^current_user.days_absent since we last saw you.</p>
|
33
|
-
|
34
|
-
|
35
|
-
$[] allows ruby src code to be embedded. It's a bad practice (use helpers or something) but we let you do it.
|
17
|
+
Use $[] instead of <% ... -%>
|
36
18
|
|
37
19
|
$[if foo]
|
38
20
|
$foo
|
@@ -40,14 +22,14 @@ $[end]
|
|
40
22
|
|
41
23
|
Attribute Expressions
|
42
24
|
=====================
|
43
|
-
|
25
|
+
Attr. expressions are insertable into HTML elements as attributes.
|
44
26
|
|
45
27
|
<p r:if="user.known?">Welcome $user.name</p>
|
46
28
|
|
47
29
|
They can be combined on elements and are interpreted in the order of appearance and are cumulative, allowing you to program inline on the HTML structure.
|
48
30
|
|
49
31
|
<li r:each="@sphinx.results[:words], |k,v|" r:if="v[:hits].to_i > 0">
|
50
|
-
|
32
|
+
$k - Hits $v[:hits] in $v[:docs] documents
|
51
33
|
</li>
|
52
34
|
|
53
35
|
In the above, you can see that the if statement is scoped within the preceding each block, so you can reference variables between attr. expressions. Variables within an attr. expression don't need the $ symbol. That's only for setting up Ruby insertions within regular HTML.
|
@@ -166,17 +148,7 @@ To print a $ use $$, e.g. $$10.95 comes out as $10.95
|
|
166
148
|
|
167
149
|
Because the $foo evaluation can take all sorts of symbols to interpret a Ruby statement, if you are using a special symbol *immediately* before it, you'll have to use ${foo} instead. For example, because $greetings[0].upcase is interpretable, if you want to output "[HELLO]" where the brackets surround the string, you'd use [${greetings[0].upcase}]
|
168
150
|
|
169
|
-
The
|
170
|
-
|
171
|
-
To output xml elements in a string use the escaped versions - e.g.for
|
172
|
-
|
173
|
-
(incorrect)
|
174
|
-
${@page.section.root? ? "<li>Home</li>" : render_breadcrumbs(:from_top => 1)}
|
175
|
-
|
176
|
-
use, instead,
|
177
|
-
|
178
|
-
(correct)
|
179
|
-
${@page.section.root? ? "<li>Home</li>" : render_breadcrumbs(:from_top => 1)}
|
151
|
+
The $ parser *delimits* (splits) on any character which is not in this list - . " ' { } ( ) + = * / \ - @ [ ] : ? ! % \w
|
180
152
|
|
181
153
|
Installation
|
182
154
|
============
|
data/lib/renshi/parser.rb
CHANGED
@@ -105,8 +105,10 @@ module Renshi
|
|
105
105
|
|
106
106
|
while idx != nil do
|
107
107
|
next_char = text[(idx + 1)..(idx + 1)]
|
108
|
-
|
109
|
-
if next_char == "
|
108
|
+
|
109
|
+
if next_char == " "
|
110
|
+
raise SyntaxError, "Floating $ - use $$ to output '$': #{text[(idx +1)..-1]}", caller
|
111
|
+
elsif next_char == "("
|
110
112
|
#this may be jquery, etc. $(...)
|
111
113
|
end_statement_idx = (idx + 2)
|
112
114
|
bits << text[idx..(idx + 1)]
|
@@ -114,6 +116,7 @@ module Renshi
|
|
114
116
|
#an escaped $ - i.e. '$$'
|
115
117
|
end_statement_idx = (idx + 2)
|
116
118
|
bits << "$"
|
119
|
+
|
117
120
|
#${...}
|
118
121
|
elsif next_char == "{"
|
119
122
|
begin
|
@@ -125,7 +128,8 @@ module Renshi
|
|
125
128
|
end_statement_idx = closing_brace_idx + 1
|
126
129
|
rescue StandardError
|
127
130
|
raise SyntaxError, "No closing brace: #{text}", caller
|
128
|
-
end
|
131
|
+
end
|
132
|
+
|
129
133
|
#$[...]
|
130
134
|
elsif next_char == "["
|
131
135
|
begin
|
@@ -137,36 +141,16 @@ module Renshi
|
|
137
141
|
end_statement_idx = closing_brace_idx + 1
|
138
142
|
rescue StandardError
|
139
143
|
raise SyntaxError, "No closing bracket: #{text}", caller
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end_statement_idx = (idx + 2)
|
151
|
-
bits << "\s"
|
152
|
-
else #$foo
|
153
|
-
#divide with a delimiter on \n or $ or assume ruby until the end of element
|
154
|
-
words = text[(idx +1)..-1].split(/[\n$]/)
|
155
|
-
words[0] = "'$'" if words[0] == "$"
|
156
|
-
|
157
|
-
#now respect whitespace trailing the word - e.g. $foo $bar should not render as "helloworld"
|
158
|
-
if words.first.index(/\s/)
|
159
|
-
before_whitespace = words.first.rindex(/[^\s]/)
|
160
|
-
src = words.first[0..(before_whitespace)]
|
161
|
-
else
|
162
|
-
src = words.first
|
163
|
-
end
|
164
|
-
|
165
|
-
statement_str = src
|
166
|
-
statement = Statement.new(statement_str)
|
167
|
-
bits << statement.compile_to_print!
|
168
|
-
end_statement_idx = (src.length) + 1 + idx
|
169
|
-
end
|
144
|
+
end
|
145
|
+
else #$foo
|
146
|
+
#divide with a delimiter for anything which is not a name character - alpa-numeric and underscore
|
147
|
+
words = text[(idx +1)..-1].split(/[^\w."'{}()+=*\/\-@\[\]:?!%]/)
|
148
|
+
words[0] = "'$'" if words[0] == "$"
|
149
|
+
statement_str = words.first
|
150
|
+
statement = Statement.new(statement_str)
|
151
|
+
bits << statement.compile_to_print!
|
152
|
+
end_statement_idx = (words.first.length) + 1 + idx
|
153
|
+
end
|
170
154
|
|
171
155
|
next_statement_idx = text.index("$", end_statement_idx)
|
172
156
|
|
data/lib/renshi.rb
CHANGED
data/spec/each_spec.rb
CHANGED
data/spec/parser_spec.rb
CHANGED
@@ -86,7 +86,7 @@ describe Renshi::Parser do
|
|
86
86
|
it "should interpret all Renshi instructions and remove them from the document" do
|
87
87
|
raw = compile_file("data/example1.ren")
|
88
88
|
html = eval(raw, binding)
|
89
|
-
|
89
|
+
|
90
90
|
html.should_not =~/R_INSTR_IDX_START/
|
91
91
|
html.should_not =~/R_INSTR_IDX_END/
|
92
92
|
html.should_not =~/@output_buffer.concat/
|
@@ -101,8 +101,8 @@ describe Renshi::Parser do
|
|
101
101
|
html.should =~/head/
|
102
102
|
end
|
103
103
|
|
104
|
-
it "should interpret single
|
105
|
-
raw = Renshi::Parser.parse("
|
104
|
+
it "should interpret single $foos using \W, i.e. $foo$bar should render" do
|
105
|
+
raw = Renshi::Parser.parse("$foo$bar")
|
106
106
|
foo = "hello"
|
107
107
|
bar = " world"
|
108
108
|
|
@@ -110,14 +110,6 @@ describe Renshi::Parser do
|
|
110
110
|
|
111
111
|
html.should eql "hello world"
|
112
112
|
end
|
113
|
-
|
114
|
-
it "should interpret $a$b$c" do
|
115
|
-
a = 'a'; b = 'b'; c = 'c';
|
116
|
-
raw = Renshi::Parser.parse("$a$b$c")
|
117
|
-
html = eval(raw, binding)
|
118
|
-
|
119
|
-
html.should eql "abc"
|
120
|
-
end
|
121
113
|
|
122
114
|
class Test
|
123
115
|
def bar
|
@@ -126,131 +118,106 @@ class Test
|
|
126
118
|
end
|
127
119
|
|
128
120
|
it "should interpret single $foo.bar " do
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
it "should interpret single $1+1 and $2*2 and $3/3 and $4-4 " do
|
137
|
-
raw = Renshi::Parser.parse("$1+1")
|
138
|
-
foo = Test.new
|
139
|
-
html = eval(raw, binding)
|
140
|
-
html.should eql "2"
|
141
|
-
|
142
|
-
raw = Renshi::Parser.parse("$2*2")
|
143
|
-
foo = Test.new
|
144
|
-
html = eval(raw, binding)
|
145
|
-
html.should eql "4"
|
121
|
+
raw = Renshi::Parser.parse("$foo.bar")
|
122
|
+
foo = Test.new
|
123
|
+
html = eval(raw, binding)
|
124
|
+
|
125
|
+
html.should eql "hello world"
|
126
|
+
end
|
146
127
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
128
|
+
it "should interpret single $1+1 and $2*2 and $3/3 and $4-4 " do
|
129
|
+
raw = Renshi::Parser.parse("$1+1")
|
130
|
+
foo = Test.new
|
131
|
+
html = eval(raw, binding)
|
132
|
+
html.should eql "2"
|
133
|
+
|
134
|
+
raw = Renshi::Parser.parse("$2*2")
|
135
|
+
foo = Test.new
|
136
|
+
html = eval(raw, binding)
|
137
|
+
html.should eql "4"
|
138
|
+
|
139
|
+
raw = Renshi::Parser.parse("$3/3")
|
140
|
+
foo = Test.new
|
141
|
+
html = eval(raw, binding)
|
142
|
+
html.should eql "1"
|
143
|
+
|
144
|
+
raw = Renshi::Parser.parse("$4-4")
|
145
|
+
foo = Test.new
|
146
|
+
html = eval(raw, binding)
|
147
|
+
html.should eql "0"
|
148
|
+
end
|
151
149
|
|
152
|
-
raw = Renshi::Parser.parse("$4-4")
|
153
|
-
foo = Test.new
|
154
|
-
html = eval(raw, binding)
|
155
|
-
html.should eql "0"
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
it "should interpret $foo[0] " do
|
160
|
-
raw = Renshi::Parser.parse("$foo[0]")
|
161
|
-
foo = ["hello world"]
|
162
|
-
html = eval(raw, binding)
|
163
|
-
|
164
|
-
html.should eql "hello world"
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
it "should interpret \"${@foo}\" " do
|
169
|
-
raw = Renshi::Parser.parse(%Q!"${@foo}"!)
|
170
|
-
puts raw
|
171
|
-
@foo = "hello world"
|
172
|
-
html = eval(raw, binding)
|
173
|
-
|
174
|
-
html.should eql %Q!"hello world"!
|
175
|
-
end
|
176
150
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
it "should interpret <a href='{$r.path}'>hello</a>" do
|
186
|
-
r = R.new
|
187
|
-
raw = Renshi::Parser.parse(%Q!<a href="${r.path}">hello</a>!)
|
188
|
-
html = eval(raw, binding)
|
189
|
-
|
190
|
-
html.should eql "<a href=\"#{r.path}\">hello</a>"
|
191
|
-
end
|
192
|
-
|
193
|
-
it "should interpret $foo.nil?" do
|
194
|
-
foo = nil
|
195
|
-
raw = Renshi::Parser.parse("$foo.nil?")
|
196
|
-
html = eval(raw, binding)
|
197
|
-
|
198
|
-
html.should eql true.to_s
|
199
|
-
end
|
200
|
-
|
201
|
-
it "should interpret $@foo.nil?" do
|
202
|
-
@foo = nil
|
203
|
-
raw = Renshi::Parser.parse("$@foo.nil?")
|
204
|
-
html = eval(raw, binding)
|
205
|
-
|
206
|
-
html.should eql true.to_s
|
207
|
-
end
|
208
|
-
|
209
|
-
|
210
|
-
it "should interpret $'foo'.upcase!" do
|
211
|
-
raw = Renshi::Parser.parse("$'foo'.upcase!")
|
212
|
-
html = eval(raw, binding)
|
213
|
-
|
214
|
-
html.should eql "FOO"
|
215
|
-
end
|
216
|
-
|
217
|
-
it "should interpret $Time.now.strftime('%I:%M')" do
|
218
|
-
raw = Renshi::Parser.parse("$Time.now.strftime('%I:%M')")
|
219
|
-
html = eval(raw, binding)
|
220
|
-
|
221
|
-
html.should =~ /:/
|
222
|
-
end
|
223
|
-
|
224
|
-
it "should evaluate ternary statements in the curly braces" do
|
225
|
-
foo = nil
|
226
|
-
raw = Renshi::Parser.parse("${foo.nil? ? '>li<hello>/li<' : '>li<goodbye>/li<'}")
|
227
|
-
html = eval(raw, binding)
|
228
|
-
html.should =~ /hello/
|
229
|
-
foo = ""
|
230
|
-
html = eval(raw, binding)
|
231
|
-
html.should =~ /goodbye/
|
232
|
-
end
|
233
|
-
|
234
|
-
it "should interpret $foo until \n or end of element as ruby to string" do
|
235
|
-
raw = Renshi::Parser.parse("$'this should output as a string'")
|
236
|
-
html = eval(raw, binding)
|
237
|
-
|
238
|
-
html.should =~ /this should output as a string/
|
239
|
-
end
|
151
|
+
it "should interpret $foo[0] " do
|
152
|
+
raw = Renshi::Parser.parse("$foo[0]")
|
153
|
+
foo = ["hello world"]
|
154
|
+
html = eval(raw, binding)
|
155
|
+
|
156
|
+
html.should eql "hello world"
|
157
|
+
end
|
158
|
+
|
240
159
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
160
|
+
it "should interpret \"${@foo}\" " do
|
161
|
+
raw = Renshi::Parser.parse(%Q!"${@foo}"!)
|
162
|
+
puts raw
|
163
|
+
@foo = "hello world"
|
164
|
+
html = eval(raw, binding)
|
165
|
+
|
166
|
+
html.should eql %Q!"hello world"!
|
167
|
+
end
|
168
|
+
|
169
|
+
class R
|
170
|
+
attr_accessor :path
|
171
|
+
|
172
|
+
def initialize
|
173
|
+
@path = "/hello/world"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should interpret <a href='{$r.path}'>hello</a>" do
|
178
|
+
r = R.new
|
179
|
+
raw = Renshi::Parser.parse(%Q!<a href="${r.path}">hello</a>!)
|
180
|
+
html = eval(raw, binding)
|
181
|
+
|
182
|
+
html.should eql "<a href=\"#{r.path}\">hello</a>"
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should interpret $foo.nil?" do
|
186
|
+
foo = nil
|
187
|
+
raw = Renshi::Parser.parse("$foo.nil?")
|
188
|
+
html = eval(raw, binding)
|
189
|
+
|
190
|
+
html.should eql true.to_s
|
191
|
+
end
|
248
192
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
193
|
+
it "should interpret $@foo.nil?" do
|
194
|
+
@foo = nil
|
195
|
+
raw = Renshi::Parser.parse("$@foo.nil?")
|
196
|
+
html = eval(raw, binding)
|
197
|
+
|
198
|
+
html.should eql true.to_s
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should interpret $a$b$c" do
|
202
|
+
a = 'a'; b = 'b'; c = 'c';
|
203
|
+
raw = Renshi::Parser.parse("$a$b$c")
|
204
|
+
html = eval(raw, binding)
|
205
|
+
|
206
|
+
html.should eql "abc"
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should interpret $'foo'.upcase!" do
|
210
|
+
raw = Renshi::Parser.parse("$'foo'.upcase!")
|
211
|
+
html = eval(raw, binding)
|
212
|
+
|
213
|
+
html.should eql "FOO"
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should interpret $Time.now.strftime('%I:%M')" do
|
217
|
+
raw = Renshi::Parser.parse("$Time.now.strftime('%I:%M')")
|
218
|
+
html = eval(raw, binding)
|
219
|
+
|
220
|
+
html.should =~ /:/
|
221
|
+
end
|
222
|
+
|
256
223
|
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicholas Faiz
|
@@ -9,7 +9,7 @@ autorequire: renshi
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-13 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -39,7 +39,6 @@ files:
|
|
39
39
|
- lib/renshi/attribute_expressions/unless.rb
|
40
40
|
- lib/renshi/attribute_expressions/while.rb
|
41
41
|
- lib/renshi/attribute_expressions.rb
|
42
|
-
- lib/renshi/frameworks/generic.rb
|
43
42
|
- lib/renshi/frameworks/rails.rb
|
44
43
|
- lib/renshi/frameworks/sinatra.rb
|
45
44
|
- lib/renshi/frameworks.rb
|