armadillo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 076e70fe3bf56b1ff58d780add8495daec39c332
4
+ data.tar.gz: 3a0c4f3c77fa0d215c622647d7ce99506a9d2228
5
+ SHA512:
6
+ metadata.gz: 6abcaa901422e65f838fafe28ebd2c39c29f65d089157fa5b7bb38df037581fe8f9c294fa0456dc501aca27b418cbf7364dcaeec3e97f31e470ef824f6e00267
7
+ data.tar.gz: 058695378b0a9f846a1081f929b57ad832b267b1bc3eec8f79f3740d175d90ff74a58f378074c6d2e8d9d4c8b8b9afbaee6fb37221711c3fdbdc71cbb95c343d
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Sebastian Borrazas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ Armadillo
2
+ =========
3
+
4
+ A small library for [Django-like template inheritance](https://docs.djangoproject.com/en/dev/topics/templates/#template-inheritance)
5
+ adapted for ERB.
6
+
7
+ Usage
8
+ -----
9
+
10
+ To render an Armadillo template you need to call the `Armadillo.render` method.
11
+
12
+ This method accepts any of the following options:
13
+ * `:scope` - Any object you want to bound to the template scope.
14
+ * `:base_path` - The path of the directory for which the templates are going to
15
+ be searched on.
16
+
17
+ Note: A `.erb` extension is assumed for every file and should not be part of
18
+ the filename given as the template filename.
19
+
20
+
21
+ ```ruby
22
+ Armadillo.render("myview.html", { :items => [1, 2, 3] }, {
23
+ :base_path => File.join(Dir.pwd, "views"),
24
+ :scope => self
25
+ })
26
+ ```
27
+
28
+ ```erb
29
+ <!-- views/myview.html.erb -->
30
+ <% extends("base.html") %>
31
+
32
+ <% vlock(:title) do %>
33
+ <%= current_user.name %>
34
+ <% end %>
35
+
36
+ <% vlock(:body) do %>
37
+ <ul>
38
+ <% items.each do |item| %>
39
+ <li><%= item %></li>
40
+ <% end %>
41
+ </ul>
42
+ <% end %>
43
+
44
+ <!-- views/base.html.erb -->
45
+ <!DOCTYPE>
46
+ <html>
47
+ <title><% vlock(:title) %> - MyApp</title>
48
+ <body>
49
+ <% vlock(:body) %>
50
+ </body>
51
+ </html>
52
+ ```
53
+
54
+ ### Usage example using Cuba
55
+
56
+ ```ruby
57
+ module View
58
+ def render_view(template_name, locals = {})
59
+ content = Armadillo.render(template_name, locals, {
60
+ :base_path => File.join(APP_PATH, "views"),
61
+ :scope => self
62
+ })
63
+ res.write(content)
64
+ halt(res.finish)
65
+ end
66
+ end
67
+
68
+ on get, root do
69
+ render_view("main/index.html", {
70
+ :items => [1, 2, 3]
71
+ })
72
+ end
73
+ ```
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "rake/testtask"
2
+
3
+ desc "Run all tests"
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.pattern = "./spec/**/*_spec.rb"
6
+ t.verbose = false
7
+ end
data/armadillo.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "armadillo"
3
+ s.version = "0.0.1"
4
+ s.summary = "Template inheritance with ERB templates"
5
+ s.description = "A small library for Django-like template inheritance adapted for ERB"
6
+ s.authors = ["Sebastian Borrazas"]
7
+ s.email = ["seba.borrazas@gmail.com"]
8
+ s.homepage = "http://github.com/sborrazas/armadillo"
9
+ s.license = "MIT"
10
+
11
+ s.files = Dir[
12
+ "LICENSE",
13
+ "README.md",
14
+ "Rakefile",
15
+ "lib/**/*.rb",
16
+ "*.gemspec",
17
+ "spec/*.*"
18
+ ]
19
+
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "tilt"
23
+
24
+ end
data/lib/armadillo.rb ADDED
@@ -0,0 +1,171 @@
1
+ require "tilt"
2
+ require "delegate"
3
+
4
+ module Armadillo
5
+
6
+ VERSION = "0.0.1"
7
+
8
+ DEFAULT_OPTIONS = {
9
+ :default_encoding => Encoding.default_external,
10
+ :outvar => "@_output"
11
+ }
12
+
13
+ # @api private
14
+ class TemplateContext < SimpleDelegator
15
+
16
+ # Extend the specified template in which the inner view blocks will be
17
+ # rendered.
18
+ #
19
+ # @note
20
+ # This is a template instruction.
21
+ #
22
+ # @param template_path [String]
23
+ # @param locals [Hash]
24
+ def extends(template_path, locals = {})
25
+ @extends_data = [template_path, locals]
26
+ end
27
+
28
+ # Determine the contents or specify the place in which the view block will
29
+ # be rendered.
30
+ #
31
+ # @note
32
+ # This is a template instruction.
33
+ #
34
+ # @param block_name [Symbol]
35
+ # @param block [Block]
36
+ def vlock(block_name, &block)
37
+ raise "Invalid vlock usage" unless current_frame
38
+
39
+ if extends?
40
+ raise "No block given" unless block_given?
41
+
42
+ current_frame[:vlocks][block_name] = block
43
+ elsif (frame = get_frame(block_name, current_frame))
44
+ temporary_frame(frame[:parent_frame]) do
45
+ frame[:vlocks][block_name].call
46
+ end
47
+ elsif block_given?
48
+ block.call
49
+ end
50
+ end
51
+
52
+ # Create a new frame with previous frame as parent.
53
+ def create_frame
54
+ @current_frame = {
55
+ :vlocks => {},
56
+ :parent_frame => current_frame
57
+ }
58
+ end
59
+
60
+ # Determine if the current template should extend from a new template.
61
+ #
62
+ # @return [Boolean]
63
+ def extends?
64
+ !! @extends_data
65
+ end
66
+
67
+ # Return and delete the extract data.
68
+ #
69
+ # @return [Array<(String, Hash)>]
70
+ # The extended template name and the locals.
71
+ def extract_extends_data
72
+ @extends_data.tap { @extends_data = nil }
73
+ end
74
+
75
+ private
76
+
77
+ # Get the current frame. Each frame contains the blocks specified using
78
+ # #vlock and its parent frame.
79
+ #
80
+ # @return [Hash]
81
+ def current_frame
82
+ @current_frame
83
+ end
84
+
85
+ # Create a temporary current frame for the block to be executed.
86
+ #
87
+ # @param frame [Hash]
88
+ # @param block [Block]
89
+ def temporary_frame(frame, &block)
90
+ old = current_frame
91
+ @current_frame = frame
92
+ block.call
93
+ @current_frame = old
94
+ end
95
+
96
+ # Get the block from the frames stack by its name.
97
+ #
98
+ # @param block_name [Symbol]
99
+ def get_frame(block_name, frame)
100
+ if frame[:vlocks].has_key?(block_name)
101
+ frame
102
+ elsif frame[:parent_frame]
103
+ get_frame(block_name, frame[:parent_frame])
104
+ end
105
+ end
106
+ end
107
+
108
+ # Render the erb template.
109
+ #
110
+ # @param template_path [String]
111
+ # @param locals [Hash]
112
+ # @option options [Object] :scope (Object.new)
113
+ # Any object you want to bound to the template scope.
114
+ # @option options [String, nil] :base_path (nil)
115
+ # The path of the directory for which the templates are going to be
116
+ # searched on.
117
+ #
118
+ # @note
119
+ # options also accepts any options offered by the Erubis templating system.
120
+ #
121
+ # @return [String]
122
+ # @api public
123
+ def self.render(template_path, locals = {}, options = {})
124
+ scope = options.fetch(:scope) { Object.new }
125
+ context = TemplateContext.new(scope)
126
+ _render(template_path, locals, context, options)
127
+ end
128
+
129
+ # Render the erb template with the given context.
130
+ #
131
+ # @param template_path [String]
132
+ # @param context [Armadillo::TemplateContext]
133
+ # @param locals [Hash]
134
+ # @option options [String] :base_path (nil)
135
+ #
136
+ # @note
137
+ # options also accepts any options offered by the Erubis templating system.
138
+ #
139
+ # @api private
140
+ def self._render(template_path, locals, context, options)
141
+ context.create_frame
142
+ template_path = "#{template_path}.erb"
143
+ if (base_path = options.fetch(:base_path, nil))
144
+ template_path = File.join(base_path, template_path)
145
+ end
146
+ template = _templates_cache.fetch(template_path) do
147
+ Tilt.new(template_path, 1, DEFAULT_OPTIONS.merge(options))
148
+ end
149
+
150
+ content = template.render(context, locals)
151
+
152
+ if context.extends?
153
+ template_path, locals = context.extract_extends_data
154
+ content = _render(template_path, locals, context, options)
155
+ end
156
+
157
+ content
158
+ end
159
+ private_class_method :_render
160
+
161
+ # Get Tilt templates cache.
162
+ #
163
+ # @return [Tilt::Cache]
164
+ #
165
+ # @api private
166
+ def self._templates_cache
167
+ Thread.current[:tilt_cache] ||= Tilt::Cache.new
168
+ end
169
+ private_class_method :_templates_cache
170
+
171
+ end
@@ -0,0 +1,3 @@
1
+ require "minitest/spec"
2
+ require "minitest/autorun"
3
+ require "armadillo"
@@ -0,0 +1,81 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe Armadillo do
4
+
5
+ TEMPLATES_PATH = File.join(File.dirname(__FILE__), "templates")
6
+
7
+ def assert_lines_match(content, lines)
8
+ content_lines = content.split("\n")
9
+ lines.each do |line|
10
+ assert_includes(content_lines, line)
11
+ end
12
+ end
13
+
14
+ describe ".render" do
15
+ it "renders a regular erb template" do
16
+ locals = { :items => ["a", "b", "c"] }
17
+ content = Armadillo.render("basic.text", locals, {
18
+ :base_path => TEMPLATES_PATH
19
+ })
20
+ assert_lines_match(content, ["Basic", "a", "b", "c"])
21
+ end
22
+
23
+ it "renders a one-step inheritance template" do
24
+ content = Armadillo.render("one_step_1.text", {}, {
25
+ :base_path => TEMPLATES_PATH
26
+ })
27
+ assert_lines_match(content, ["Base", "Title", "Subtitle"])
28
+ end
29
+
30
+ it "allows parent templates to access locals from #extends" do
31
+ locals = { :items => ["a", "b", "c"] }
32
+
33
+ content = Armadillo.render("parent_locals_2.text", locals, {
34
+ :base_path => TEMPLATES_PATH
35
+ })
36
+ assert_lines_match(content, ["Base", locals[:items].first])
37
+ end
38
+
39
+ it "renders a two-step inheritance template" do
40
+ content = Armadillo.render("two_step_2.text", {}, {
41
+ :base_path => TEMPLATES_PATH
42
+ })
43
+ assert_lines_match(content, ["Base", "Title", "Subtitle"])
44
+ end
45
+
46
+ describe "when reusing child vlocks" do
47
+ it "renders them according to the inheritance" do
48
+ content = Armadillo.render("nested_two_step_2.text", {}, {
49
+ :base_path => TEMPLATES_PATH
50
+ })
51
+ assert_lines_match(content, ["Base", "Title - Subtitle"])
52
+ end
53
+ end
54
+
55
+ describe "when sending a scope object" do
56
+ it "access the object methods as locals" do
57
+ obj = Object.new
58
+ def obj.some_text
59
+ "text!"
60
+ end
61
+
62
+ content = Armadillo.render("scope_object.text", {}, {
63
+ :base_path => TEMPLATES_PATH,
64
+ :scope => obj
65
+ })
66
+ assert_lines_match(content, ["Base", obj.some_text])
67
+ end
68
+ end
69
+
70
+ describe "when sending :escape_html option" do
71
+ it "sanitizes the HTML by default" do
72
+ content = Armadillo.render("sanitized.html", {}, {
73
+ :base_path => TEMPLATES_PATH,
74
+ :escape_html => true
75
+ })
76
+ assert_lines_match(content, ["Sanitized &amp;", "Not sanitized &"])
77
+ end
78
+ end
79
+ end
80
+
81
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: armadillo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Borrazas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tilt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: A small library for Django-like template inheritance adapted for ERB
28
+ email:
29
+ - seba.borrazas@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - armadillo.gemspec
38
+ - lib/armadillo.rb
39
+ - spec/spec_helper.rb
40
+ - spec/template_spec.rb
41
+ homepage: http://github.com/sborrazas/armadillo
42
+ licenses:
43
+ - MIT
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 2.2.0
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: Template inheritance with ERB templates
65
+ test_files: []