ruhl 0.9.3 → 0.9.4
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/VERSION +1 -1
- data/lib/ruhl/engine.rb +205 -0
- data/lib/ruhl/rails.rb +1 -0
- data/lib/ruhl.rb +6 -198
- data/ruhl.gemspec +3 -2
- metadata +3 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.4
|
data/lib/ruhl/engine.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
module Ruhl
|
2
|
+
class Engine
|
3
|
+
attr_reader :document, :scope, :layout, :layout_source,
|
4
|
+
:local_object, :block_object
|
5
|
+
|
6
|
+
def initialize(html, options = {})
|
7
|
+
@local_object = options[:local_object] || options[:object]
|
8
|
+
@block_object = options[:block_object]
|
9
|
+
@layout_source = options[:layout_source]
|
10
|
+
|
11
|
+
if @layout = options[:layout]
|
12
|
+
raise LayoutNotFoundError.new(@layout) unless File.exists?(@layout)
|
13
|
+
end
|
14
|
+
|
15
|
+
if @layout || @local_object || @block_object
|
16
|
+
@document = Nokogiri::HTML.fragment(html)
|
17
|
+
else
|
18
|
+
@document = Nokogiri::HTML(html)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(current_scope)
|
23
|
+
set_scope(current_scope)
|
24
|
+
|
25
|
+
parse_doc(document)
|
26
|
+
|
27
|
+
if @layout
|
28
|
+
render_with_layout
|
29
|
+
else
|
30
|
+
document.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# The _render_ method is used within a layout to inject
|
35
|
+
# the results of the template render.
|
36
|
+
#
|
37
|
+
# Ruhl::Engine.new(html, :layout => path_to_layout).render(self)
|
38
|
+
def _render_
|
39
|
+
document.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def render_with_layout
|
45
|
+
render_file( @layout_source || File.read(@layout) )
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_partial(tag, code)
|
49
|
+
file = execute_ruby(tag, code)
|
50
|
+
raise PartialNotFoundError.new(file) unless File.exists?(file)
|
51
|
+
|
52
|
+
render_file( File.read(file) )
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_collection(tag, code, actions = nil)
|
56
|
+
results = execute_ruby(tag, code)
|
57
|
+
|
58
|
+
actions = actions.to_s.strip
|
59
|
+
|
60
|
+
tag['data-ruhl'] = actions if actions.length > 0
|
61
|
+
html = tag.to_html
|
62
|
+
|
63
|
+
new_content = results.collect do |item|
|
64
|
+
# Call to_s on the item only if there are no other actions
|
65
|
+
# and there are no other nested data-ruhls
|
66
|
+
if actions.length == 0 && tag.xpath('.//*[@data-ruhl]').length == 0
|
67
|
+
tag.inner_html = item.to_s
|
68
|
+
tag.to_html
|
69
|
+
else
|
70
|
+
Ruhl::Engine.new(html, :local_object => item).render(scope)
|
71
|
+
end
|
72
|
+
end.to_s
|
73
|
+
|
74
|
+
tag.swap(new_content)
|
75
|
+
end
|
76
|
+
|
77
|
+
def render_block(tag, code)
|
78
|
+
bo = execute_ruby(tag, code)
|
79
|
+
Ruhl::Engine.new(tag.inner_html, :block_object => bo).render(scope)
|
80
|
+
end
|
81
|
+
|
82
|
+
def render_file(contents)
|
83
|
+
doc = Nokogiri::HTML( contents )
|
84
|
+
parse_doc(doc)
|
85
|
+
doc.to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_doc(doc)
|
89
|
+
if (nodes = doc.xpath('*[@data-ruhl][1]')).empty?
|
90
|
+
nodes = doc.search('*[@data-ruhl]')
|
91
|
+
end
|
92
|
+
|
93
|
+
return if nodes.empty?
|
94
|
+
|
95
|
+
tag = nodes.first
|
96
|
+
code = tag.remove_attribute('data-ruhl')
|
97
|
+
process_attribute(tag, code.value)
|
98
|
+
|
99
|
+
parse_doc(doc)
|
100
|
+
end
|
101
|
+
|
102
|
+
def process_attribute(tag, code)
|
103
|
+
actions = code.split(',')
|
104
|
+
actions.dup.each_with_index do |pair, ndx|
|
105
|
+
attribute, value = pair.split(':')
|
106
|
+
|
107
|
+
attribute.strip!
|
108
|
+
|
109
|
+
if value.nil?
|
110
|
+
results = execute_ruby(tag, attribute)
|
111
|
+
process_results(tag, results)
|
112
|
+
else
|
113
|
+
value.strip!
|
114
|
+
|
115
|
+
unless attribute =~ /^_/
|
116
|
+
tag[attribute] = execute_ruby(tag, value)
|
117
|
+
else
|
118
|
+
case attribute
|
119
|
+
when "_use"
|
120
|
+
tag.inner_html = render_block(tag, value)
|
121
|
+
when "_partial"
|
122
|
+
tag.inner_html = render_partial(tag, value)
|
123
|
+
when "_collection"
|
124
|
+
actions.delete_at(ndx)
|
125
|
+
render_collection(tag, value, actions.join(','))
|
126
|
+
return
|
127
|
+
when "_if"
|
128
|
+
return unless process_if(tag, value)
|
129
|
+
when "_unless"
|
130
|
+
return if process_unless(tag, value)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def process_if(tag, value)
|
138
|
+
contents = execute_ruby(tag, value)
|
139
|
+
if contents
|
140
|
+
process_results(tag, contents) unless contents == true
|
141
|
+
true
|
142
|
+
else
|
143
|
+
tag.remove
|
144
|
+
false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def process_unless(tag, value)
|
149
|
+
contents = execute_ruby(tag, value)
|
150
|
+
if contents
|
151
|
+
tag.remove
|
152
|
+
true
|
153
|
+
else
|
154
|
+
false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def process_results(tag, results)
|
159
|
+
if results.is_a?(Hash)
|
160
|
+
results.each do |key, value|
|
161
|
+
if key == :inner_html
|
162
|
+
tag.inner_html = value
|
163
|
+
else
|
164
|
+
tag[key.to_s] = value
|
165
|
+
end
|
166
|
+
end
|
167
|
+
else
|
168
|
+
tag.inner_html = results.to_s
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def execute_ruby(tag, code)
|
173
|
+
unless code == '_render_'
|
174
|
+
if local_object && local_object.respond_to?(code)
|
175
|
+
local_object.send(code)
|
176
|
+
elsif block_object && block_object.respond_to?(code)
|
177
|
+
block_object.send(code)
|
178
|
+
else
|
179
|
+
scope.send(code)
|
180
|
+
end
|
181
|
+
else
|
182
|
+
_render_
|
183
|
+
end
|
184
|
+
rescue NoMethodError => e
|
185
|
+
log_context(tag,code)
|
186
|
+
raise e
|
187
|
+
end
|
188
|
+
|
189
|
+
def set_scope(current_scope)
|
190
|
+
raise Ruhl::NoScopeError unless current_scope
|
191
|
+
@scope = current_scope
|
192
|
+
end
|
193
|
+
|
194
|
+
def log_context(tag,code)
|
195
|
+
Ruhl.logger.error <<CONTEXT
|
196
|
+
Context:
|
197
|
+
tag : #{tag.inspect}
|
198
|
+
code : #{code.inspect}
|
199
|
+
local_object : #{local_object.inspect}
|
200
|
+
block_object : #{block_object.inspect}
|
201
|
+
scope : #{scope.class}
|
202
|
+
CONTEXT
|
203
|
+
end
|
204
|
+
end # Engine
|
205
|
+
end # Ruhl
|
data/lib/ruhl/rails.rb
CHANGED
@@ -13,6 +13,7 @@ module Ruhl
|
|
13
13
|
options[:layout] = layout.filename
|
14
14
|
options[:layout_source] = layout.source
|
15
15
|
|
16
|
+
Rails.logger.info("calling ruhl. template: #{template.inspect}\n options: #{options.inspect}")
|
16
17
|
Ruhl::Engine.new(template.source, options).render(@action_view)
|
17
18
|
end
|
18
19
|
end
|
data/lib/ruhl.rb
CHANGED
@@ -1,207 +1,15 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__)
|
2
2
|
|
3
3
|
require 'nokogiri'
|
4
|
+
require 'logger'
|
5
|
+
require 'ruhl/engine'
|
4
6
|
require 'ruhl/errors'
|
5
7
|
|
6
8
|
module Ruhl
|
7
|
-
class
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(html, options = {})
|
12
|
-
@local_object = options[:local_object]
|
13
|
-
@block_object = options[:block_object]
|
14
|
-
@layout_source = options[:layout_source]
|
15
|
-
|
16
|
-
if @layout = options[:layout]
|
17
|
-
raise LayoutNotFoundError.new(@layout) unless File.exists?(@layout)
|
18
|
-
end
|
19
|
-
|
20
|
-
if @layout || @local_object || @block_object
|
21
|
-
@document = Nokogiri::HTML.fragment(html)
|
22
|
-
else
|
23
|
-
@document = Nokogiri::HTML(html)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def render(current_scope)
|
28
|
-
set_scope(current_scope)
|
29
|
-
|
30
|
-
parse_doc(document)
|
31
|
-
|
32
|
-
if @layout
|
33
|
-
render_with_layout
|
34
|
-
else
|
35
|
-
document.to_s
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# The _render_ method is used within a layout to inject
|
40
|
-
# the results of the template render.
|
41
|
-
#
|
42
|
-
# Ruhl::Engine.new(html, :layout => path_to_layout).render(self)
|
43
|
-
def _render_
|
44
|
-
document.to_s
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def render_with_layout
|
50
|
-
render_file( @layout_source || File.read(@layout) )
|
51
|
-
end
|
52
|
-
|
53
|
-
def render_partial(tag, code)
|
54
|
-
file = execute_ruby(tag, code)
|
55
|
-
raise PartialNotFoundError.new(file) unless File.exists?(file)
|
56
|
-
|
57
|
-
render_file( File.read(file) )
|
58
|
-
end
|
59
|
-
|
60
|
-
def render_collection(tag, code, actions = nil)
|
61
|
-
results = execute_ruby(tag, code)
|
62
|
-
|
63
|
-
actions = actions.to_s.strip
|
64
|
-
|
65
|
-
tag['data-ruhl'] = actions if actions.length > 0
|
66
|
-
html = tag.to_html
|
67
|
-
|
68
|
-
new_content = results.collect do |item|
|
69
|
-
# Call to_s on the item only if there are no other actions
|
70
|
-
# and there are no other nested data-ruhls
|
71
|
-
if actions.length == 0 && tag.xpath('.//*[@data-ruhl]').length == 0
|
72
|
-
tag.inner_html = item.to_s
|
73
|
-
tag.to_html
|
74
|
-
else
|
75
|
-
Ruhl::Engine.new(html, :local_object => item).render(scope)
|
76
|
-
end
|
77
|
-
end.to_s
|
78
|
-
|
79
|
-
tag.swap(new_content)
|
80
|
-
end
|
81
|
-
|
82
|
-
def render_block(tag, code)
|
83
|
-
bo = execute_ruby(tag, code)
|
84
|
-
Ruhl::Engine.new(tag.inner_html, :block_object => bo).render(scope)
|
85
|
-
end
|
86
|
-
|
87
|
-
def render_file(contents)
|
88
|
-
doc = Nokogiri::HTML( contents )
|
89
|
-
parse_doc(doc)
|
90
|
-
doc.to_s
|
91
|
-
end
|
92
|
-
|
93
|
-
def parse_doc(doc)
|
94
|
-
if (nodes = doc.xpath('*[@data-ruhl][1]')).empty?
|
95
|
-
nodes = doc.search('*[@data-ruhl]')
|
96
|
-
end
|
97
|
-
|
98
|
-
return if nodes.empty?
|
99
|
-
|
100
|
-
tag = nodes.first
|
101
|
-
code = tag.remove_attribute('data-ruhl')
|
102
|
-
process_attribute(tag, code.value)
|
103
|
-
|
104
|
-
parse_doc(doc)
|
105
|
-
end
|
106
|
-
|
107
|
-
def process_attribute(tag, code)
|
108
|
-
actions = code.split(',')
|
109
|
-
actions.dup.each_with_index do |pair, ndx|
|
110
|
-
attribute, value = pair.split(':')
|
111
|
-
|
112
|
-
attribute.strip!
|
113
|
-
|
114
|
-
if value.nil?
|
115
|
-
results = execute_ruby(tag, attribute)
|
116
|
-
process_results(tag, results)
|
117
|
-
else
|
118
|
-
value.strip!
|
119
|
-
|
120
|
-
unless attribute =~ /^_/
|
121
|
-
tag[attribute] = execute_ruby(tag, value)
|
122
|
-
else
|
123
|
-
case attribute
|
124
|
-
when "_use"
|
125
|
-
tag.inner_html = render_block(tag, value)
|
126
|
-
when "_partial"
|
127
|
-
tag.inner_html = render_partial(tag, value)
|
128
|
-
when "_collection"
|
129
|
-
actions.delete_at(ndx)
|
130
|
-
render_collection(tag, value, actions.join(','))
|
131
|
-
return
|
132
|
-
when "_if"
|
133
|
-
return unless process_if(tag, value)
|
134
|
-
when "_unless"
|
135
|
-
return if process_unless(tag, value)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def process_if(tag, value)
|
143
|
-
contents = execute_ruby(tag, value)
|
144
|
-
if contents
|
145
|
-
process_results(tag, contents) unless contents == true
|
146
|
-
true
|
147
|
-
else
|
148
|
-
tag.remove
|
149
|
-
false
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def process_unless(tag, value)
|
154
|
-
contents = execute_ruby(tag, value)
|
155
|
-
if contents
|
156
|
-
tag.remove
|
157
|
-
true
|
158
|
-
else
|
159
|
-
false
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def process_results(tag, results)
|
164
|
-
if results.is_a?(Hash)
|
165
|
-
results.each do |key, value|
|
166
|
-
if key == :inner_html
|
167
|
-
tag.inner_html = value
|
168
|
-
else
|
169
|
-
tag[key.to_s] = value
|
170
|
-
end
|
171
|
-
end
|
172
|
-
else
|
173
|
-
tag.inner_html = results.to_s
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def execute_ruby(tag, code)
|
178
|
-
unless code == '_render_'
|
179
|
-
if local_object && local_object.respond_to?(code)
|
180
|
-
local_object.send(code)
|
181
|
-
elsif block_object && block_object.respond_to?(code)
|
182
|
-
block_object.send(code)
|
183
|
-
else
|
184
|
-
scope.send(code)
|
185
|
-
end
|
186
|
-
else
|
187
|
-
_render_
|
188
|
-
end
|
189
|
-
rescue NoMethodError => e
|
190
|
-
puts <<CONTEXT
|
191
|
-
Context:
|
192
|
-
tag : #{tag.inspect}
|
193
|
-
code : #{code.inspect}
|
194
|
-
local_object : #{local_object.inspect}
|
195
|
-
block_object : #{block_object.inspect}
|
196
|
-
scope : #{scope.inspect}
|
197
|
-
CONTEXT
|
198
|
-
raise e
|
199
|
-
end
|
9
|
+
class << self
|
10
|
+
attr_accessor :logger
|
11
|
+
end
|
200
12
|
|
201
|
-
|
202
|
-
raise Ruhl::NoScopeError unless current_scope
|
203
|
-
@scope = current_scope
|
204
|
-
end
|
13
|
+
self.logger = Logger.new(STDOUT)
|
205
14
|
|
206
|
-
end
|
207
15
|
end
|
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.9.
|
8
|
+
s.version = "0.9.4"
|
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-17}
|
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 = [
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
"Rakefile",
|
22
22
|
"VERSION",
|
23
23
|
"lib/ruhl.rb",
|
24
|
+
"lib/ruhl/engine.rb",
|
24
25
|
"lib/ruhl/errors.rb",
|
25
26
|
"lib/ruhl/rails.rb",
|
26
27
|
"lib/ruhl/sinatra.rb",
|
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.9.
|
4
|
+
version: 0.9.4
|
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-17 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -46,6 +46,7 @@ files:
|
|
46
46
|
- Rakefile
|
47
47
|
- VERSION
|
48
48
|
- lib/ruhl.rb
|
49
|
+
- lib/ruhl/engine.rb
|
49
50
|
- lib/ruhl/errors.rb
|
50
51
|
- lib/ruhl/rails.rb
|
51
52
|
- lib/ruhl/sinatra.rb
|