renee-render 0.0.1

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.md ADDED
@@ -0,0 +1,38 @@
1
+ # Renee Render
2
+
3
+ Rendering templates in Renee should be familiar and intuitive using the `render` command:
4
+
5
+ ```ruby
6
+ run Renee::Core.new {
7
+ path('blog') do
8
+ get { render! :haml, :"blogs/index" }
9
+ end
10
+ }
11
+ ```
12
+
13
+ This above is the standard render syntax, specifying the engine followed by the template. You can also render without specifying an engine:
14
+
15
+ ```ruby
16
+ path('blog') do
17
+ get { render! "blogs/index" }
18
+ end
19
+ ```
20
+
21
+ This will do a lookup in the views path to find the appropriately named template. You can also pass locals and layout options as you would expect:
22
+
23
+ ```ruby
24
+ path('blog') do
25
+ get { render! "blogs/index", :locals => { :foo => "bar" }, :layout => :bar }
26
+ end
27
+ ```
28
+
29
+ This will render the "blogs/index.erb" file if it exists, passing the 'foo' local variable
30
+ and wrapping the result in the 'bar.erb' layout file. You can also render without returning the response by using:
31
+
32
+ ```ruby
33
+ path('blog') do
34
+ get { render "blogs/index" }
35
+ end
36
+ ```
37
+
38
+ This allows you to render the content as a string without immediately responding.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push "lib"
6
+ t.test_files = FileList[File.expand_path('../test/**/*_test.rb', __FILE__)]
7
+ t.verbose = true
8
+ end
@@ -0,0 +1,6 @@
1
+ class Renee
2
+ module Render
3
+ # The version for the renee-render gem.
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
@@ -0,0 +1,136 @@
1
+ require 'tilt'
2
+
3
+ class Renee
4
+ # This module is responsible for handling the rendering of templates
5
+ # using Tilt supporting all included template engines.
6
+ module Render
7
+ ##
8
+ # Exception responsible for when a generic rendering error occurs.
9
+ #
10
+ class RenderError < RuntimeError; end
11
+
12
+ ##
13
+ # Exception responsible for when an expected template does not exist.
14
+ #
15
+ class TemplateNotFound < RenderError; end
16
+
17
+ # Same as render but automatically halts.
18
+ # @param (see #render)
19
+ # @return (see #render)
20
+ # @see #render
21
+ def render!(*args, &blk)
22
+ halt render(*args, &blk)
23
+ end
24
+
25
+ ##
26
+ # Renders a string given the engine and the content.
27
+ #
28
+ # @param [Symbol] engine The template engine to use for rendering.
29
+ # @param [String] data The content or file to render.
30
+ # @param [Hash] options The rendering options to pass onto tilt.
31
+ #
32
+ # @return [String] The result of rendering the data with specified engine.
33
+ #
34
+ # @example
35
+ # render :haml, "%p test" => "<p>test</p>"
36
+ # render :haml, :index => "<p>test</p>"
37
+ # render "index" => "<p>test</p>"
38
+ #
39
+ # @api public
40
+ #
41
+ def render(engine, data=nil, options={}, &block)
42
+ # Handles the case where engine is unspecified by shifting the data (i.e render "index")
43
+ engine, data, options = nil, engine.to_sym, data if data.nil? || data.is_a?(Hash)
44
+
45
+ options ||= {}
46
+ options[:outvar] ||= '@_out_buf'
47
+ # TODO allow default encoding to be set (as an option)
48
+ options[:default_encoding] ||= "utf-8"
49
+
50
+ locals = options.delete(:locals) || {}
51
+ views = options.delete(:views) || settings.views_path || "./views"
52
+ layout = options.delete(:layout)
53
+ layout_engine = options.delete(:layout_engine) || engine
54
+ # TODO suppress template errors for layouts?
55
+ # TODO allow content_type to be set with an option to render?
56
+ scope = options.delete(:scope) || self
57
+
58
+ # TODO default layout file convention?
59
+ template = compile_template(engine, data, options, views)
60
+ output = template.render(scope, locals, &block)
61
+
62
+ if layout # render layout
63
+ # TODO handle when layout is missing better!
64
+ options = options.merge(:views => views, :layout => false, :scope => scope)
65
+ return render(layout_engine, layout, options.merge(:locals => locals)) { output }
66
+ end
67
+
68
+ output
69
+ end # render
70
+
71
+ ##
72
+ # Constructs a template based on engine, data and options.
73
+ #
74
+ # @param [Symbol] engine The template engine to use for rendering.
75
+ # @param [String] data The content or file to render.
76
+ # @param [Hash] options The rendering options to pass onto tilt.
77
+ # @param [String] views The view_path from which to locate the template.
78
+ #
79
+ # @return [Tilt::Template] The tilt template to render with all required options.
80
+ # @raise [TemplateNotFound] The template to render could not be located.
81
+ # @raise [RenderError] The template to render could not be located.
82
+ #
83
+ # @api private
84
+ #
85
+ def compile_template(engine, data, options, views)
86
+ template_cache.fetch engine, data, options do
87
+ if data.is_a?(Symbol) # data is template path
88
+ file_path, engine = find_template(views, data, engine)
89
+ template = Tilt[engine]
90
+ raise TemplateNotFound, "Template engine not found: #{engine}" if template.nil?
91
+ raise TemplateNotFound, "Template '#{data}' not found in '#{views}'!" unless file_path
92
+ # TODO suppress errors for layouts?
93
+ template.new(file_path, 1, options)
94
+ elsif data.is_a?(String) # data is body string
95
+ # TODO figure out path based on caller file
96
+ path, line = options[:path] || "caller file", options[:line] || 1
97
+ body = data.is_a?(String) ? Proc.new { data } : data
98
+ template = Tilt[engine]
99
+ raise "Template engine not found: #{engine}" if template.nil?
100
+ template.new(path, line.to_i, options, &body)
101
+ else # data can't be handled
102
+ raise RenderError, "Cannot render data #{data.inspect}."
103
+ end
104
+ end # template_cache.fetch
105
+ end # compile_template
106
+
107
+ ##
108
+ # Searches view paths for template based on data and engine with rendering options.
109
+ # Supports finding a template without an engine.
110
+ #
111
+ # @param [String] views The view paths
112
+ # @param [String] name The name of the template
113
+ # @param [Symbol] engine The engine to use for rendering.
114
+ #
115
+ # @return [<String, Symbol>] An array of the file path and the engine.
116
+ #
117
+ # @example
118
+ # find_template("./views", "index", :erb) => ["path/to/index.erb", :erb]
119
+ # find_template("./views", "foo") => ["path/to/index.haml", :haml]
120
+ #
121
+ # @api private
122
+ #
123
+ def find_template(views, name, engine=nil)
124
+ lookup_ext = (engine || File.extname(name.to_s)[1..-1] || "*").to_s
125
+ base_name = name.to_s.chomp(".#{lookup_ext}")
126
+ file_path = Dir[File.join(views, "#{base_name}.#{lookup_ext}")].first
127
+ engine ||= File.extname(file_path)[1..-1].to_sym if file_path
128
+ [file_path, engine]
129
+ end # find_template
130
+
131
+ # Maintain Tilt::Cache of the templates.
132
+ def template_cache
133
+ @template_cache ||= Tilt::Cache.new
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "renee-render/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "renee-render"
7
+ s.version = Renee::Render::VERSION
8
+ s.authors = ["Josh Hull", "Nathan Esquenazi", "Arthur Chiu"]
9
+ s.email = ["joshbuddy@gmail.com", "nesquena@gmail.com", "mr.arthur.chiu@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{The super-friendly web framework rendering component}
12
+ s.description = %q{The super-friendly web framework rendering component.}
13
+
14
+ s.rubyforge_project = "renee"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency 'rack', "~> 1.3.0"
22
+ s.add_runtime_dependency 'tilt', "~> 1.3.3"
23
+ s.add_development_dependency 'minitest', "~> 2.6.1"
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'bundler', "~> 1.0.10"
26
+ s.add_development_dependency "rack-test", ">= 0.5.0"
27
+ s.add_development_dependency "haml", ">= 2.2.0"
28
+ end
@@ -0,0 +1,114 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe Renee::Render do
4
+ describe "#render" do
5
+ after { remove_views }
6
+
7
+ it "should allow rendering string with engine" do
8
+ mock_app {
9
+ path("/a") { get { render! :erb, "<p>test</p>" } }
10
+ path("/b") { get { render! :erb, "<p><%= foo %></p>", :locals => { :foo => "bar" } } }
11
+ path("/c") { get { halt render(:erb, "<p><%= foo %></p>", :locals => { :foo => "bar" }) } }
12
+ }
13
+ get('/a')
14
+ assert_equal 200, response.status
15
+ assert_equal "<p>test</p>", response.body
16
+ get('/b')
17
+ assert_equal 200, response.status
18
+ assert_equal "<p>bar</p>", response.body
19
+ get('/c')
20
+ assert_equal 200, response.status
21
+ assert_equal "<p>bar</p>", response.body
22
+ end # string, with engine
23
+
24
+ it "should allow rendering template file with engine" do
25
+ create_view :index, "%p test", :haml
26
+ create_view :foo, "%p= foo", :haml
27
+ mock_app {
28
+ path("/a") { get { render! :haml, :index } }
29
+ path("/b") { get { render! :haml, :foo, :locals => { :foo => "bar" } } }
30
+ path("/c") { get { halt render(:haml, :foo, :locals => { :foo => "bar" }) } }
31
+ }
32
+ get('/a')
33
+ assert_equal 200, response.status
34
+ assert_equal "<p>test</p>\n", response.body
35
+ get('/b')
36
+ assert_equal 200, response.status
37
+ assert_equal "<p>bar</p>\n", response.body
38
+ get('/c')
39
+ assert_equal 200, response.status
40
+ assert_equal "<p>bar</p>\n", response.body
41
+ end # template, with engine
42
+
43
+ it "should allow rendering template file with unspecified engine" do
44
+ create_view :index, "%p test", :haml
45
+ create_view :foo, "%p= foo", :haml
46
+ mock_app {
47
+ path("/a") { get { render! "index" } }
48
+ path("/b") { get { render! "foo.haml", :locals => { :foo => "bar" } } }
49
+ }
50
+ get('/a')
51
+ assert_equal 200, response.status
52
+ assert_equal "<p>test</p>\n", response.body
53
+ get('/b')
54
+ assert_equal 200, response.status
55
+ assert_equal "<p>bar</p>\n", response.body
56
+ end # template, unspecified engine
57
+
58
+ it "should allow rendering template file with engine and layout" do
59
+ create_view :index, "%p test", :haml
60
+ create_view :foo, "%p= foo", :haml
61
+ create_view :layout, "%div.wrapper= yield", :haml
62
+ mock_app {
63
+ path("/a") { get { render! :haml, :index, :layout => :layout } }
64
+ path("/b") { get { render! :foo, :layout => :layout, :locals => { :foo => "bar" } } }
65
+ }
66
+ get('/a')
67
+ assert_equal 200, response.status
68
+ assert_equal %Q{<div class='wrapper'><p>test</p></div>\n}, response.body
69
+ get('/b')
70
+ assert_equal 200, response.status
71
+ assert_equal %Q{<div class='wrapper'><p>bar</p></div>\n}, response.body
72
+ end # with engine and layout specified
73
+
74
+ it "should allow rendering template with different layout engines" do
75
+ create_view :index, "%p test", :haml
76
+ create_view :foo, "%p= foo", :haml
77
+ create_view :base, "<div class='wrapper'><%= yield %></div>", :erb
78
+ mock_app {
79
+ path("/a") { get { render! :haml, :index, :layout => :base, :layout_engine => :erb } }
80
+ path("/b") { get { render! :foo, :layout => :base, :locals => { :foo => "bar" } } }
81
+ }
82
+ get('/a')
83
+ assert_equal 200, response.status
84
+ assert_equal %Q{<div class='wrapper'><p>test</p>\n</div>}, response.body
85
+ get('/b')
86
+ assert_equal 200, response.status
87
+ assert_equal %Q{<div class='wrapper'><p>bar</p>\n</div>}, response.body
88
+ end # different layout and template engines
89
+
90
+ it "should fail properly rendering template file with invalid engine" do
91
+ create_view :index, "%p test", :haml
92
+ mock_app {
93
+ get { render! :fake, :index }
94
+ }
95
+ assert_raises(Renee::Render::TemplateNotFound) { get('/') }
96
+ end # template, invalid engine
97
+
98
+ it "should fail properly rendering missing template file with engine" do
99
+ create_view :index, "%p test", :haml
100
+ mock_app {
101
+ get { render! :haml, :foo }
102
+ }
103
+ assert_raises(Renee::Render::TemplateNotFound) { get('/') }
104
+ end # missing template, with engine
105
+
106
+ it "should fail properly rendering invalid data" do
107
+ create_view :index, "%p test", :haml
108
+ mock_app {
109
+ get { render! :haml, /invalid regex data/ }
110
+ }
111
+ assert_raises(Renee::Render::RenderError) { get('/') }
112
+ end # missing template, with engine
113
+ end
114
+ end
@@ -0,0 +1,10 @@
1
+ $: << File.expand_path('../../../renee-core/lib', __FILE__)
2
+ $: << File.expand_path('../../lib', __FILE__)
3
+ require 'renee-core'
4
+ require 'renee-render'
5
+
6
+ # TODO better registration method (?)
7
+ Renee::Core::Application.send(:include, Renee::Render)
8
+
9
+ # Load shared test helpers
10
+ require File.expand_path('../../../lib/test_helper', __FILE__)
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: renee-render
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Josh Hull
14
+ - Nathan Esquenazi
15
+ - Arthur Chiu
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-10-15 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 27
29
+ segments:
30
+ - 1
31
+ - 3
32
+ - 0
33
+ version: 1.3.0
34
+ requirement: *id001
35
+ type: :runtime
36
+ prerelease: false
37
+ name: rack
38
+ - !ruby/object:Gem::Dependency
39
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 29
45
+ segments:
46
+ - 1
47
+ - 3
48
+ - 3
49
+ version: 1.3.3
50
+ requirement: *id002
51
+ type: :runtime
52
+ prerelease: false
53
+ name: tilt
54
+ - !ruby/object:Gem::Dependency
55
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 21
61
+ segments:
62
+ - 2
63
+ - 6
64
+ - 1
65
+ version: 2.6.1
66
+ requirement: *id003
67
+ type: :development
68
+ prerelease: false
69
+ name: minitest
70
+ - !ruby/object:Gem::Dependency
71
+ version_requirements: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirement: *id004
81
+ type: :development
82
+ prerelease: false
83
+ name: rake
84
+ - !ruby/object:Gem::Dependency
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 1
93
+ - 0
94
+ - 10
95
+ version: 1.0.10
96
+ requirement: *id005
97
+ type: :development
98
+ prerelease: false
99
+ name: bundler
100
+ - !ruby/object:Gem::Dependency
101
+ version_requirements: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 11
107
+ segments:
108
+ - 0
109
+ - 5
110
+ - 0
111
+ version: 0.5.0
112
+ requirement: *id006
113
+ type: :development
114
+ prerelease: false
115
+ name: rack-test
116
+ - !ruby/object:Gem::Dependency
117
+ version_requirements: &id007 !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 7
123
+ segments:
124
+ - 2
125
+ - 2
126
+ - 0
127
+ version: 2.2.0
128
+ requirement: *id007
129
+ type: :development
130
+ prerelease: false
131
+ name: haml
132
+ description: The super-friendly web framework rendering component.
133
+ email:
134
+ - joshbuddy@gmail.com
135
+ - nesquena@gmail.com
136
+ - mr.arthur.chiu@gmail.com
137
+ executables: []
138
+
139
+ extensions: []
140
+
141
+ extra_rdoc_files: []
142
+
143
+ files:
144
+ - README.md
145
+ - Rakefile
146
+ - lib/renee-render.rb
147
+ - lib/renee-render/version.rb
148
+ - renee-render.gemspec
149
+ - test/render_test.rb
150
+ - test/test_helper.rb
151
+ homepage: ""
152
+ licenses: []
153
+
154
+ post_install_message:
155
+ rdoc_options: []
156
+
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ none: false
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ hash: 3
165
+ segments:
166
+ - 0
167
+ version: "0"
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ hash: 3
174
+ segments:
175
+ - 0
176
+ version: "0"
177
+ requirements: []
178
+
179
+ rubyforge_project: renee
180
+ rubygems_version: 1.8.10
181
+ signing_key:
182
+ specification_version: 3
183
+ summary: The super-friendly web framework rendering component
184
+ test_files:
185
+ - test/render_test.rb
186
+ - test/test_helper.rb