ruhl 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.DS_Store
2
+ *.swp
3
+ pkg/**
4
+ coverage/**
data/README ADDED
@@ -0,0 +1,241 @@
1
+ Ruhl (Ruby Hypertext Language)
2
+
3
+ This project is here to flesh out an idea. What I want is to have developers
4
+ work with HTML and with the simple addition of a 'data-ruhl' attribute, convert it
5
+ to a dynamic page.
6
+
7
+ At no time in the dev process would the view be unviewable in a browser.
8
+ The view could actually retain the original template data the designer used
9
+ because this replaces the content. I think this is a nice plus.
10
+
11
+
12
+ Notes (use cases) for me to remember:
13
+
14
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15
+ :: Basic Use ::
16
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
+
18
+ <h1 data-ruhl="page_header">
19
+
20
+ Method :page_header would know how to represent itself in the context of
21
+ the h1 element.
22
+
23
+ The Ruby executed would replace the content of the element it was being
24
+ called on.
25
+
26
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27
+ :: Replacing attribute values ::
28
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29
+
30
+ <meta data-ruhl="content: meta_description" content='This is a description template'
31
+ id='metaDescription' name='description' />
32
+
33
+ content: meta_description is telling the parser to replace attribute 'content'
34
+ with results from meta_description method.
35
+
36
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37
+ :: Don't use iterators in views ::
38
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39
+
40
+ <table id="aab">
41
+ <tr data-ruhl="_collection: user_list">
42
+ <td data-ruhl="name">John Doe</td>
43
+ <td data-ruhl="email">john@doe.com</td>
44
+ </tr>
45
+ </table>
46
+
47
+ 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:
48
+
49
+ <tr data-ruhl="_collection: user_list">
50
+ <td data-ruhl="name">John Doe</td>
51
+ <td data-ruhl="email">john@doe.com</td>
52
+ </tr>
53
+
54
+ is duplicated for each user in user_list.
55
+
56
+ If user_list return an array of User objects like:
57
+
58
+ [ User.create(:name => 'Rupert Boy', :email => 'rupert@stonean.com'),
59
+ User.create(:name => 'Kaylee Girl', :email => 'kaylee@stonean.com'),
60
+ User.create(:name => 'Monty Man', :email => 'monty@stonean.com')]
61
+
62
+ <table id="aab">
63
+ <tr>
64
+ <td>Rupert Boy</td>
65
+ <td>rupert@stonean.com</td>
66
+ </tr>
67
+ <tr>
68
+ <td>Kaylee Girl</td>
69
+ <td>kaylee@stonean.com</td>
70
+ </tr>
71
+ <tr>
72
+ <td>Monty Man</td>
73
+ <td>monty@stonean.com</td>
74
+ </tr>
75
+ </table>
76
+
77
+
78
+
79
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
80
+ :: Using a Layout ::
81
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
82
+
83
+ Layout:
84
+ <html>
85
+ <head>
86
+ <title>This is a title template</title>
87
+ </head>
88
+ <body>
89
+ <div data-ruhl="_render_"></div>
90
+ </body>
91
+ </html>
92
+
93
+ Fragment:
94
+ <h1 data-ruhl="generate_h1">I am a templated headline</h1>
95
+ <p data-ruhl="my_content">Lorem ipsum dolor sit amet</p>
96
+
97
+ To use:
98
+
99
+ Ruhl::Engine.new(File.read(fragment), :layout => path_to_layout).render(self)
100
+
101
+ Returns the expected result of parsed Layout w/ parsed Fragment.
102
+
103
+ Note the use of the _render_ method. This is a 'special' method that
104
+ Ruhl uses to inject the results of the parsed fragment into the layout.
105
+
106
+
107
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108
+ :: Using a Partial ::
109
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110
+
111
+ Main:
112
+ <html>
113
+ <head>
114
+ <title>This is a title template</title>
115
+ </head>
116
+ <body>
117
+ <div id="wrap">
118
+ <div id="sidebar" data-ruhl="_partial: sidebar_partial">
119
+ <h3>Sidebar links</h3>
120
+ <ul>
121
+ <li><a href="#">Link 1</a></li>
122
+ <li><a href="#">Link 2</a></li>
123
+ <li><a href="#">Link 3</a></li>
124
+ <li><a href="#">Link 4</a></li>
125
+ </ul>
126
+ </div>
127
+ <div id="main">
128
+ <h1> My main content</h1>
129
+ <p>Text designers would put here to test their layout</p>
130
+ </div>
131
+ </div>
132
+ </body>
133
+ </html>
134
+
135
+ Sidebar:
136
+ <h3>Real Sidebarlinks</h3>
137
+ <ul>
138
+ <li><a href="#">Real Link 1</a></li>
139
+ <li><a href="#">Real Link 2</a></li>
140
+ <li><a href="#">Real Link 3</a></li>
141
+ <li><a href="#">Real Link 4</a></li>
142
+ </ul>
143
+
144
+ To use:
145
+
146
+ Ruhl::Engine.new(File.read(path_to_main)).render(self)
147
+
148
+ Returns the expected result of parsed Main with sidebar div contents
149
+ replaced with parsed sidebar partial contents.
150
+
151
+ Note the use of the _partial key. This is a 'special' key that Ruhl
152
+ uses to inject the results of the parsed partial into the contents
153
+ of the calling node.
154
+
155
+
156
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157
+ :: Conditional display of block (_render_if)::
158
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
159
+
160
+ <html>
161
+ <head>
162
+ <title>This is a title template</title>
163
+ </head>
164
+ <body>
165
+ <h1>This is the header template</h1>
166
+ <div data-ruhl="_render_if: has_users?">
167
+ <table>
168
+ <thead>
169
+ <tr>
170
+ <td>First Name</td>
171
+ <td>Last Name</td>
172
+ <td>Email</td>
173
+ </tr>
174
+ </thead>
175
+ <tr data-ruhl="_collection: user_list">
176
+ <td data-ruhl="first_name">Andrew</td>
177
+ <td data-ruhl="last_name">Stone</td>
178
+ <td data-ruhl="email">andy@stonean.com</td>
179
+ </tr>
180
+ </table>
181
+ </div>
182
+ </ul>
183
+ </body>
184
+ </html>
185
+
186
+ if has_users? returns false then the div (including it's contents) are not shown
187
+ on output.
188
+
189
+
190
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191
+ :: Conditional display of tag (_if)::
192
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
193
+
194
+ <html>
195
+ <head>
196
+ <title>This is a title template</title>
197
+ </head>
198
+ <body>
199
+ <h1>This is the header template</h1>
200
+ <table>
201
+ <thead>
202
+ <tr>
203
+ <td>First Name</td>
204
+ <td>Last Name</td>
205
+ <td>Email</td>
206
+ </tr>
207
+ </thead>
208
+ <tr data-ruhl="_collection: user_list">
209
+ <td data-ruhl="first_name">Andrew</td>
210
+ <td data-ruhl="last_name">Stone</td>
211
+ <td data-ruhl="_if: email">andy@stonean.com</td>
212
+ </tr>
213
+ </table>
214
+ </ul>
215
+ </body>
216
+ </html>
217
+
218
+ if email == nil then the td is not shown.
219
+
220
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
221
+ :: Notes ::
222
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223
+
224
+ * No eval (I don't think eval is evil, it's just not the way this works)
225
+
226
+ * The data-ruhl attribute is always removed from the output.
227
+
228
+ * Each method called must accept a tag parameter.
229
+ e.g def page_header(tag)
230
+
231
+ * Since it's just HTML, syntax highlighting is built-in.
232
+ For vim, just add this to your ~/.vimrc:
233
+ au BufNewFile,BufRead *.ruhl set filetype=html
234
+
235
+
236
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237
+ :: TODO ::
238
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239
+
240
+ 1) Test more scenarios
241
+
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rcov'
4
+ require 'spec/rake/spectask'
5
+
6
+ task :default => 'rcov'
7
+
8
+ desc "Run all specs and rcov in a non-sucky way"
9
+ Spec::Rake::SpecTask.new(:rcov) do |t|
10
+ t.spec_opts = IO.readlines("spec/spec.opts").map {|l| l.chomp.split " "}.flatten
11
+ t.spec_files = FileList['spec/**/*_spec.rb']
12
+ t.rcov = true
13
+ t.rcov_opts = IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
14
+ end
15
+
16
+
17
+ begin
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |gemspec|
20
+ gemspec.name = "ruhl"
21
+ gemspec.summary = "Ruby Hypertext Language"
22
+ gemspec.description = "Make your HTML dynamic with the addition of a ruby attribute."
23
+ gemspec.email = "andy@stonean.com"
24
+ gemspec.homepage = "http://github.com/stonean/ruhl"
25
+ gemspec.authors = ["Andrew Stone"]
26
+ gemspec.add_dependency('nokogiri','>=1.3.3')
27
+ gemspec.add_development_dependency('rspec')
28
+ end
29
+ rescue LoadError
30
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
31
+ end
32
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -0,0 +1,135 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'nokogiri'
4
+ require 'ruhl/errors'
5
+
6
+ module Ruhl
7
+ class Engine
8
+ attr_reader :document, :scope, :layout, :local_object
9
+
10
+ def initialize(html, options = {})
11
+ @local_object = options[:local_object]
12
+
13
+ if @layout = options[:layout]
14
+ raise LayoutNotFoundError.new(@layout) unless File.exists?(@layout)
15
+ end
16
+
17
+ if @layout || @local_object
18
+ @document = Nokogiri::HTML.fragment(html)
19
+ else
20
+ @document = Nokogiri::HTML(html)
21
+ end
22
+ end
23
+
24
+ def render(current_scope)
25
+ set_scope(current_scope)
26
+
27
+ parse_doc(@document)
28
+
29
+ if @layout
30
+ render_with_layout
31
+ else
32
+ document.to_s
33
+ end
34
+ end
35
+
36
+ # The _render_ method is used within a layout to inject
37
+ # the results of the template render.
38
+ #
39
+ # Ruhl::Engine.new(html, :layout => path_to_layout).render(self)
40
+ def _render_
41
+ document.to_s
42
+ end
43
+
44
+ private
45
+
46
+ def render_with_layout
47
+ render_file( File.read(@layout) )
48
+ end
49
+
50
+ def render_partial(tag, code)
51
+ file = execute_ruby(tag, code)
52
+ raise PartialNotFoundError.new(file) unless File.exists?(file)
53
+ render_file( File.read(file) )
54
+ end
55
+
56
+ def render_collection(tag, code)
57
+ results = execute_ruby(tag, code)
58
+
59
+ html = tag.to_html
60
+
61
+ new_content = results.collect do |item|
62
+ Ruhl::Engine.new(html, :local_object => item).render(scope)
63
+ end.to_s
64
+
65
+ tag.swap(new_content)
66
+ end
67
+
68
+ def render_file(contents)
69
+ doc = Nokogiri::HTML( contents )
70
+ parse_doc(doc)
71
+ doc.to_s
72
+ end
73
+
74
+ def parse_doc(doc)
75
+ if (nodes = doc.xpath('//*[@data-ruhl][1]')).empty?
76
+ nodes = doc.search('*[@data-ruhl]')
77
+ end
78
+
79
+ return if nodes.empty?
80
+
81
+ tag = nodes.first
82
+ code = tag.remove_attribute('data-ruhl')
83
+ process_attribute(tag, code.value)
84
+ parse_doc(doc)
85
+ end
86
+
87
+ def process_attribute(tag, code)
88
+ code.split(',').each do |pair|
89
+ attribute, value = pair.split(':')
90
+
91
+ if value.nil?
92
+ tag.inner_html = execute_ruby(tag, attribute)
93
+ else
94
+ value.strip!
95
+ if attribute == "_partial"
96
+ tag.inner_html = render_partial(tag, value)
97
+ elsif attribute == "_collection"
98
+ render_collection(tag, value)
99
+ elsif attribute == "_if"
100
+ contents = execute_ruby(tag, value)
101
+ if contents
102
+ tag.inner_html = contents
103
+ else
104
+ tag.remove
105
+ end
106
+ elsif attribute == "_render_if"
107
+ unless execute_ruby(tag, value)
108
+ tag.remove
109
+ end
110
+ else
111
+ tag[attribute] = execute_ruby(tag, value)
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ def execute_ruby(tag, code)
118
+ unless code == '_render_'
119
+ if local_object && local_object.respond_to?(code)
120
+ local_object.send(code)
121
+ else
122
+ scope.send(code, tag)
123
+ end
124
+ else
125
+ _render_
126
+ end
127
+ end
128
+
129
+ def set_scope(current_scope)
130
+ raise Ruhl::NoScopeError unless current_scope
131
+ @scope = current_scope
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,5 @@
1
+ module Ruhl
2
+ class LayoutNotFoundError < StandardError; end
3
+ class PartialNotFoundError < StandardError; end
4
+ class NoScopeError < StandardError; end
5
+ end
@@ -0,0 +1,21 @@
1
+ module Ruhl
2
+ class Plugin < ActionView::TemplateHandler
3
+
4
+ def initialize(action_view)
5
+ @action_view = action_view
6
+ end
7
+
8
+ def render(template, options)
9
+ layout = @action_view.controller.send(:active_layout)
10
+
11
+ puts "==========> @action_view: #{@action_view.controller.response.inspect}"
12
+ puts "==========> template: #{template.inspect}"
13
+ puts "==========> options: #{options.inspect}"
14
+ end
15
+ end
16
+ end
17
+
18
+ ActionView::Template.register_template_handler(:ruhl, Ruhl::Plugin)
19
+
20
+ ActionView::Template.exempt_from_layout(:ruhl)
21
+
@@ -0,0 +1,29 @@
1
+ require 'ruhl'
2
+
3
+ module Sinatra
4
+ module Templates
5
+ def ruhl(template, options = {}, locals = {})
6
+ require_warn('Ruhl') unless defined?(::Ruhl::Engine)
7
+
8
+ render :ruhl, template, options, locals
9
+ end
10
+
11
+ private
12
+
13
+ def render(engine, template, options={}, locals={})
14
+ # merge app-level options
15
+ options = self.class.send(engine).merge(options) if self.class.respond_to?(engine)
16
+
17
+ views = options.delete(:views) || self.class.views || "./views"
18
+
19
+ # render template
20
+ data, options[:filename], options[:line] = lookup_template(engine, template, views)
21
+
22
+ __send__("render_#{engine}", template, data, options)
23
+ end
24
+
25
+ def render_ruhl(template, data, options)
26
+ ::Ruhl::Engine.new(data, options).render(self)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruhl}
8
+ s.version = "0.6.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andrew Stone"]
12
+ s.date = %q{2009-10-07}
13
+ s.description = %q{Make your HTML dynamic with the addition of a ruby attribute.}
14
+ s.email = %q{andy@stonean.com}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "lib/ruhl.rb",
24
+ "lib/ruhl/errors.rb",
25
+ "lib/ruhl/rails.rb",
26
+ "lib/ruhl/sinatra.rb",
27
+ "ruhl.gemspec",
28
+ "spec/html/basic.html",
29
+ "spec/html/fragment.html",
30
+ "spec/html/if.html",
31
+ "spec/html/layout.html",
32
+ "spec/html/main_with_sidebar.html",
33
+ "spec/html/medium.html",
34
+ "spec/html/render_if.html",
35
+ "spec/html/seo.html",
36
+ "spec/html/sidebar.html",
37
+ "spec/rcov.opts",
38
+ "spec/ruhl_spec.rb",
39
+ "spec/spec.opts",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/stonean/ruhl}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.5}
46
+ s.summary = %q{Ruby Hypertext Language}
47
+ s.test_files = [
48
+ "spec/ruhl_spec.rb",
49
+ "spec/spec_helper.rb"
50
+ ]
51
+
52
+ if s.respond_to? :specification_version then
53
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
+ s.specification_version = 3
55
+
56
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.3"])
58
+ s.add_development_dependency(%q<rspec>, [">= 0"])
59
+ else
60
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
61
+ s.add_dependency(%q<rspec>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
65
+ s.add_dependency(%q<rspec>, [">= 0"])
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>Hello World</title>
4
+ </head>
5
+ <body>
6
+ <h1 data-ruhl="generate_h1">I am a templated headline</h1>
7
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet lacinia metus. Nam sed dui est. Sed pellentesque aliquet massa, vel cursus arcu faucibus tincidunt. Nunc aliquet ultricies tellus sit amet elementum. Integer porttitor lorem dolor. Proin leo nunc, sollicitudin sed ullamcorper non, tempus non erat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed commodo sodales pharetra. Vivamus pharetra, augue a volutpat scelerisque, elit nisl auctor elit, quis mollis dolor urna in ligula. Aliquam nisi augue, adipiscing quis mollis ut, aliquam nec urna. Morbi faucibus semper ante ut dignissim. Maecenas et dui eros, eget tristique odio. Sed vehicula erat nec dui porttitor laoreet.</p>
8
+ </body>
9
+ </html>
@@ -0,0 +1,2 @@
1
+ <h1 data-ruhl="generate_h1">I am a templated headline</h1>
2
+ <p data-ruhl="my_content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet lacinia metus. Nam sed dui est. Sed pellentesque aliquet massa, vel cursus arcu faucibus tincidunt. Nunc aliquet ultricies tellus sit amet elementum. Integer porttitor lorem dolor. Proin leo nunc, sollicitudin sed ullamcorper non, tempus non erat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed commodo sodales pharetra. Vivamus pharetra, augue a volutpat scelerisque, elit nisl auctor elit, quis mollis dolor urna in ligula. Aliquam nisi augue, adipiscing quis mollis ut, aliquam nec urna. Morbi faucibus semper ante ut dignissim. Maecenas et dui eros, eget tristique odio. Sed vehicula erat nec dui porttitor laoreet.</p>
@@ -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>
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
+ </ul>
22
+ </body>
23
+ </html>
@@ -0,0 +1,8 @@
1
+ <html>
2
+ <head>
3
+ <title>This is a title template</title>
4
+ </head>
5
+ <body>
6
+ <div data-ruhl="_render_"></div>
7
+ </body>
8
+ </html>
@@ -0,0 +1,22 @@
1
+ <html>
2
+ <head>
3
+ <title>This is a title template</title>
4
+ </head>
5
+ <body>
6
+ <div id="wrap">
7
+ <div id="sidebar" data-ruhl="_partial: sidebar_partial">
8
+ <h3>Sidebar links</h3>
9
+ <ul>
10
+ <li><a href="#">Link 1</a></li>
11
+ <li><a href="#">Link 2</a></li>
12
+ <li><a href="#">Link 3</a></li>
13
+ <li><a href="#">Link 4</a></li>
14
+ </ul>
15
+ </div>
16
+ <div id="main">
17
+ <h1> My main content</h1>
18
+ <p>Text designers would put here to test their layout</p>
19
+ </div>
20
+ </div>
21
+ </body>
22
+ </html>
@@ -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>
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="email">andy@stonean.com</td>
19
+ </tr>
20
+ </table>
21
+ </ul>
22
+ </body>
23
+ </html>
@@ -0,0 +1,25 @@
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
+ <div data-ruhl="_render_if: has_users?">
8
+ <table>
9
+ <thead>
10
+ <tr>
11
+ <td>First Name</td>
12
+ <td>Last Name</td>
13
+ <td>Email</td>
14
+ </tr>
15
+ </thead>
16
+ <tr data-ruhl="_collection: user_list">
17
+ <td data-ruhl="first_name">Andrew</td>
18
+ <td data-ruhl="last_name">Stone</td>
19
+ <td data-ruhl="email">andy@stonean.com</td>
20
+ </tr>
21
+ </table>
22
+ </div>
23
+ </ul>
24
+ </body>
25
+ </html>
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <head>
3
+ <title>This is a title template</title>
4
+ <meta data-ruhl="content: generate_description" content='This is a description template' id='metaDescription' name='description' />
5
+ <meta data-ruhl="content: generate_keywords" content='these,are,template,keywords' id='metaKeywords' name='keywords' />
6
+ </head>
7
+ <body>
8
+ <h1 data-ruhl="generate_h1">I am a templated headline</h1>
9
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet lacinia metus. Nam sed dui est. Sed pellentesque aliquet massa, vel cursus arcu faucibus tincidunt. Nunc aliquet ultricies tellus sit amet elementum. Integer porttitor lorem dolor. Proin leo nunc, sollicitudin sed ullamcorper non, tempus non erat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed commodo sodales pharetra. Vivamus pharetra, augue a volutpat scelerisque, elit nisl auctor elit, quis mollis dolor urna in ligula. Aliquam nisi augue, adipiscing quis mollis ut, aliquam nec urna. Morbi faucibus semper ante ut dignissim. Maecenas et dui eros, eget tristique odio. Sed vehicula erat nec dui porttitor laoreet.</p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,7 @@
1
+ <h3>Real Sidebarlinks</h3>
2
+ <ul>
3
+ <li><a href="#">Real Link 1</a></li>
4
+ <li><a href="#">Real Link 2</a></li>
5
+ <li><a href="#">Real Link 3</a></li>
6
+ <li><a href="#">Real Link 4</a></li>
7
+ </ul>
@@ -0,0 +1,5 @@
1
+ --text-summary
2
+ --exclude
3
+ json,FakeWeb,rcov.rb,rspec,spec
4
+ --sort
5
+ coverage
@@ -0,0 +1,163 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ def generate_h1(tag = nil)
4
+ "data from presenter"
5
+ end
6
+
7
+ def data_from_method(tag = nil)
8
+ "I am data from a method"
9
+ end
10
+
11
+ def generate_description(tag = nil)
12
+ "I am a custom meta description"
13
+ end
14
+
15
+ def generate_keywords(tag = nil)
16
+ "I, am, custom, keywords"
17
+ end
18
+
19
+ def my_content(tag = nil)
20
+ "hello from my content."
21
+ end
22
+
23
+ def sidebar_partial(tag = nil)
24
+ html(:sidebar)
25
+ end
26
+
27
+ def user_list(tag = nil)
28
+ [
29
+ TestUser.new('Jane', 'Doe', 'jane@stonean.com'),
30
+ TestUser.new('John', 'Joe', 'john@stonean.com'),
31
+ TestUser.new('Jake', 'Smo', 'jake@stonean.com'),
32
+ TestUser.new('Paul', 'Tin', 'paul@stonean.com'),
33
+ TestUser.new('NoMail', 'Man')
34
+ ]
35
+ end
36
+
37
+ describe Ruhl do
38
+
39
+ describe "basic.html" do
40
+ before do
41
+ @html = File.read html(:basic)
42
+ end
43
+
44
+ it "content of p should be content from data_from_method" do
45
+ doc = create_doc
46
+ doc.xpath('//h1').first.content.should == generate_h1
47
+ end
48
+ end
49
+
50
+ describe "seo.html" do
51
+ before do
52
+ @html = File.read html(:seo)
53
+ end
54
+
55
+ it "meta keywords should be replaced" do
56
+ doc = create_doc
57
+ doc.xpath('//meta[@name="keywords"]').first['content'].
58
+ should == generate_keywords
59
+ end
60
+
61
+ it "meta title should be replaced" do
62
+ doc = create_doc
63
+ doc.xpath('//meta[@name="description"]').first['content'].
64
+ should == generate_description
65
+ end
66
+ end
67
+
68
+ describe "medium.html" do
69
+ before do
70
+ @html = File.read html(:medium)
71
+ @doc = create_doc
72
+ end
73
+
74
+ it "first data row should equal first user " do
75
+ table = @doc.xpath('/html/body/table/tr//td')
76
+ table.children[0].to_s.should == "Jane"
77
+ table.children[1].to_s.should == "Doe"
78
+ table.children[2].to_s.should == "jane@stonean.com"
79
+ end
80
+
81
+ it "last data row should equal last user " do
82
+ table = @doc.xpath('/html/body/table/tr//td')
83
+ table.children[9].to_s.should == "Paul"
84
+ table.children[10].to_s.should == "Tin"
85
+ table.children[11].to_s.should == "paul@stonean.com"
86
+ end
87
+ end
88
+
89
+ describe "fragment.html" do
90
+ before do
91
+ @html = File.read html(:fragment)
92
+ end
93
+
94
+ it "will be injected into layout.html" do
95
+ doc = create_doc( html(:layout) )
96
+ doc.xpath('//h1').should_not be_empty
97
+ doc.xpath('//p').should_not be_empty
98
+ end
99
+ end
100
+
101
+ describe "main_with_sidebar.html" do
102
+ before do
103
+ @html = File.read html(:main_with_sidebar)
104
+ end
105
+
106
+ it "should replace sidebar with partial contents" do
107
+ doc = create_doc
108
+ end
109
+ end
110
+
111
+ describe "if.html" do
112
+ before do
113
+ @html = File.read html(:if)
114
+ @doc = create_doc
115
+ end
116
+
117
+ it "first data row should equal first user " do
118
+ table = @doc.xpath('/html/body/table/tr//td')
119
+ table.children[0].to_s.should == "Jane"
120
+ table.children[1].to_s.should == "Doe"
121
+ table.children[2].to_s.should == "jane@stonean.com"
122
+ end
123
+
124
+ it "last data row should equal last user " do
125
+ table = @doc.xpath('/html/body/table/tr//td')
126
+ table.children[12].to_s.should == "NoMail"
127
+ table.children[13].to_s.should == "Man"
128
+ table.children[14].should == nil
129
+ end
130
+ end
131
+
132
+ describe "render if.html" do
133
+ it "table should not render" do
134
+ def has_users?(tag = nil)
135
+ false
136
+ end
137
+
138
+ @html = File.read html(:render_if)
139
+ @doc = create_doc
140
+ nodes = @doc.xpath('/html/body//*')
141
+ nodes.children.length.should == 1
142
+ nodes.children.to_s.should == "This is the header template"
143
+ end
144
+
145
+ it "table shouldrender" do
146
+ def has_users?(tag = nil)
147
+ true
148
+ end
149
+
150
+ @html = File.read html(:render_if)
151
+ @doc = create_doc
152
+ nodes = @doc.xpath('/html/body//*')
153
+ nodes.children.length.should > 1
154
+
155
+ table = @doc.xpath('/html/body/div/table/tr//td')
156
+ table.children[12].to_s.should == "NoMail"
157
+ table.children[13].to_s.should == "Man"
158
+ end
159
+ end
160
+ end
161
+
162
+
163
+
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format
3
+ progress
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib ruhl]))
2
+
3
+ def html(name)
4
+ File.join( File.dirname(__FILE__), 'html', "#{name}.html" )
5
+ end
6
+
7
+ def do_parse(html)
8
+ Nokogiri::HTML(html)
9
+ end
10
+
11
+ def create_doc(layout = nil)
12
+ options = {:layout => layout}
13
+ html = Ruhl::Engine.new(@html, :layout => layout).render(self)
14
+ do_parse(html)
15
+ end
16
+
17
+ class TestUser
18
+ attr_accessor :first_name, :last_name, :email
19
+
20
+ def initialize(first, last , email = nil)
21
+ @first_name = first
22
+ @last_name = last
23
+ @email = email
24
+ end
25
+ end
26
+
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruhl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Stone
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-07 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: nokogiri
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: Make your HTML dynamic with the addition of a ruby attribute.
36
+ email: andy@stonean.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ files:
44
+ - .gitignore
45
+ - README
46
+ - Rakefile
47
+ - VERSION
48
+ - lib/ruhl.rb
49
+ - lib/ruhl/errors.rb
50
+ - lib/ruhl/rails.rb
51
+ - lib/ruhl/sinatra.rb
52
+ - ruhl.gemspec
53
+ - spec/html/basic.html
54
+ - spec/html/fragment.html
55
+ - spec/html/if.html
56
+ - spec/html/layout.html
57
+ - spec/html/main_with_sidebar.html
58
+ - spec/html/medium.html
59
+ - spec/html/render_if.html
60
+ - spec/html/seo.html
61
+ - spec/html/sidebar.html
62
+ - spec/rcov.opts
63
+ - spec/ruhl_spec.rb
64
+ - spec/spec.opts
65
+ - spec/spec_helper.rb
66
+ has_rdoc: true
67
+ homepage: http://github.com/stonean/ruhl
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --charset=UTF-8
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ requirements: []
88
+
89
+ rubyforge_project:
90
+ rubygems_version: 1.3.5
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: Ruby Hypertext Language
94
+ test_files:
95
+ - spec/ruhl_spec.rb
96
+ - spec/spec_helper.rb