wrapt 0.1.0
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/Users/dneighman/Projects/wrapt/Gemfile +15 -0
- data/Users/dneighman/Projects/wrapt/Gemfile.lock +80 -0
- data/Users/dneighman/Projects/wrapt/LICENSE +20 -0
- data/Users/dneighman/Projects/wrapt/README.textile +162 -0
- data/Users/dneighman/Projects/wrapt/Rakefile +45 -0
- data/Users/dneighman/Projects/wrapt/VERSION +1 -0
- data/Users/dneighman/Projects/wrapt/lib/wrapt.rb +7 -0
- data/Users/dneighman/Projects/wrapt/lib/wrapt/helpers.rb +6 -0
- data/Users/dneighman/Projects/wrapt/lib/wrapt/layout.rb +132 -0
- data/Users/dneighman/Projects/wrapt/lib/wrapt/layout_context.rb +9 -0
- data/Users/dneighman/Projects/wrapt/lib/wrapt/wrapt.rb +175 -0
- data/Users/dneighman/Projects/wrapt/spec/alt_layouts/second.html.haml +1 -0
- data/Users/dneighman/Projects/wrapt/spec/layouts/first.html.haml +1 -0
- data/Users/dneighman/Projects/wrapt/spec/layouts/multiple.html.haml +3 -0
- data/Users/dneighman/Projects/wrapt/spec/layouts/other.html.haml +4 -0
- data/Users/dneighman/Projects/wrapt/spec/layouts/wrapper.html.haml +4 -0
- data/Users/dneighman/Projects/wrapt/spec/layouts/wrapper.jsonp.erb +2 -0
- data/Users/dneighman/Projects/wrapt/spec/layouts/wrapper.xml.haml +4 -0
- data/Users/dneighman/Projects/wrapt/spec/spec.opts +1 -0
- data/Users/dneighman/Projects/wrapt/spec/spec_helper.rb +11 -0
- data/Users/dneighman/Projects/wrapt/spec/wrapt_spec.rb +245 -0
- data/Users/dneighman/Projects/wrapt/wrapt.gemspec +23 -0
- metadata +118 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gem 'tilt', :git => 'git://github.com/hassox/tilt.git', :branch => :hassox
|
4
|
+
gem 'any_view', :git => 'git://github.com/hassox/any_view.git'
|
5
|
+
|
6
|
+
gem 'hashie'
|
7
|
+
|
8
|
+
group(:test) do
|
9
|
+
gem 'rspec'
|
10
|
+
gem 'rack'
|
11
|
+
gem 'ZenTest'
|
12
|
+
gem 'haml'
|
13
|
+
gem 'rake'
|
14
|
+
gem 'jeweler'
|
15
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
---
|
2
|
+
dependencies:
|
3
|
+
ZenTest:
|
4
|
+
group:
|
5
|
+
- :test
|
6
|
+
version: ">= 0"
|
7
|
+
haml:
|
8
|
+
group:
|
9
|
+
- :test
|
10
|
+
version: ">= 0"
|
11
|
+
any_view:
|
12
|
+
group:
|
13
|
+
- :default
|
14
|
+
version: ">= 0"
|
15
|
+
rake:
|
16
|
+
group:
|
17
|
+
- :test
|
18
|
+
version: ">= 0"
|
19
|
+
hashie:
|
20
|
+
group:
|
21
|
+
- :default
|
22
|
+
version: ">= 0"
|
23
|
+
rspec:
|
24
|
+
group:
|
25
|
+
- :test
|
26
|
+
version: ">= 0"
|
27
|
+
rack:
|
28
|
+
group:
|
29
|
+
- :test
|
30
|
+
version: ">= 0"
|
31
|
+
jeweler:
|
32
|
+
group:
|
33
|
+
- :test
|
34
|
+
version: ">= 0"
|
35
|
+
tilt:
|
36
|
+
group:
|
37
|
+
- :default
|
38
|
+
version: ">= 0"
|
39
|
+
specs:
|
40
|
+
- rake:
|
41
|
+
version: 0.8.7
|
42
|
+
- ZenTest:
|
43
|
+
version: 4.3.1
|
44
|
+
- tilt:
|
45
|
+
version: "0.9"
|
46
|
+
source: 1
|
47
|
+
- any_view:
|
48
|
+
version: 0.2.0pre
|
49
|
+
source: 0
|
50
|
+
- json_pure:
|
51
|
+
version: 1.4.2
|
52
|
+
- gemcutter:
|
53
|
+
version: 0.5.0
|
54
|
+
- git:
|
55
|
+
version: 1.2.5
|
56
|
+
- haml:
|
57
|
+
version: 2.2.24
|
58
|
+
- hashie:
|
59
|
+
version: 0.2.0
|
60
|
+
- rubyforge:
|
61
|
+
version: 2.0.4
|
62
|
+
- jeweler:
|
63
|
+
version: 1.4.0
|
64
|
+
- rack:
|
65
|
+
version: 1.1.0
|
66
|
+
- rspec:
|
67
|
+
version: 1.3.0
|
68
|
+
hash: 5219adb34705354844440dcaeead99c7e6b271c5
|
69
|
+
sources:
|
70
|
+
- Git:
|
71
|
+
uri: git://github.com/hassox/any_view.git
|
72
|
+
git: git://github.com/hassox/any_view.git
|
73
|
+
ref: e1db4990883427eb634ae824ef95928f4ca51415
|
74
|
+
- Git:
|
75
|
+
uri: git://github.com/hassox/tilt.git
|
76
|
+
branch: :hassox
|
77
|
+
git: git://github.com/hassox/tilt.git
|
78
|
+
ref: 8c652c803c1a62ec9854e1c320bee58c40546349
|
79
|
+
- Rubygems:
|
80
|
+
uri: http://gemcutter.org
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Daniel Neighman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,162 @@
|
|
1
|
+
h1. Wrapt
|
2
|
+
|
3
|
+
Wrapt is a rack middleware that provides facilities to any rack application for wrapping the content in a consistent layout.
|
4
|
+
|
5
|
+
Wrapt is intended to sit out the front of a rack graph (but doesn't have to), and is only activated when a downstream application asks to be wrapped in a layout. This means that disparate rack applications that have been mounted, may share the same layout and appear to belong to a single application.
|
6
|
+
|
7
|
+
Wrapt injects a layout object into the Rack environment which is idle until activated. To activeate, just assign it some content, and return it as the body portion of your response.
|
8
|
+
|
9
|
+
h2. Example
|
10
|
+
|
11
|
+
Declare your middleware stack
|
12
|
+
<pre><code lang='ruby'>use Wrapt
|
13
|
+
run MyApp
|
14
|
+
</code></pre>
|
15
|
+
|
16
|
+
Get your application using the wrapt layout
|
17
|
+
<pre><code>class MyApp
|
18
|
+
def self.call(env)
|
19
|
+
new.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
layout = env['layout']
|
24
|
+
layout.content = "This is the content of my app"
|
25
|
+
Rack::Response.new(layout).finish
|
26
|
+
end
|
27
|
+
end
|
28
|
+
</code></pre>
|
29
|
+
|
30
|
+
Say our layout file looked like this:
|
31
|
+
|
32
|
+
<pre><code>%html
|
33
|
+
%body
|
34
|
+
= yield
|
35
|
+
</code></pre>
|
36
|
+
|
37
|
+
We would end up with:
|
38
|
+
|
39
|
+
<pre><code lang='html'><html>
|
40
|
+
<body>
|
41
|
+
This is the content of my app
|
42
|
+
</body>
|
43
|
+
</html>
|
44
|
+
</code></pre>
|
45
|
+
|
46
|
+
h2. Layout Files
|
47
|
+
|
48
|
+
Wrapt is built on "Tilt":http://github.com/rtomayko/tilt Any tilt compatible template is usable.
|
49
|
+
|
50
|
+
A layout file is one that is constructed for use with a layout. To fill in the content into the layout template, you 'yield'.
|
51
|
+
|
52
|
+
h3. Template Location
|
53
|
+
|
54
|
+
By default, wrapt will look in the following palces for your layout templates:
|
55
|
+
|
56
|
+
* layouts
|
57
|
+
* views/layouts
|
58
|
+
* app/views/layouts
|
59
|
+
|
60
|
+
You can customize this by passing an array of directory locations to wrapt when declaring the middleware.
|
61
|
+
|
62
|
+
<pre><code>use Wrapt do |wrapt|
|
63
|
+
wrapt.layout_dirs = ["/path/to/my/layouts", "/fallback/path/to/layouts"]
|
64
|
+
end
|
65
|
+
</code></pre>
|
66
|
+
|
67
|
+
Directories are checked in order and the first template found is used.
|
68
|
+
|
69
|
+
h3. Template Naming
|
70
|
+
|
71
|
+
Templates follow a simple naming convention.
|
72
|
+
|
73
|
+
<pre><code><template_name>.<format>.<template_type></code></pre>
|
74
|
+
|
75
|
+
For example. The default template name is "application" with a default format of "html". This will match anything then of the form "application.html"
|
76
|
+
|
77
|
+
And will render the layout, inserting the content in the right spot.
|
78
|
+
|
79
|
+
You can define the name of the default template when declaring the middleware
|
80
|
+
|
81
|
+
<pre><code>use Wrapt do |wrapt|
|
82
|
+
wrapt.default_template = "my_default_layout"
|
83
|
+
end
|
84
|
+
</code></pre>
|
85
|
+
|
86
|
+
You can also select the layout to use inside a request. The following sets the layout for all downstream applications as 'special' (unless it's changed downstream')
|
87
|
+
|
88
|
+
<pre><code>def call(env)
|
89
|
+
layout = env['layout']
|
90
|
+
|
91
|
+
layout.template_name = "special"
|
92
|
+
app.call(env)
|
93
|
+
end
|
94
|
+
</code></pre>
|
95
|
+
|
96
|
+
h3. Format
|
97
|
+
|
98
|
+
Layouts are associated with a format. By default the format is html. Tempaltes are selected by their name with <name>.<format>.<template_type>.
|
99
|
+
|
100
|
+
You can select a default format when declaring the middleware
|
101
|
+
|
102
|
+
<pre><code>use Wrapt do |wrapt|
|
103
|
+
wrapt.default_format = :json
|
104
|
+
end
|
105
|
+
</code></pre>
|
106
|
+
|
107
|
+
Or in the request
|
108
|
+
<pre><code>def call(env)
|
109
|
+
layout = env['layout']
|
110
|
+
layout.format = :json
|
111
|
+
layout.content = {:my => "hash"}.to_json
|
112
|
+
end
|
113
|
+
</code></pre>
|
114
|
+
|
115
|
+
h3. Content Sections
|
116
|
+
|
117
|
+
Wrapt allows you to have different sections of content. To declare this:
|
118
|
+
|
119
|
+
<pre><code>layout.content = "foo" # main content
|
120
|
+
layout.set_content_for(:nav, "some navigation")
|
121
|
+
</code></pre>
|
122
|
+
|
123
|
+
Once that content is set, you may then use it in the layout by yielding to the layout.
|
124
|
+
|
125
|
+
<pre><code>%h1 My Layout
|
126
|
+
= yield # yields the main content
|
127
|
+
|
128
|
+
%nav
|
129
|
+
= yield :nav # yields the content with the label :nav
|
130
|
+
</code></pre>
|
131
|
+
|
132
|
+
h3. Helpers
|
133
|
+
|
134
|
+
You can include any helpers you need into the layout by including them into
|
135
|
+
|
136
|
+
Wrapt::Helpers
|
137
|
+
|
138
|
+
h3. Wrapping content on demand
|
139
|
+
|
140
|
+
You can use the layouter object to wrap content on demand
|
141
|
+
|
142
|
+
<pre><code>def call(env)
|
143
|
+
layout = env['layout']
|
144
|
+
wrapped_content = layout.wrap("my content", :layout => :inner_layout, :format => :json)
|
145
|
+
layout.content = wrapped_content
|
146
|
+
Rack::Response(layout).finish
|
147
|
+
end
|
148
|
+
</code></pre>
|
149
|
+
|
150
|
+
h2. Note on Patches/Pull Requests
|
151
|
+
|
152
|
+
* Fork the project.
|
153
|
+
* Make your feature addition or bug fix.
|
154
|
+
* Add tests for it. This is important so I don't break it in a
|
155
|
+
future version unintentionally.
|
156
|
+
* Commit, do not mess with rakefile, version, or history.
|
157
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
158
|
+
* Send me a pull request. Bonus points for topic branches.
|
159
|
+
|
160
|
+
h2. Copyright
|
161
|
+
|
162
|
+
Copyright (c) 2010 Daniel Neighman. See LICENSE for details.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "wrapt"
|
8
|
+
gem.summary = %Q{TODO: one-line summary of your gem}
|
9
|
+
gem.description = %Q{TODO: longer description of your gem}
|
10
|
+
gem.email = "has.sox@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/hassox/wrapt"
|
12
|
+
gem.authors = ["Daniel Neighman"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "wrapt #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,132 @@
|
|
1
|
+
class Wrapt
|
2
|
+
class Layout
|
3
|
+
include Enumerable
|
4
|
+
attr_accessor :wrapt, :env, :template_name, :format
|
5
|
+
|
6
|
+
def initialize(wrapt, env)
|
7
|
+
@env = env
|
8
|
+
@wrapt = wrapt
|
9
|
+
@content_for = Hashie::Mash.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Is the wrapt instance that created this layouter set as a master?
|
13
|
+
# @see Wrapt#master?
|
14
|
+
def master?
|
15
|
+
@wrapt.master?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Gets the format that this layouter has been set to.
|
19
|
+
# Defaults to the default_format of the wrapt instance
|
20
|
+
#
|
21
|
+
# May be set with Wrapt::Layout#format=
|
22
|
+
#
|
23
|
+
# @see Wrapt#default_format
|
24
|
+
def format
|
25
|
+
@format ||= @wrapt.default_format
|
26
|
+
end
|
27
|
+
|
28
|
+
# Gets the template name that this layouter has.
|
29
|
+
# Defaults to the wrapts instances default_template
|
30
|
+
#
|
31
|
+
# May be set with Wrapt::Layout#default_template=
|
32
|
+
#
|
33
|
+
# @see Wrapt.default_template
|
34
|
+
def template_name
|
35
|
+
@template_name ||= @wrapt.default_template
|
36
|
+
end
|
37
|
+
|
38
|
+
# Wraps the given content into the layout using the same base
|
39
|
+
# as the layouter currently has
|
40
|
+
#
|
41
|
+
# @params [String] content The content to form the main body of the layout
|
42
|
+
# @params [Hash] opts an options hash
|
43
|
+
# @option opts [String|Symbol] :layout the name of a layout template to use
|
44
|
+
# @option opts [String|Symbol] :format the format of the layout template to use
|
45
|
+
# @api public
|
46
|
+
def wrap(content, opts={})
|
47
|
+
layout = self.dup
|
48
|
+
|
49
|
+
layout.format = opts[:format] if opts[:format]
|
50
|
+
layout.template_name = opts[:layout] if opts[:layout]
|
51
|
+
|
52
|
+
layout.content = content
|
53
|
+
layout.map.join
|
54
|
+
end
|
55
|
+
|
56
|
+
def dup
|
57
|
+
dupped = super
|
58
|
+
dupped.instance_variable_set('@content_for', Hashie::Mash.new)
|
59
|
+
dupped
|
60
|
+
end
|
61
|
+
|
62
|
+
# Set the content for the layout for the given label
|
63
|
+
# @param [Symbol] label The label to identify the content to insert
|
64
|
+
# @param [String] content The content to set for this label
|
65
|
+
# @block The return of the block is used as preference. Block is optional
|
66
|
+
#
|
67
|
+
# @see Wrapt::Layout#content_for
|
68
|
+
# @api public
|
69
|
+
def set_content_for(label = :content, content = nil)
|
70
|
+
if block_given?
|
71
|
+
content = block.call
|
72
|
+
end
|
73
|
+
|
74
|
+
content_for[label] = content
|
75
|
+
end
|
76
|
+
|
77
|
+
# Provides access to the content_for hash.
|
78
|
+
# Content may be accessed for concatination etc
|
79
|
+
#
|
80
|
+
# When using content_for you can provide different contents for you layouts.
|
81
|
+
# The default content label is :content
|
82
|
+
# @example
|
83
|
+
# # In your application
|
84
|
+
# layout = env['layout']
|
85
|
+
# layout.set_content_for(:foo, "Foo Content")
|
86
|
+
# layout.content = "Normal Content"
|
87
|
+
#
|
88
|
+
#
|
89
|
+
# # In the layout
|
90
|
+
# <%= yield %> <-- inserts the content labeled :content
|
91
|
+
# <%= yield :content %> <-- insert the content labeled :content
|
92
|
+
# <%= yield :foo %> <-- insert the content labled :foo
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
def content_for
|
96
|
+
@content_for
|
97
|
+
end
|
98
|
+
|
99
|
+
# Set the main content for the layout
|
100
|
+
# @api public
|
101
|
+
def content=(content)
|
102
|
+
set_content_for(:content, content)
|
103
|
+
end
|
104
|
+
|
105
|
+
# An easy method to get the wrapped results
|
106
|
+
# @api public
|
107
|
+
def to_s
|
108
|
+
map.join
|
109
|
+
end
|
110
|
+
|
111
|
+
# The interface for rack.
|
112
|
+
# @api public
|
113
|
+
def each
|
114
|
+
opts = {}
|
115
|
+
opts[:format] ||= format
|
116
|
+
template = template_name
|
117
|
+
|
118
|
+
template = @wrapt.template(template, opts)
|
119
|
+
|
120
|
+
output = if template
|
121
|
+
template.render(LayoutContext.new) do |*args|
|
122
|
+
label = args.first || :content
|
123
|
+
content_for[label]
|
124
|
+
end
|
125
|
+
else
|
126
|
+
content_for[:content]
|
127
|
+
end
|
128
|
+
yield output
|
129
|
+
output
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Wrapt
|
2
|
+
# The context used within the layouts
|
3
|
+
# Anything that is required to be avaible in the view context should be included into the Helpers module, or the LayoutContext
|
4
|
+
# @see Wrapt::Helpers
|
5
|
+
class LayoutContext
|
6
|
+
include Tilt::CompileSite
|
7
|
+
include Helpers
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# Wrapt is a specialised middleware that wraps content in a given layout
|
2
|
+
#
|
3
|
+
# Wrapt injects an object into the environment which you can use to provide content to.
|
4
|
+
# When you're done, return the wrapt object as the body for your request and the layout will be applied.
|
5
|
+
#
|
6
|
+
# You can pass variables through the rack through the environment via the 'request.variables' key which will be a hash like object
|
7
|
+
#
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# def call(e)
|
12
|
+
# wrapt = e['layout']
|
13
|
+
# wrapt.content = "Here's some content"
|
14
|
+
# [200, {"Content-Type" => "text/html"}, wrapt]
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Produces:
|
18
|
+
# <!-- wrapping layout -->
|
19
|
+
# Here's some content
|
20
|
+
# <!-- footer wrapping layout -->
|
21
|
+
#
|
22
|
+
# A layout directory may be specified that points to any layouts that are to be used.
|
23
|
+
#
|
24
|
+
# A format may be specified for the layout if it is intended not to use html.
|
25
|
+
# Simply tell wrapt the format to use via the +format=+ method.
|
26
|
+
#
|
27
|
+
# If you don't want a layout, simply don't use the wrapt object.
|
28
|
+
class Wrapt
|
29
|
+
|
30
|
+
# Wrapt is initialized as middleware in a Rack stack
|
31
|
+
# @block the wrapt instance is passed to the block for further configuration
|
32
|
+
# You can set layout template directories,
|
33
|
+
# Default format, default layout or declare the layouter as the "master"
|
34
|
+
#
|
35
|
+
# @see Wrapt#master!
|
36
|
+
# @see Wrapt#layout_dirs
|
37
|
+
# @see Wrapt#default_format
|
38
|
+
# @see Wrapt#default_template
|
39
|
+
def initialize(app)
|
40
|
+
@app = app
|
41
|
+
@master = false
|
42
|
+
yield self if block_given?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Declare this wrapt instance to be the master
|
46
|
+
# This will mean that all downstream wrapt instances will be ignored
|
47
|
+
# and this layouter will be used for the entire downstream graph
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def master!
|
51
|
+
@master = true
|
52
|
+
end
|
53
|
+
|
54
|
+
# Checks to see if this layouter is a master
|
55
|
+
# @api private
|
56
|
+
def master?
|
57
|
+
!!@master
|
58
|
+
end
|
59
|
+
|
60
|
+
def call(env)
|
61
|
+
env['request.variables'] ||= Hashie::Mash.new
|
62
|
+
layout = env['layout']
|
63
|
+
if !layout || (layout && !layout.master?)
|
64
|
+
env['layout'] = Layout.new(self, env)
|
65
|
+
end
|
66
|
+
r = @app.call(env) # just return what the app returns… If it wants a layout, it will return it.
|
67
|
+
env['layout'] = layout if layout
|
68
|
+
r
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set the layout directories
|
72
|
+
# These are the directories that wrapt will inspect (in order) when it attempts to find the given layouts
|
73
|
+
# @param [Array] dirs An array of directories where wrapt should look to find the layout templates
|
74
|
+
# @api public
|
75
|
+
def layout_dirs=(dirs)
|
76
|
+
@layout_dirs = Array.new(dirs).flatten
|
77
|
+
end
|
78
|
+
|
79
|
+
# Provides access to the directories where wrapt will inspect to find the layouts
|
80
|
+
# @api public
|
81
|
+
# @return [Array] An array of directories that wrapt will look in for template files
|
82
|
+
def layout_dirs
|
83
|
+
@layout_dirs ||= begin
|
84
|
+
[
|
85
|
+
File.join(Dir.pwd, "layouts"),
|
86
|
+
File.join(Dir.pwd, "views/layouts"),
|
87
|
+
File.join(Dir.pwd, "app/views/layouts")
|
88
|
+
]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# The default template name wrapt will use when none is specified
|
93
|
+
# @api public
|
94
|
+
# @return [String] default template name
|
95
|
+
def default_template
|
96
|
+
@default_template ||= "application"
|
97
|
+
end
|
98
|
+
|
99
|
+
# set the default template
|
100
|
+
# @api public
|
101
|
+
# @see Wrapt#default_template
|
102
|
+
def default_template=(name)
|
103
|
+
@default_template = name
|
104
|
+
end
|
105
|
+
|
106
|
+
# Get the default format that has been defined for the instance of wrapt
|
107
|
+
#
|
108
|
+
# The format is used by default in the template file name.
|
109
|
+
# The default naming convention for the template name is
|
110
|
+
# <template_name>.<format>.<template_type>
|
111
|
+
#
|
112
|
+
# @example
|
113
|
+
# application.html.haml
|
114
|
+
# @api public
|
115
|
+
def default_format
|
116
|
+
@default_format ||= :html
|
117
|
+
end
|
118
|
+
|
119
|
+
# Set the default format for this instance of wrapt
|
120
|
+
# @see Wrapt#default_format
|
121
|
+
# @api public
|
122
|
+
def default_format=(format)
|
123
|
+
@default_format = format
|
124
|
+
end
|
125
|
+
|
126
|
+
# Fetches the named template with any given options
|
127
|
+
#
|
128
|
+
# @param [String|Symbol] The template name to fetch
|
129
|
+
# @param [Hash] opts
|
130
|
+
# @option opts [String|Symbol] :format Provide the format for the template that will be used
|
131
|
+
# @return [Tilt::Template|NilClass] A template file to use to render the layout
|
132
|
+
# @api public
|
133
|
+
def template(name, opts={})
|
134
|
+
format = opts.fetch(:format, default_format)
|
135
|
+
template_name = template_name_and_format_glob(name,format, opts)
|
136
|
+
|
137
|
+
return _template_cache[template_name] if _template_cache[template_name]
|
138
|
+
|
139
|
+
file = nil
|
140
|
+
layout_dirs.detect do |dir|
|
141
|
+
file = Dir[File.join(dir, template_name)].first
|
142
|
+
end
|
143
|
+
|
144
|
+
if file.nil?
|
145
|
+
nil
|
146
|
+
else
|
147
|
+
_template_cache[template_name] = Tilt.new(file)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
# Calculates the relative filename of the template
|
153
|
+
# @param [String|Symbol] name The template name
|
154
|
+
# @param [String|Symbol] format The template format
|
155
|
+
# @param [Hash] opts An options hash that is provided to the template method
|
156
|
+
#
|
157
|
+
# @see Wrapt#template
|
158
|
+
# @api overwritable
|
159
|
+
def template_name_and_format(name, format, opts)
|
160
|
+
"#{name}.#{format}"
|
161
|
+
end
|
162
|
+
|
163
|
+
# Provides a glob from the template_name_and_format to look up the file from
|
164
|
+
# @api private
|
165
|
+
def template_name_and_format_glob(name, format, opts)
|
166
|
+
"#{template_name_and_format(name,format,opts)}.*"
|
167
|
+
end
|
168
|
+
|
169
|
+
# A cache for the template files so that they're only loaded once
|
170
|
+
# @api private
|
171
|
+
def _template_cache
|
172
|
+
@cache ||= {}
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
%h1 Second (Alternative)
|
@@ -0,0 +1 @@
|
|
1
|
+
%h1 Layout: First
|
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Wrapt do
|
4
|
+
before(:all) do
|
5
|
+
unless defined?(SpecWraptApp)
|
6
|
+
SpecWraptApp = lambda do |e|
|
7
|
+
msg = $message || "ok"
|
8
|
+
layout = e['layout']
|
9
|
+
|
10
|
+
out = if layout
|
11
|
+
layout.content = msg
|
12
|
+
layout
|
13
|
+
else
|
14
|
+
msg
|
15
|
+
end
|
16
|
+
Rack::Response.new(out).finish
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def layouts_dirs
|
22
|
+
[File.join(File.dirname(__FILE__), "layouts")]
|
23
|
+
end
|
24
|
+
|
25
|
+
def alt_layouts_dirs
|
26
|
+
[File.join(File.dirname(__FILE__), "alt_layouts")]
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "defining the middleware" do
|
30
|
+
before do
|
31
|
+
@wrapt = Wrapt.new(SpecWraptApp){|w| w.default_template = "wrapper"}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow me to define the directories to use to find the templates" do
|
35
|
+
w = Wrapt.new(SpecWraptApp)
|
36
|
+
w.layout_dirs = layouts_dirs
|
37
|
+
w.layout_dirs.should == layouts_dirs
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should allow me to set the layout_dirs in the middleware" do
|
41
|
+
w = Wrapt.new(SpecWraptApp) do |wrapt|
|
42
|
+
wrapt.layout_dirs = layouts_dirs
|
43
|
+
end
|
44
|
+
w.layout_dirs.should == layouts_dirs
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should provide me with the Dir.pwd/layouts as the default location to find layouts" do
|
48
|
+
@wrapt.layout_dirs.should == [
|
49
|
+
File.join(Dir.pwd, "layouts"),
|
50
|
+
File.join(Dir.pwd, "views/layouts"),
|
51
|
+
File.join(Dir.pwd, "app/views/layouts")
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should use the 'application' template by default" do
|
56
|
+
wrapt = Wrapt.new(SpecWraptApp)
|
57
|
+
wrapt.default_template.should == "application"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should allow me to set my own default template" do
|
61
|
+
@wrapt.default_template = "my_template"
|
62
|
+
@wrapt.default_template.should == "my_template"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should allow me to set a default format" do
|
66
|
+
@wrapt.default_format = :json
|
67
|
+
@wrapt.default_format.should == :json
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have a default format of :html" do
|
71
|
+
@wrapt.default_format.should == :html
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should provide a hook for me to work out the format to use"
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "managing templates" do
|
78
|
+
before do
|
79
|
+
@wrapt = Wrapt.new(SpecWraptApp) do |w|
|
80
|
+
w.layout_dirs = layouts_dirs
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should find me a template of a given name with the format for the current request" do
|
85
|
+
@wrapt.template(:first).should be_a_kind_of(Tilt::Template)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return nil when there is no format found of that name" do
|
89
|
+
@wrapt.template("not_a_real_template").should be_nil
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return nil when there is no format found of that format" do
|
93
|
+
@wrapt.template(:first, :format => :no_real_forma).should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should search all the layout directories provided to return the template" do
|
97
|
+
@wrapt = Wrapt.new(SpecWraptApp) do |w|
|
98
|
+
w.layout_dirs = layouts_dirs + alt_layouts_dirs
|
99
|
+
end
|
100
|
+
@wrapt.template(:second).should be_a_kind_of(Tilt::Template)
|
101
|
+
@wrapt.template(:second).render.should match(/Second \(Alternative\)/)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "injecting into the environment" do
|
106
|
+
before do
|
107
|
+
@wrapt = Wrapt.new(SpecWraptApp){|w| w.default_template = :wrapper}
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should inject a Wrapt::Layout object into the environment" do
|
111
|
+
env = {}
|
112
|
+
@wrapt.call(env)
|
113
|
+
env['layout'].should be_an_instance_of(Wrapt::Layout)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should make sure there's a request.variables key in the env" do
|
117
|
+
env = {}
|
118
|
+
@wrapt.call(env)
|
119
|
+
vars = env['request.variables']
|
120
|
+
vars.should_not be_nil
|
121
|
+
vars.should respond_to(:[])
|
122
|
+
vars.should respond_to(:[]=)
|
123
|
+
vars.should respond_to(:clear)
|
124
|
+
vars.should respond_to(:keys)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should allow me to define an upstream wrapt as the master, meaning it won't be replaced by any downstream ones" do
|
128
|
+
env = Rack::MockRequest.env_for("/")
|
129
|
+
@wrapt.master!
|
130
|
+
wrapt2 = Wrapt.new(SpecWraptApp) do |wrapt|
|
131
|
+
wrapt.default_format = :jsonp
|
132
|
+
wrapt.default_template = :wrapper
|
133
|
+
end
|
134
|
+
|
135
|
+
@wrapt.call(env)
|
136
|
+
r = wrapt2.call(env)
|
137
|
+
|
138
|
+
layout = env['layout']
|
139
|
+
result = r[2].body.to_s
|
140
|
+
result.should_not include("{ content")
|
141
|
+
layout.wrapt.should == @wrapt
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should allow me to define an upstream wrapt and a downstream, and have the downstream one work downstream and the upstream one work upstream" do
|
145
|
+
env = Rack::MockRequest.env_for("/")
|
146
|
+
|
147
|
+
wrapt2 = Wrapt.new(SpecWraptApp) do |wrapt|
|
148
|
+
wrapt.default_format = :jsonp
|
149
|
+
wrapt.default_template = :wrapper
|
150
|
+
wrapt.layout_dirs = layouts_dirs
|
151
|
+
end
|
152
|
+
|
153
|
+
s = @wrapt.call(env)
|
154
|
+
r = wrapt2.call(env)
|
155
|
+
|
156
|
+
result = r[2].body.to_s
|
157
|
+
result.should include("{ content")
|
158
|
+
layout = env['layout']
|
159
|
+
layout.wrapt.should == @wrapt
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe Wrapt::Layout do
|
164
|
+
before(:all) do
|
165
|
+
unless defined?(WraptApp)
|
166
|
+
WraptApp = lambda do |e|
|
167
|
+
layout = e['layout']
|
168
|
+
layout.content = $msg || "ok"
|
169
|
+
Rack::Response.new(layout).finish
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
before do
|
175
|
+
@wrapt = Wrapt.new(WraptApp) do |w|
|
176
|
+
w.layout_dirs = layouts_dirs
|
177
|
+
w.default_template = "wrapper"
|
178
|
+
end
|
179
|
+
|
180
|
+
@env = Rack::MockRequest.env_for("/")
|
181
|
+
@wrapt.call(@env)
|
182
|
+
@layout = @env['layout']
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "on demand" do
|
186
|
+
it "should wrap content on demand" do
|
187
|
+
result = @layout.wrap("Hi There")
|
188
|
+
result.should include("Hi There")
|
189
|
+
result.should include("<h1>Wrapper Template</h1>")
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should wrap the content with a different layout" do
|
193
|
+
result = @layout.wrap("Hi There", :layout => :other)
|
194
|
+
result.should include("Other Template")
|
195
|
+
result.should include("Hi There")
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should wrap the content with a different format" do
|
199
|
+
result = @layout.wrap("Hi There", :format => :xml)
|
200
|
+
result.should include("<h1>Wrapper Template XML</h1>")
|
201
|
+
result.should include("Hi There")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should allow me to set the content" do
|
206
|
+
@layout.content = "This is some content of mine"
|
207
|
+
result = @layout.map.join
|
208
|
+
result.should include("This is some content of mine")
|
209
|
+
result.should include("<h1>Wrapper Template</h1>")
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should allow me to set the format of a request" do
|
213
|
+
@layout.format = :xml
|
214
|
+
result = @layout.map.join
|
215
|
+
result.should include("<h1>Wrapper Template XML</h1>")
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should ask the middleware for the format if no format is set" do
|
219
|
+
@wrapt = Wrapt.new(WraptApp) do |w|
|
220
|
+
w.layout_dirs = layouts_dirs
|
221
|
+
w.default_template = "wrapper"
|
222
|
+
w.default_format = :jsonp
|
223
|
+
end
|
224
|
+
@env = Rack::MockRequest.env_for("/")
|
225
|
+
@wrapt.call(@env)
|
226
|
+
@layout = @env['layout']
|
227
|
+
@layout.content = "json data"
|
228
|
+
result = @layout.map.join
|
229
|
+
result.should include("{ content: 'json data' }")
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should provide me with the wrapped layout with to_s" do
|
233
|
+
@layout.to_s.should == @layout.map.join
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should yield multiple contents" do
|
237
|
+
@layout.content = "Main Content"
|
238
|
+
@layout.set_content_for(:foo, "Foo Content")
|
239
|
+
@layout.template_name = "multiple"
|
240
|
+
result = @layout.to_s
|
241
|
+
result.should include("<div class='content'>Main Content</div>")
|
242
|
+
result.should include("<div class='foo'>Foo Content</div>")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = %q{wrapt}
|
6
|
+
s.version = "0.1.0"
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.authors = ["Daniel Neighman"]
|
10
|
+
s.date = %q{2010-04-30}
|
11
|
+
s.description = %q{Layouts in rack}
|
12
|
+
s.summary = %q{Layouts in rack}
|
13
|
+
s.homepage = %q{http://github.com/hassox/wrapt}
|
14
|
+
s.email = %q{has.sox@gmail.com}
|
15
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubygems_version = %q{1.3.6}
|
18
|
+
|
19
|
+
s.files = Dir[File.join(Dir.pwd, "**/*")]
|
20
|
+
|
21
|
+
s.add_bundler_dependencies
|
22
|
+
end
|
23
|
+
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wrapt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Daniel Neighman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-30 00:00:00 +10:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
segments:
|
26
|
+
- 0
|
27
|
+
version: "0"
|
28
|
+
name: any_view
|
29
|
+
prerelease: false
|
30
|
+
requirement: *id001
|
31
|
+
type: :runtime
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
segments:
|
38
|
+
- 0
|
39
|
+
version: "0"
|
40
|
+
name: hashie
|
41
|
+
prerelease: false
|
42
|
+
requirement: *id002
|
43
|
+
type: :runtime
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
segments:
|
50
|
+
- 0
|
51
|
+
version: "0"
|
52
|
+
name: tilt
|
53
|
+
prerelease: false
|
54
|
+
requirement: *id003
|
55
|
+
type: :runtime
|
56
|
+
description: Layouts in rack
|
57
|
+
email: has.sox@gmail.com
|
58
|
+
executables: []
|
59
|
+
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
extra_rdoc_files: []
|
63
|
+
|
64
|
+
files:
|
65
|
+
- /Users/dneighman/Projects/wrapt/Gemfile
|
66
|
+
- /Users/dneighman/Projects/wrapt/Gemfile.lock
|
67
|
+
- /Users/dneighman/Projects/wrapt/lib/wrapt/helpers.rb
|
68
|
+
- /Users/dneighman/Projects/wrapt/lib/wrapt/layout.rb
|
69
|
+
- /Users/dneighman/Projects/wrapt/lib/wrapt/layout_context.rb
|
70
|
+
- /Users/dneighman/Projects/wrapt/lib/wrapt/wrapt.rb
|
71
|
+
- /Users/dneighman/Projects/wrapt/lib/wrapt.rb
|
72
|
+
- /Users/dneighman/Projects/wrapt/LICENSE
|
73
|
+
- /Users/dneighman/Projects/wrapt/Rakefile
|
74
|
+
- /Users/dneighman/Projects/wrapt/README.textile
|
75
|
+
- /Users/dneighman/Projects/wrapt/spec/alt_layouts/second.html.haml
|
76
|
+
- /Users/dneighman/Projects/wrapt/spec/layouts/first.html.haml
|
77
|
+
- /Users/dneighman/Projects/wrapt/spec/layouts/multiple.html.haml
|
78
|
+
- /Users/dneighman/Projects/wrapt/spec/layouts/other.html.haml
|
79
|
+
- /Users/dneighman/Projects/wrapt/spec/layouts/wrapper.html.haml
|
80
|
+
- /Users/dneighman/Projects/wrapt/spec/layouts/wrapper.jsonp.erb
|
81
|
+
- /Users/dneighman/Projects/wrapt/spec/layouts/wrapper.xml.haml
|
82
|
+
- /Users/dneighman/Projects/wrapt/spec/spec.opts
|
83
|
+
- /Users/dneighman/Projects/wrapt/spec/spec_helper.rb
|
84
|
+
- /Users/dneighman/Projects/wrapt/spec/wrapt_spec.rb
|
85
|
+
- /Users/dneighman/Projects/wrapt/VERSION
|
86
|
+
- /Users/dneighman/Projects/wrapt/wrapt.gemspec
|
87
|
+
has_rdoc: true
|
88
|
+
homepage: http://github.com/hassox/wrapt
|
89
|
+
licenses: []
|
90
|
+
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options:
|
93
|
+
- --charset=UTF-8
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.3.6
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Layouts in rack
|
117
|
+
test_files: []
|
118
|
+
|