stonean-ruhl 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/README +48 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/lib/ruhl.rb +52 -0
- data/lib/ruhl/errors.rb +3 -0
- data/lib/ruhl/sinatra.rb +15 -0
- data/spec/html/basic.html +9 -0
- data/spec/html/medium.html +12 -0
- data/spec/html/seo.html +11 -0
- data/spec/rcov.opts +5 -0
- data/spec/ruhl_spec.rb +68 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +15 -0
- metadata +68 -0
data/.gitignore
ADDED
data/README
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
Ruhl (Ruby Hypertext Language)
|
2
|
+
|
3
|
+
This project is here to flesh out an idea. What I want is to have developers work with HTML and with the simple addition of a 'ruby' attribute, convert it to a dynamic page.
|
4
|
+
|
5
|
+
At no time in the dev process would the view be unviewable in a browser. The view could actually retain the original template data the designer used because this replaces the content. I think this is a nice plus.
|
6
|
+
|
7
|
+
|
8
|
+
Notes (use cases) for me to remember:
|
9
|
+
|
10
|
+
##############################################################################
|
11
|
+
|
12
|
+
<ul id="aab" ruby="present_results">
|
13
|
+
<li>Lorem ipsum dolor sit amet</li>
|
14
|
+
<li>consectetur adipiscing elit</li>
|
15
|
+
</ul>
|
16
|
+
|
17
|
+
Method :present_results would know how to represent itself in the context of the ul element. In other words, it would know how to produce <li> elements.
|
18
|
+
|
19
|
+
|
20
|
+
##############################################################################
|
21
|
+
|
22
|
+
<h1 ruby="page_header">
|
23
|
+
|
24
|
+
Method :page_header would know how to represent itself in the context of the h1 element.
|
25
|
+
|
26
|
+
The ruby executed would replace the content of the element it was being called on.
|
27
|
+
|
28
|
+
|
29
|
+
##############################################################################
|
30
|
+
|
31
|
+
<meta ruby="content: meta_description" content='This is a description template' id='metaDescription' name='description' />
|
32
|
+
|
33
|
+
content: meta_description is telling the parser to replace attribute 'content' with results from meta_description method.
|
34
|
+
|
35
|
+
|
36
|
+
##############################################################################
|
37
|
+
|
38
|
+
Things to note:
|
39
|
+
|
40
|
+
1) The ruby attribute is always removed from the output.
|
41
|
+
2) Each method called must accept a tag parameter.
|
42
|
+
e.g def page_header(tag)
|
43
|
+
|
44
|
+
TODO:
|
45
|
+
|
46
|
+
1) Work on supporting templates (shouldn't be hard)
|
47
|
+
2) Work on supporting partials (shouldn't be hard)
|
48
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
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
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
29
|
+
end
|
30
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/ruhl.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'ruhl/errors'
|
5
|
+
|
6
|
+
module Ruhl
|
7
|
+
class Engine
|
8
|
+
attr_reader :doc, :scope
|
9
|
+
|
10
|
+
def initialize(html)
|
11
|
+
@doc = Nokogiri::HTML(html)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render(current_scope)
|
15
|
+
set_scope(current_scope)
|
16
|
+
|
17
|
+
doc.xpath('//*[@ruby]').each do |tag|
|
18
|
+
code = tag['ruby']
|
19
|
+
|
20
|
+
if code =~ /^\w+:/
|
21
|
+
process_attribute(tag,code)
|
22
|
+
else
|
23
|
+
tag.inner_html = execute_ruby(tag,code)
|
24
|
+
end
|
25
|
+
|
26
|
+
tag.remove_attribute('ruby')
|
27
|
+
end
|
28
|
+
|
29
|
+
doc.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def process_attribute(tag,code)
|
35
|
+
parts = code.split(';')
|
36
|
+
parts.each do |pair|
|
37
|
+
attribute, value = pair.split(':')
|
38
|
+
|
39
|
+
tag[attribute] = execute_ruby(tag, value.strip)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_scope(current_scope)
|
44
|
+
raise Ruhl::NoScopeError unless current_scope
|
45
|
+
@scope = current_scope
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute_ruby(tag, code)
|
49
|
+
scope.send(code, tag)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/ruhl/errors.rb
ADDED
data/lib/ruhl/sinatra.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Templates
|
3
|
+
def ruhl(template, options = {}, locals = {})
|
4
|
+
require_warn('Ruhl') unless defined?(::Ruhl::Engine)
|
5
|
+
|
6
|
+
render :ruhl, template, options, locals
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def render_ruhl(template, data, options, locals, &block)
|
12
|
+
::Ruhl::Engine.new(data).render(self)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Hello World</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<h1 ruby="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>
|
data/spec/html/seo.html
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>This is a title template</title>
|
4
|
+
<meta ruby="content: generate_description" content='This is a description template' id='metaDescription' name='description' />
|
5
|
+
<meta ruby="content: generate_keywords" content='these,are,template,keywords' id='metaKeywords' name='keywords' />
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1 ruby="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>
|
data/spec/rcov.opts
ADDED
data/spec/ruhl_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
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 present_results(tag = nil)
|
20
|
+
"<li>line item 1</li><li>line item 2</li>"
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Ruhl do
|
24
|
+
|
25
|
+
describe "basic.html" do
|
26
|
+
before do
|
27
|
+
@html = File.read html(:basic)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "content of p should be content from data_from_method" do
|
31
|
+
doc = create_doc
|
32
|
+
doc.xpath('//h1').first.content.should == generate_h1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "seo.html" do
|
37
|
+
before do
|
38
|
+
@html = File.read html(:seo)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "meta keywords should be replaced" do
|
42
|
+
doc = create_doc
|
43
|
+
doc.xpath('//meta[@name="keywords"]').first['content'].
|
44
|
+
should == generate_keywords
|
45
|
+
end
|
46
|
+
|
47
|
+
it "meta title should be replaced" do
|
48
|
+
doc = create_doc
|
49
|
+
doc.xpath('//meta[@name="description"]').first['content'].
|
50
|
+
should == generate_description
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "medium.html" do
|
55
|
+
before do
|
56
|
+
@html = File.read html(:medium)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "ul content should have new li's" do
|
60
|
+
doc = create_doc
|
61
|
+
ul = doc.xpath('//ul').first
|
62
|
+
ul.inner_html.should == "<li>line item 1</li>\n<li>line item 2</li>\n"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
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
|
12
|
+
html = Ruhl::Engine.new(@html).render(self)
|
13
|
+
do_parse(html)
|
14
|
+
end
|
15
|
+
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stonean-ruhl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Stone
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Make your HTML dynamic with the addition of a ruby attribute.
|
17
|
+
email: andy@stonean.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- README
|
27
|
+
- Rakefile
|
28
|
+
- VERSION
|
29
|
+
- lib/ruhl.rb
|
30
|
+
- lib/ruhl/errors.rb
|
31
|
+
- lib/ruhl/sinatra.rb
|
32
|
+
- spec/html/basic.html
|
33
|
+
- spec/html/medium.html
|
34
|
+
- spec/html/seo.html
|
35
|
+
- spec/rcov.opts
|
36
|
+
- spec/ruhl_spec.rb
|
37
|
+
- spec/spec.opts
|
38
|
+
- spec/spec_helper.rb
|
39
|
+
has_rdoc: false
|
40
|
+
homepage: http://github.com/stonean/ruhl
|
41
|
+
licenses:
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Ruby Hypertext Language
|
66
|
+
test_files:
|
67
|
+
- spec/ruhl_spec.rb
|
68
|
+
- spec/spec_helper.rb
|