ruhl 0.9.7 → 0.10.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.
- data/README +2 -387
- data/VERSION +1 -1
- data/lib/ruhl/engine.rb +115 -82
- data/ruhl.gemspec +4 -2
- data/spec/html/if_on_collection.html +23 -0
- data/spec/html/use_if.html +28 -0
- data/spec/ruhl_spec.rb +85 -26
- data/spec/spec_helper.rb +13 -13
- metadata +4 -2
data/README
CHANGED
@@ -2,392 +2,7 @@ RuHL (Ruby Hypertext Language)
|
|
2
2
|
|
3
3
|
**gem available on gemcutter: http://gemcutter.org/gems/ruhl
|
4
4
|
|
5
|
-
|
6
|
-
:: What? ::
|
7
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
5
|
+
Documentation has been moved to:
|
8
6
|
|
9
|
-
|
10
|
-
the contents dynamic!
|
11
|
-
|
12
|
-
Let's say you have the following HTML in a file called ('hello_world.ruhl')
|
13
|
-
|
14
|
-
<html>
|
15
|
-
<body>
|
16
|
-
<p data-ruhl="say_hello"/>
|
17
|
-
</body>
|
18
|
-
</html>
|
19
|
-
|
20
|
-
And you have the following method available to self:
|
21
|
-
|
22
|
-
def say_hello
|
23
|
-
"Hello World"
|
24
|
-
end
|
25
|
-
|
26
|
-
If you call
|
27
|
-
|
28
|
-
RuHL::Engine.new(File.read('hello_world.ruhl')).render(self)
|
29
|
-
|
30
|
-
It will return:
|
31
|
-
|
32
|
-
<html>
|
33
|
-
<body>
|
34
|
-
<p>Hello World</p>
|
35
|
-
</body>
|
36
|
-
</html>
|
37
|
-
|
38
|
-
Notice that it removes the data-ruhl attribute.
|
39
|
-
|
40
|
-
|
41
|
-
You can pass an options hash to RuHL:
|
42
|
-
RuHL::Engine.new(File.read('hello_world.ruhl'), options).render(self)
|
43
|
-
|
44
|
-
Right now, RuHL knows the following options:
|
45
|
-
|
46
|
-
:layout => This is the file name of the layout
|
47
|
-
|
48
|
-
:layout_source => If the framework (like Rails) has already read the file,
|
49
|
-
pass the contents through so RuHL doesn't have to reread
|
50
|
-
the file.
|
51
|
-
|
52
|
-
If you don't pass :layout_source, RuHL must be able to
|
53
|
-
find/read :layout
|
54
|
-
|
55
|
-
:local_object => If you are rendering a show page for @person, pass the
|
56
|
-
@person object into RuHL. RuHL will first try to call
|
57
|
-
the methods against the local_object then try the scope.
|
58
|
-
|
59
|
-
For example:
|
60
|
-
<li data-ruhl="first_name">
|
61
|
-
|
62
|
-
RuHL will first try @person.first_name.
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
There are some special methods defined by RuHL (examples follow):
|
67
|
-
|
68
|
-
_render_ - This is used in your layout and lets rule know where to inject
|
69
|
-
the rendered sub content.
|
70
|
-
|
71
|
-
_partial - Path to a partial file. RuHL must be able to find/read this file.
|
72
|
-
|
73
|
-
_if - If the method returns true, processing will continue.
|
74
|
-
If the method returns a value other than true, the inner_html
|
75
|
-
of the tag will be set to that value.
|
76
|
-
If the method returns false or nil, processing will halt and
|
77
|
-
the tag will not be included on output.
|
78
|
-
|
79
|
-
_unless - If the method returns true, processing will halt and the tag
|
80
|
-
will not included on output.
|
81
|
-
If the method returns false, processing will continue.
|
82
|
-
|
83
|
-
_collection - RuHL expects the method reference to return an array of objects.
|
84
|
-
RuHL will iteratate over the collection and render the contents
|
85
|
-
of the tag agains the collection item. (example below)
|
86
|
-
|
87
|
-
_use - The object returned is used within the scope of the tag.
|
88
|
-
|
89
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
90
|
-
:: Rails ::
|
91
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
92
|
-
|
93
|
-
In your config/environment.rb :
|
94
|
-
|
95
|
-
config.gem 'ruhl', :lib => 'ruhl/rails'
|
96
|
-
|
97
|
-
Your filenames should end in .ruhl ('show.html.ruhl')
|
98
|
-
|
99
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
100
|
-
:: Sinatra ::
|
101
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
102
|
-
|
103
|
-
require 'ruhl/sinatra'
|
104
|
-
|
105
|
-
You can then do:
|
106
|
-
|
107
|
-
get '/' do
|
108
|
-
ruhl(:index, :layout => path_to_layout)
|
109
|
-
end
|
110
|
-
|
111
|
-
*******************************************************************************
|
112
|
-
*
|
113
|
-
* EXAMPLES
|
114
|
-
*
|
115
|
-
*******************************************************************************
|
116
|
-
|
117
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
118
|
-
:: Replacing attribute values ::
|
119
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
120
|
-
|
121
|
-
<meta data-ruhl="content: meta_description" content='This is a description template'
|
122
|
-
id='metaDescription' name='description' />
|
123
|
-
|
124
|
-
content: meta_description is telling the parser to replace attribute 'content'
|
125
|
-
with results from meta_description method.
|
126
|
-
|
127
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
128
|
-
:: Don't use iterators in views ::
|
129
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
130
|
-
|
131
|
-
<table id="aab">
|
132
|
-
<tr data-ruhl="_collection: user_list">
|
133
|
-
<td data-ruhl="name">John Doe</td>
|
134
|
-
<td data-ruhl="email">john@doe.com</td>
|
135
|
-
</tr>
|
136
|
-
</table>
|
137
|
-
|
138
|
-
The above will call the :user_list method and iterate over the results. For each result it will duplicate the tag and it's contents. For the above example this means:
|
139
|
-
|
140
|
-
<tr data-ruhl="_collection: user_list">
|
141
|
-
<td data-ruhl="name">John Doe</td>
|
142
|
-
<td data-ruhl="email">john@doe.com</td>
|
143
|
-
</tr>
|
144
|
-
|
145
|
-
is duplicated for each user in user_list.
|
146
|
-
|
147
|
-
If user_list return an array of User objects like:
|
148
|
-
|
149
|
-
[ User.create(:name => 'Rupert Boy', :email => 'rupert@stonean.com'),
|
150
|
-
User.create(:name => 'Kaylee Girl', :email => 'kaylee@stonean.com'),
|
151
|
-
User.create(:name => 'Monty Man', :email => 'monty@stonean.com')]
|
152
|
-
|
153
|
-
<table id="aab">
|
154
|
-
<tr>
|
155
|
-
<td>Rupert Boy</td>
|
156
|
-
<td>rupert@stonean.com</td>
|
157
|
-
</tr>
|
158
|
-
<tr>
|
159
|
-
<td>Kaylee Girl</td>
|
160
|
-
<td>kaylee@stonean.com</td>
|
161
|
-
</tr>
|
162
|
-
<tr>
|
163
|
-
<td>Monty Man</td>
|
164
|
-
<td>monty@stonean.com</td>
|
165
|
-
</tr>
|
166
|
-
</table>
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
171
|
-
:: Using a Layout ::
|
172
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
173
|
-
|
174
|
-
Layout:
|
175
|
-
<html>
|
176
|
-
<head>
|
177
|
-
<title>This is a title template</title>
|
178
|
-
</head>
|
179
|
-
<body>
|
180
|
-
<div data-ruhl="_render_"></div>
|
181
|
-
</body>
|
182
|
-
</html>
|
183
|
-
|
184
|
-
Fragment:
|
185
|
-
<h1 data-ruhl="generate_h1">I am a templated headline</h1>
|
186
|
-
<p data-ruhl="my_content">Lorem ipsum dolor sit amet</p>
|
187
|
-
|
188
|
-
To use:
|
189
|
-
|
190
|
-
RuHL::Engine.new(File.read(fragment), :layout => path_to_layout).render(self)
|
191
|
-
|
192
|
-
Returns the expected result of parsed Layout w/ parsed Fragment.
|
193
|
-
|
194
|
-
Note the use of the _render_ method. This is a 'special' method that
|
195
|
-
RuHL uses to inject the results of the parsed fragment into the layout.
|
196
|
-
|
197
|
-
|
198
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
199
|
-
:: Using a Partial ::
|
200
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
201
|
-
|
202
|
-
Main:
|
203
|
-
<html>
|
204
|
-
<head>
|
205
|
-
<title>This is a title template</title>
|
206
|
-
</head>
|
207
|
-
<body>
|
208
|
-
<div id="wrap">
|
209
|
-
<div id="sidebar" data-ruhl="_partial: sidebar_partial">
|
210
|
-
<h3>Sidebar links</h3>
|
211
|
-
<ul>
|
212
|
-
<li><a href="#">Link 1</a></li>
|
213
|
-
<li><a href="#">Link 2</a></li>
|
214
|
-
<li><a href="#">Link 3</a></li>
|
215
|
-
<li><a href="#">Link 4</a></li>
|
216
|
-
</ul>
|
217
|
-
</div>
|
218
|
-
<div id="main">
|
219
|
-
<h1> My main content</h1>
|
220
|
-
<p>Text designers would put here to test their layout</p>
|
221
|
-
</div>
|
222
|
-
</div>
|
223
|
-
</body>
|
224
|
-
</html>
|
225
|
-
|
226
|
-
Sidebar:
|
227
|
-
<h3>Real Sidebarlinks</h3>
|
228
|
-
<ul>
|
229
|
-
<li><a href="#">Real Link 1</a></li>
|
230
|
-
<li><a href="#">Real Link 2</a></li>
|
231
|
-
<li><a href="#">Real Link 3</a></li>
|
232
|
-
<li><a href="#">Real Link 4</a></li>
|
233
|
-
</ul>
|
234
|
-
|
235
|
-
To use:
|
236
|
-
|
237
|
-
RuHL::Engine.new(File.read(path_to_main)).render(self)
|
238
|
-
|
239
|
-
Returns the expected result of parsed Main with sidebar div contents
|
240
|
-
replaced with parsed sidebar partial contents.
|
241
|
-
|
242
|
-
Note the use of the _partial key. This is a 'special' key that RuHL
|
243
|
-
uses to inject the results of the parsed partial into the contents
|
244
|
-
of the calling node.
|
245
|
-
|
246
|
-
|
247
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
248
|
-
:: Conditional display of block (_if)::
|
249
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
250
|
-
|
251
|
-
<html>
|
252
|
-
<head>
|
253
|
-
<title>This is a title template</title>
|
254
|
-
</head>
|
255
|
-
<body>
|
256
|
-
<h1>This is the header template</h1>
|
257
|
-
<div data-ruhl="_if: users?">
|
258
|
-
<table>
|
259
|
-
<thead>
|
260
|
-
<tr>
|
261
|
-
<td>First Name</td>
|
262
|
-
<td>Last Name</td>
|
263
|
-
<td>Email</td>
|
264
|
-
</tr>
|
265
|
-
</thead>
|
266
|
-
<tr data-ruhl="_collection: user_list">
|
267
|
-
<td data-ruhl="first_name">Andrew</td>
|
268
|
-
<td data-ruhl="last_name">Stone</td>
|
269
|
-
<td data-ruhl="email">andy@stonean.com</td>
|
270
|
-
</tr>
|
271
|
-
</table>
|
272
|
-
</div>
|
273
|
-
</ul>
|
274
|
-
</body>
|
275
|
-
</html>
|
276
|
-
|
277
|
-
if users? returns false then the div (including it's contents) are not shown
|
278
|
-
on output.
|
279
|
-
|
280
|
-
|
281
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
282
|
-
:: Conditional display of tag (_if)::
|
283
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
284
|
-
|
285
|
-
<html>
|
286
|
-
<head>
|
287
|
-
<title>This is a title template</title>
|
288
|
-
</head>
|
289
|
-
<body>
|
290
|
-
<h1>This is the header template</h1>
|
291
|
-
<table>
|
292
|
-
<thead>
|
293
|
-
<tr>
|
294
|
-
<td>First Name</td>
|
295
|
-
<td>Last Name</td>
|
296
|
-
<td>Email</td>
|
297
|
-
</tr>
|
298
|
-
</thead>
|
299
|
-
<tr data-ruhl="_collection: user_list">
|
300
|
-
<td data-ruhl="first_name">Andrew</td>
|
301
|
-
<td data-ruhl="last_name">Stone</td>
|
302
|
-
<td data-ruhl="_if: email">andy@stonean.com</td>
|
303
|
-
</tr>
|
304
|
-
</table>
|
305
|
-
</ul>
|
306
|
-
</body>
|
307
|
-
</html>
|
308
|
-
|
309
|
-
if email.nil? then the td is not shown.
|
310
|
-
|
311
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
312
|
-
:: Conditional display of tag (_unless)::
|
313
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
314
|
-
|
315
|
-
<html>
|
316
|
-
<head>
|
317
|
-
<title>This is a title template</title>
|
318
|
-
</head>
|
319
|
-
<body>
|
320
|
-
<h1>This is the header template</h1>
|
321
|
-
<table data-ruhl="_if: users?">
|
322
|
-
<thead>
|
323
|
-
<tr>
|
324
|
-
<td>First Name</td>
|
325
|
-
<td>Last Name</td>
|
326
|
-
<td>Email</td>
|
327
|
-
</tr>
|
328
|
-
</thead>
|
329
|
-
<tr data-ruhl="_collection: user_list">
|
330
|
-
<td data-ruhl="first_name">Andrew</td>
|
331
|
-
<td data-ruhl="last_name">Stone</td>
|
332
|
-
<td data-ruhl="_if: email">andy@stonean.com</td>
|
333
|
-
</tr>
|
334
|
-
</table>
|
335
|
-
<p data-ruhl="_unless: users?">No Users were found.</p>
|
336
|
-
</ul>
|
337
|
-
</body>
|
338
|
-
</html>
|
339
|
-
|
340
|
-
if users? == false then the "No Users were found" message appears.
|
341
|
-
|
342
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
343
|
-
:: Scope object to tag block (_use)::
|
344
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
345
|
-
|
346
|
-
<html>
|
347
|
-
<head>
|
348
|
-
<title>My Account</title>
|
349
|
-
</head>
|
350
|
-
<body>
|
351
|
-
<div data-ruhl="_use: current_user">
|
352
|
-
<h1> Editing <span data-ruhl="full_name"/></h1>
|
353
|
-
<table>
|
354
|
-
<thead>
|
355
|
-
<tr>
|
356
|
-
<td>First Name</td>
|
357
|
-
<td>Last Name</td>
|
358
|
-
<td>Email</td>
|
359
|
-
</tr>
|
360
|
-
</thead>
|
361
|
-
<tr>
|
362
|
-
<td data-ruhl="first_name">Andrew</td>
|
363
|
-
<td data-ruhl="last_name">Stone</td>
|
364
|
-
<td data-ruhl="_if: email">andy@stonean.com</td>
|
365
|
-
</tr>
|
366
|
-
</table>
|
367
|
-
</div>
|
368
|
-
</body>
|
369
|
-
</html>
|
370
|
-
|
371
|
-
The table row information will be replace with the current_user details.
|
372
|
-
|
373
|
-
*Note: _use can not be used with _partial as it replaces the inner_html
|
374
|
-
|
375
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
376
|
-
:: Notes ::
|
377
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
378
|
-
|
379
|
-
* No eval (I don't think eval is evil, it's just not the way this works)
|
380
|
-
|
381
|
-
* The data-ruhl attribute is always removed from the output.
|
382
|
-
|
383
|
-
* Since it's just HTML, syntax highlighting is built-in.
|
384
|
-
For vim, just add this to your ~/.vimrc:
|
385
|
-
au BufNewFile,BufRead *.ruhl set filetype=html
|
386
|
-
|
387
|
-
|
388
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
389
|
-
:: TODO ::
|
390
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
391
|
-
|
392
|
-
1) Test more scenarios
|
7
|
+
http://stonean.com/page/ruhl
|
393
8
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.0
|
data/lib/ruhl/engine.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Ruhl
|
2
2
|
class Engine
|
3
|
-
attr_reader :
|
4
|
-
|
3
|
+
attr_reader :layout, :layout_source, :local_object, :block_object
|
4
|
+
attr_reader :document, :scope, :current_tag, :call_result, :ruhl_actions
|
5
5
|
|
6
6
|
def initialize(html, options = {})
|
7
7
|
@local_object = options[:local_object] || options[:object]
|
@@ -45,38 +45,37 @@ module Ruhl
|
|
45
45
|
render_nodes Nokogiri::HTML( @layout_source || File.read(@layout) )
|
46
46
|
end
|
47
47
|
|
48
|
-
def render_partial
|
49
|
-
|
50
|
-
|
48
|
+
def render_partial
|
49
|
+
unless File.exists?(call_result)
|
50
|
+
raise PartialNotFoundError.new(call_result)
|
51
|
+
end
|
51
52
|
|
52
|
-
render_nodes Nokogiri::HTML.fragment( File.read(
|
53
|
+
render_nodes Nokogiri::HTML.fragment( File.read(call_result) )
|
53
54
|
end
|
54
55
|
|
55
|
-
def render_collection
|
56
|
-
|
57
|
-
|
58
|
-
actions = actions.to_s.strip
|
56
|
+
def render_collection
|
57
|
+
actions = ruhl_actions.join(",").to_s.strip if ruhl_actions
|
59
58
|
|
60
|
-
|
61
|
-
html =
|
59
|
+
current_tag['data-ruhl'] = actions if actions.length > 0
|
60
|
+
html = current_tag.to_html
|
62
61
|
|
63
|
-
new_content =
|
62
|
+
new_content = call_result.collect do |item|
|
64
63
|
# Call to_s on the item only if there are no other actions
|
65
64
|
# and there are no other nested data-ruhls
|
66
|
-
if actions.length == 0 &&
|
67
|
-
|
68
|
-
|
65
|
+
if actions.length == 0 && current_tag.xpath('.//*[@data-ruhl]').length == 0
|
66
|
+
current_tag.inner_html = item.to_s
|
67
|
+
current_tag.to_html
|
69
68
|
else
|
70
69
|
Ruhl::Engine.new(html, :local_object => item).render(scope)
|
71
70
|
end
|
72
71
|
end.to_s
|
73
72
|
|
74
|
-
|
73
|
+
current_tag.swap(new_content)
|
75
74
|
end
|
76
75
|
|
77
|
-
def render_block
|
78
|
-
|
79
|
-
|
76
|
+
def render_block
|
77
|
+
Ruhl::Engine.new(current_tag.inner_html,
|
78
|
+
:block_object => call_result).render(scope)
|
80
79
|
end
|
81
80
|
|
82
81
|
def render_nodes(nodes)
|
@@ -91,97 +90,117 @@ module Ruhl
|
|
91
90
|
|
92
91
|
return if nodes.empty?
|
93
92
|
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
@current_tag = nodes.first
|
94
|
+
|
95
|
+
@ruhl_actions = current_tag.remove_attribute('data-ruhl').value.split(',')
|
96
|
+
|
97
|
+
process_attribute
|
97
98
|
|
98
99
|
parse_doc(doc)
|
99
100
|
end
|
100
101
|
|
101
|
-
def process_attribute
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
102
|
+
def process_attribute
|
103
|
+
catch(:done) do
|
104
|
+
ruhl_actions.dup.each_with_index do |action, ndx|
|
105
|
+
# Remove action from being applied twice.
|
106
|
+
ruhl_actions.delete_at(ndx)
|
107
|
+
|
108
|
+
process_action(action)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def process_action(action)
|
114
|
+
attribute, value = action.split(':')
|
107
115
|
|
108
|
-
|
109
|
-
|
110
|
-
|
116
|
+
code = (value || attribute)
|
117
|
+
@call_result = execute_ruby(code.strip)
|
118
|
+
|
119
|
+
if value.nil?
|
120
|
+
process_results
|
121
|
+
else
|
122
|
+
if attribute =~ /^_/
|
123
|
+
process_ruhl(attribute, value)
|
111
124
|
else
|
112
|
-
|
113
|
-
|
114
|
-
unless attribute =~ /^_/
|
115
|
-
tag[attribute] = execute_ruby(tag, value).to_s
|
116
|
-
else
|
117
|
-
case attribute
|
118
|
-
when "_use"
|
119
|
-
tag.inner_html = render_block(tag, value)
|
120
|
-
when "_partial"
|
121
|
-
tag.inner_html = render_partial(tag, value)
|
122
|
-
when "_collection"
|
123
|
-
actions.delete_at(ndx)
|
124
|
-
render_collection(tag, value, actions.join(','))
|
125
|
-
return
|
126
|
-
when "_if"
|
127
|
-
return unless process_if(tag, value)
|
128
|
-
when "_unless"
|
129
|
-
return if process_unless(tag, value)
|
130
|
-
end
|
131
|
-
end
|
125
|
+
current_tag[attribute] = call_result.to_s
|
132
126
|
end
|
133
127
|
end
|
134
128
|
end
|
129
|
+
|
130
|
+
def process_ruhl(attribute, value)
|
131
|
+
case attribute
|
132
|
+
when "_use_if"
|
133
|
+
ruhl_if { ruhl_use }
|
134
|
+
when "_use", "_collection"
|
135
|
+
ruhl_use
|
136
|
+
when "_partial"
|
137
|
+
current_tag.inner_html = render_partial
|
138
|
+
when "_if"
|
139
|
+
ruhl_if
|
140
|
+
when "_unless"
|
141
|
+
ruhl_unless
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def ruhl_use
|
146
|
+
if call_result.kind_of?(Enumerable) and !call_result.instance_of?(String)
|
147
|
+
render_collection
|
148
|
+
throw :done
|
149
|
+
else
|
150
|
+
current_tag.inner_html = render_block
|
151
|
+
end
|
152
|
+
end
|
135
153
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
true
|
154
|
+
def ruhl_if
|
155
|
+
if stop_processing?
|
156
|
+
current_tag.remove
|
157
|
+
throw :done
|
141
158
|
else
|
142
|
-
|
143
|
-
|
159
|
+
if continue_processing?
|
160
|
+
yield if block_given?
|
161
|
+
else
|
162
|
+
process_results
|
163
|
+
end
|
144
164
|
end
|
145
165
|
end
|
146
166
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
false
|
167
|
+
def ruhl_unless
|
168
|
+
if call_result
|
169
|
+
unless call_result_empty?
|
170
|
+
current_tag.remove
|
171
|
+
throw :done
|
172
|
+
end
|
154
173
|
end
|
155
174
|
end
|
156
175
|
|
157
|
-
def process_results
|
158
|
-
if
|
159
|
-
|
176
|
+
def process_results
|
177
|
+
if call_result.is_a?(Hash)
|
178
|
+
call_result.each do |key, value|
|
160
179
|
if key == :inner_html
|
161
|
-
|
180
|
+
current_tag.inner_html = value.to_s
|
162
181
|
else
|
163
|
-
|
182
|
+
current_tag[key.to_s] = value.to_s
|
164
183
|
end
|
165
184
|
end
|
166
185
|
else
|
167
|
-
|
186
|
+
current_tag.inner_html = call_result.to_s
|
168
187
|
end
|
169
188
|
end
|
170
189
|
|
171
|
-
def execute_ruby(
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
190
|
+
def execute_ruby(code)
|
191
|
+
if code == '_render_'
|
192
|
+
_render_
|
193
|
+
else
|
194
|
+
if block_object && block_object.respond_to?(code)
|
176
195
|
block_object.send(code)
|
196
|
+
elsif local_object && local_object.respond_to?(code)
|
197
|
+
local_object.send(code)
|
177
198
|
else
|
178
199
|
scope.send(code)
|
179
200
|
end
|
180
|
-
else
|
181
|
-
_render_
|
182
201
|
end
|
183
202
|
rescue NoMethodError => e
|
184
|
-
log_context(
|
203
|
+
log_context(code)
|
185
204
|
raise e
|
186
205
|
end
|
187
206
|
|
@@ -190,10 +209,24 @@ module Ruhl
|
|
190
209
|
@scope = current_scope
|
191
210
|
end
|
192
211
|
|
193
|
-
def
|
212
|
+
def stop_processing?
|
213
|
+
call_result.nil? ||
|
214
|
+
call_result == false ||
|
215
|
+
call_result_empty?
|
216
|
+
end
|
217
|
+
|
218
|
+
def continue_processing?
|
219
|
+
call_result == true || !call_result_empty?
|
220
|
+
end
|
221
|
+
|
222
|
+
def call_result_empty?
|
223
|
+
call_result.kind_of?(Enumerable) && call_result.empty?
|
224
|
+
end
|
225
|
+
|
226
|
+
def log_context(code)
|
194
227
|
Ruhl.logger.error <<CONTEXT
|
195
228
|
Context:
|
196
|
-
tag : #{
|
229
|
+
tag : #{current_tag.inspect}
|
197
230
|
code : #{code.inspect}
|
198
231
|
local_object : #{local_object.inspect}
|
199
232
|
block_object : #{block_object.inspect}
|
data/ruhl.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ruhl}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.10.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrew Stone"]
|
12
|
-
s.date = %q{2009-10-
|
12
|
+
s.date = %q{2009-10-24}
|
13
13
|
s.description = %q{Make your HTML dynamic with the addition of a data-ruhl attribute.}
|
14
14
|
s.email = %q{andy@stonean.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"spec/html/fragment.html",
|
33
33
|
"spec/html/hash.html",
|
34
34
|
"spec/html/if.html",
|
35
|
+
"spec/html/if_on_collection.html",
|
35
36
|
"spec/html/layout.html",
|
36
37
|
"spec/html/loop.html",
|
37
38
|
"spec/html/main_with_form.html",
|
@@ -40,6 +41,7 @@ Gem::Specification.new do |s|
|
|
40
41
|
"spec/html/seo.html",
|
41
42
|
"spec/html/sidebar.html",
|
42
43
|
"spec/html/use.html",
|
44
|
+
"spec/html/use_if.html",
|
43
45
|
"spec/rcov.opts",
|
44
46
|
"spec/ruhl_spec.rb",
|
45
47
|
"spec/spec.opts",
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>This is a title template</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<h1>This is the header template</h1>
|
7
|
+
<table data-ruhl="_if: user_list">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<td>First Name</td>
|
11
|
+
<td>Last Name</td>
|
12
|
+
<td>Email</td>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tr data-ruhl="_collection: user_list">
|
16
|
+
<td data-ruhl="first_name">Andrew</td>
|
17
|
+
<td data-ruhl="last_name">Stone</td>
|
18
|
+
<td data-ruhl="_if: email">andy@stonean.com</td>
|
19
|
+
</tr>
|
20
|
+
</table>
|
21
|
+
<p data-ruhl="_unless: user_list, no_users_message"/>
|
22
|
+
</body>
|
23
|
+
</html>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>This is a title template</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<div id="sidebar" data-ruhl="_use_if: user">
|
7
|
+
<h1>My Account</h1>
|
8
|
+
<form action="/account" class="edit_user" id="edit_user" method="post">
|
9
|
+
|
10
|
+
<label for='user_first_name'>First Name:</label>
|
11
|
+
<input id="user_first_name" name="user[first_name]" size="30" type="text"
|
12
|
+
data-ruhl="value: first_name" />
|
13
|
+
|
14
|
+
<label for='user_last_name'>Last Name:</label>
|
15
|
+
<input id="user_last_name" name="user[last_name]" size="30" type="text"
|
16
|
+
data-ruhl="value: last_name" />
|
17
|
+
|
18
|
+
<label for='user_email'>Email:</label>
|
19
|
+
<input id="user_email" name="user[email]" size="30" type="text"
|
20
|
+
data-ruhl="value: email" />
|
21
|
+
|
22
|
+
<div class='btn_row'>
|
23
|
+
<input id="user_submit" name="commit" type="submit" value="Login" />
|
24
|
+
</div>
|
25
|
+
</form>
|
26
|
+
</div>
|
27
|
+
</body>
|
28
|
+
</html>
|
data/spec/ruhl_spec.rb
CHANGED
@@ -82,11 +82,35 @@ describe Ruhl do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
shared_examples_for "if with no users" do
|
86
|
+
it "table should not render" do
|
87
|
+
nodes = @doc.xpath('/html/body//*')
|
88
|
+
nodes.children.length.should == 2
|
89
|
+
nodes.children[0].to_s.should == "This is the header template"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "no user message should render" do
|
93
|
+
nodes = @doc.xpath('/html/body//*')
|
94
|
+
nodes.children[1].to_s.should == @co.no_users_message
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
shared_examples_for "if with users" do
|
99
|
+
it "table should render" do
|
100
|
+
nodes = @doc.xpath('/html/body//*')
|
101
|
+
nodes.children.length.should > 1
|
102
|
+
|
103
|
+
table = @doc.xpath('/html/body/table/tr//td')
|
104
|
+
table.children[12].to_s.should == "NoMail"
|
105
|
+
table.children[13].to_s.should == "Man"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
85
109
|
describe "if.html" do
|
86
|
-
describe "
|
110
|
+
describe "users? is false" do
|
87
111
|
before do
|
88
112
|
class ContextObject
|
89
|
-
def users?
|
113
|
+
def users?
|
90
114
|
false
|
91
115
|
end
|
92
116
|
end
|
@@ -95,22 +119,13 @@ describe Ruhl do
|
|
95
119
|
@doc = create_doc
|
96
120
|
end
|
97
121
|
|
98
|
-
|
99
|
-
nodes = @doc.xpath('/html/body//*')
|
100
|
-
nodes.children.length.should == 2
|
101
|
-
nodes.children[0].to_s.should == "This is the header template"
|
102
|
-
end
|
103
|
-
|
104
|
-
it "no user message should render" do
|
105
|
-
nodes = @doc.xpath('/html/body//*')
|
106
|
-
nodes.children[1].to_s.should == @co.no_users_message
|
107
|
-
end
|
122
|
+
it_should_behave_like "if with no users"
|
108
123
|
end
|
109
124
|
|
110
|
-
describe "
|
125
|
+
describe "users? is true" do
|
111
126
|
before do
|
112
127
|
class ContextObject
|
113
|
-
def users?
|
128
|
+
def users?
|
114
129
|
true
|
115
130
|
end
|
116
131
|
end
|
@@ -119,14 +134,45 @@ describe Ruhl do
|
|
119
134
|
@doc = create_doc
|
120
135
|
end
|
121
136
|
|
122
|
-
|
123
|
-
|
124
|
-
|
137
|
+
it_should_behave_like "if with users"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "if_on_collection.html" do
|
142
|
+
describe "user_list is empty" do
|
143
|
+
before do
|
144
|
+
class ContextObject
|
145
|
+
def user_list
|
146
|
+
[]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
@html = File.read html(:if_on_collection)
|
151
|
+
@doc = create_doc
|
152
|
+
end
|
153
|
+
|
154
|
+
it_should_behave_like "if with no users"
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "user_list is not empty" do
|
158
|
+
before do
|
159
|
+
class ContextObject
|
160
|
+
def user_list
|
161
|
+
[
|
162
|
+
TestUser.new('Jane', 'Doe', 'jane@stonean.com'),
|
163
|
+
TestUser.new('John', 'Joe', 'john@stonean.com'),
|
164
|
+
TestUser.new('Jake', 'Smo', 'jake@stonean.com'),
|
165
|
+
TestUser.new('Paul', 'Tin', 'paul@stonean.com'),
|
166
|
+
TestUser.new('NoMail', 'Man')
|
167
|
+
]
|
168
|
+
end
|
169
|
+
end
|
125
170
|
|
126
|
-
|
127
|
-
|
128
|
-
table.children[13].to_s.should == "Man"
|
171
|
+
@html = File.read html(:if_on_collection)
|
172
|
+
@doc = create_doc
|
129
173
|
end
|
174
|
+
|
175
|
+
it_should_behave_like "if with users"
|
130
176
|
end
|
131
177
|
end
|
132
178
|
|
@@ -177,12 +223,7 @@ describe Ruhl do
|
|
177
223
|
end
|
178
224
|
end
|
179
225
|
|
180
|
-
|
181
|
-
before do
|
182
|
-
@html = File.read html(:use)
|
183
|
-
@doc = create_doc
|
184
|
-
end
|
185
|
-
|
226
|
+
shared_examples_for "if with user" do
|
186
227
|
it "first name will be set" do
|
187
228
|
@doc.xpath('/html/body/div//input')[0]['value'].should == "Jane"
|
188
229
|
end
|
@@ -195,6 +236,24 @@ describe Ruhl do
|
|
195
236
|
@doc.xpath('/html/body/div//input')[2]['value'].should == "jane@stonean.com"
|
196
237
|
end
|
197
238
|
end
|
239
|
+
|
240
|
+
describe "use.html" do
|
241
|
+
before do
|
242
|
+
@html = File.read html(:use)
|
243
|
+
@doc = create_doc
|
244
|
+
end
|
245
|
+
|
246
|
+
it_should_behave_like "if with user"
|
247
|
+
end
|
248
|
+
|
249
|
+
describe "use_if.html" do
|
250
|
+
before do
|
251
|
+
@html = File.read html(:use_if)
|
252
|
+
@doc = create_doc
|
253
|
+
end
|
254
|
+
|
255
|
+
it_should_behave_like "if with user"
|
256
|
+
end
|
198
257
|
|
199
258
|
describe "collection_of_strings.html" do
|
200
259
|
before do
|
data/spec/spec_helper.rb
CHANGED
@@ -29,47 +29,47 @@ class TestUser
|
|
29
29
|
@nicknames = ['Auntie','Pattern']
|
30
30
|
end
|
31
31
|
|
32
|
-
def radio_input
|
32
|
+
def radio_input
|
33
33
|
{ :inner_html => first_name, :id => "user_#{id.to_s}",
|
34
34
|
:name => "user[id]", :value => last_name.downcase}
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def user
|
38
|
+
def user
|
39
39
|
TestUser.new('Jane', 'Doe', 'jane@stonean.com')
|
40
40
|
end
|
41
41
|
|
42
42
|
|
43
43
|
class ContextObject
|
44
|
-
def generate_h1
|
44
|
+
def generate_h1
|
45
45
|
"data from presenter"
|
46
46
|
end
|
47
47
|
|
48
|
-
def data_from_method
|
48
|
+
def data_from_method
|
49
49
|
"I am data from a method"
|
50
50
|
end
|
51
51
|
|
52
|
-
def generate_description
|
52
|
+
def generate_description
|
53
53
|
"I am a custom meta description"
|
54
54
|
end
|
55
55
|
|
56
|
-
def generate_keywords
|
56
|
+
def generate_keywords
|
57
57
|
"I, am, custom, keywords"
|
58
58
|
end
|
59
59
|
|
60
|
-
def my_content
|
60
|
+
def my_content
|
61
61
|
"hello from my content."
|
62
62
|
end
|
63
63
|
|
64
|
-
def sidebar_partial
|
64
|
+
def sidebar_partial
|
65
65
|
html(:sidebar)
|
66
66
|
end
|
67
67
|
|
68
|
-
def form_partial
|
68
|
+
def form_partial
|
69
69
|
html(:form)
|
70
70
|
end
|
71
71
|
|
72
|
-
def user_list
|
72
|
+
def user_list
|
73
73
|
[
|
74
74
|
TestUser.new('Jane', 'Doe', 'jane@stonean.com'),
|
75
75
|
TestUser.new('John', 'Joe', 'john@stonean.com'),
|
@@ -79,15 +79,15 @@ class ContextObject
|
|
79
79
|
]
|
80
80
|
end
|
81
81
|
|
82
|
-
def users?
|
82
|
+
def users?
|
83
83
|
true
|
84
84
|
end
|
85
85
|
|
86
|
-
def no_users_message
|
86
|
+
def no_users_message
|
87
87
|
"Sorry no users found"
|
88
88
|
end
|
89
89
|
|
90
|
-
def states_for_select
|
90
|
+
def states_for_select
|
91
91
|
state = Struct.new(:abbr, :name)
|
92
92
|
[ state.new('AL', 'Alabama'),
|
93
93
|
state.new('AK', 'Alaska'),
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruhl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Stone
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-24 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- spec/html/fragment.html
|
58
58
|
- spec/html/hash.html
|
59
59
|
- spec/html/if.html
|
60
|
+
- spec/html/if_on_collection.html
|
60
61
|
- spec/html/layout.html
|
61
62
|
- spec/html/loop.html
|
62
63
|
- spec/html/main_with_form.html
|
@@ -65,6 +66,7 @@ files:
|
|
65
66
|
- spec/html/seo.html
|
66
67
|
- spec/html/sidebar.html
|
67
68
|
- spec/html/use.html
|
69
|
+
- spec/html/use_if.html
|
68
70
|
- spec/rcov.opts
|
69
71
|
- spec/ruhl_spec.rb
|
70
72
|
- spec/spec.opts
|