Skip to content

Commit

Permalink
added support for layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Stone committed Sep 18, 2009
1 parent dac3e4a commit 33f0df3
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 31 deletions.
60 changes: 46 additions & 14 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,27 @@ At no time in the dev process would the view be unviewable in a browser. The vi

Notes (use cases) for me to remember:

##############################################################################
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: Basic Use ::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<h1 ruby="page_header">

Method :page_header would know how to represent itself in the context of the h1 element.

The ruby executed would replace the content of the element it was being called on.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: Replacing attribute values ::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<meta ruby="content: meta_description" content='This is a description template' id='metaDescription' name='description' />

content: meta_description is telling the parser to replace attribute 'content' with results from meta_description method.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: Don't use iterators in views ::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<ul id="aab" ruby="present_results">
<li>Lorem ipsum dolor sit amet</li>
Expand All @@ -16,26 +36,36 @@ Notes (use cases) for me to remember:

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.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: Using a Layout ::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

##############################################################################

<h1 ruby="page_header">

Method :page_header would know how to represent itself in the context of the h1 element.

The ruby executed would replace the content of the element it was being called on.
Layout:
<html>
<head>
<title>This is a title template</title>
</head>
<body>
<div ruby="_render_"></div>
</body>
</html>

Fragment:
<h1 ruby="generate_h1">I am a templated headline</h1>
<p ruby="my_content">Lorem ipsum dolor sit amet</p>

##############################################################################
To use:

<meta ruby="content: meta_description" content='This is a description template' id='metaDescription' name='description' />
Ruhl::Engine.new(File.read(fragment), :layout => path_to_layout).render(self)

content: meta_description is telling the parser to replace attribute 'content' with results from meta_description method.
Returns the expected result of parsed Layout w/ parsed Fragment. Note the use of the _render_ method. This is a 'special' method that Ruhl uses to inject the results of the parsed fragment into the layout.


##############################################################################
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: Notes ::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Things to note:
* No eval (I don't think eval is evil, it's just not the way this works)

* The ruby attribute is always removed from the output.

Expand All @@ -46,7 +76,9 @@ Things to note:
au BufNewFile,BufRead *.ruhl set filetype=html


TODO:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:: TODO ::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1) Work on supporting templates (shouldn't be hard)
2) Work on supporting partials (shouldn't be hard)
Expand Down
64 changes: 50 additions & 14 deletions lib/ruhl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,36 @@

module Ruhl
class Engine
attr_reader :doc, :scope
attr_reader :document, :scope, :layout

def initialize(html)
@doc = Nokogiri::HTML(html)
def initialize(html, options = {})
if @layout = options[:layout]
raise LayoutNotFoundError.new(@layout) unless File.exists?(@layout)

@document = Nokogiri::HTML.fragment(html)
else
@document = Nokogiri::HTML(html)
end
end

def render(current_scope)
set_scope(current_scope)

doc.xpath('//*[@ruby]').each do |tag|
code = tag['ruby']

if code =~ /^\w+:/
process_attribute(tag,code)
else
tag.inner_html = execute_ruby(tag,code)
end
parse_doc(@document)

tag.remove_attribute('ruby')
if @layout
render_with_layout
else
document.to_s
end
end

doc.to_s
# The _render_ method is used within a layout to inject
# the results of the template render.
#
# Ruhl::Engine.new(html, :layout => path_to_layout).render(self)
def _render_
document.to_s
end

private
Expand All @@ -40,13 +48,41 @@ def process_attribute(tag,code)
end
end

def render_with_layout
doc = Nokogiri::HTML( File.read(@layout) )
parse_doc(doc)
doc.to_s
end

def parse_doc(doc)
if (nodes = doc.xpath('//*[@ruby]')).empty?
nodes = doc.xpath('*[@ruby]')
end

nodes.each do |tag|
code = tag['ruby']

if code =~ /^\w+:/
process_attribute(tag,code)
else
tag.inner_html = execute_ruby(tag,code)
end

tag.remove_attribute('ruby')
end
end

def set_scope(current_scope)
raise Ruhl::NoScopeError unless current_scope
@scope = current_scope
end

def execute_ruby(tag, code)
scope.send(code, tag)
unless code == '_render_'
scope.send(code, tag)
else
_render_
end
end
end
end
1 change: 1 addition & 0 deletions lib/ruhl/errors.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
module Ruhl
class LayoutNotFoundError < StandardError; end
class NoScopeError < StandardError; end
end
2 changes: 1 addition & 1 deletion lib/ruhl/sinatra.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def ruhl(template, options = {}, locals = {})
private

def render_ruhl(template, data, options, locals, &block)
::Ruhl::Engine.new(data).render(self)
::Ruhl::Engine.new(data, options).render(self)
end
end
end
2 changes: 2 additions & 0 deletions spec/html/fragment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h1 ruby="generate_h1">I am a templated headline</h1>
<p ruby="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>
8 changes: 8 additions & 0 deletions spec/html/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<title>This is a title template</title>
</head>
<body>
<div ruby="_render_"></div>
</body>
</html>
16 changes: 16 additions & 0 deletions spec/ruhl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def present_results(tag = nil)
"<li>line item 1</li><li>line item 2</li>"
end

def my_content(tag = nil)
"hello from my content."
end

describe Ruhl do

describe "basic.html" do
Expand Down Expand Up @@ -62,6 +66,18 @@ def present_results(tag = nil)
ul.inner_html.should == "<li>line item 1</li>\n<li>line item 2</li>\n"
end
end

describe "fragment.html" do
before do
@html = File.read html(:fragment)
end

it "will be injected into layout.html" do
doc = create_doc( html(:layout) )
puts '*'*40
puts doc.to_s
end
end
end


Expand Down
5 changes: 3 additions & 2 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ def do_parse(html)
Nokogiri::HTML(html)
end

def create_doc
html = Ruhl::Engine.new(@html).render(self)
def create_doc(layout = nil)
options = {:layout => layout}
html = Ruhl::Engine.new(@html, :layout => layout).render(self)
do_parse(html)
end

0 comments on commit 33f0df3

Please sign in to comment.