armadillo 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.
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: []