wrapt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,7 @@
1
+ require 'hashie'
2
+ require 'tilt'
3
+
4
+ require 'wrapt/wrapt'
5
+ require 'wrapt/layout'
6
+ require 'wrapt/helpers'
7
+ require 'wrapt/layout_context'
@@ -0,0 +1,6 @@
1
+ class Wrapt
2
+ # Included in the LayoutContext.
3
+ # Mixin any helpers or methods into the Wrapt::Helpers module
4
+ module Helpers
5
+ end
6
+ end
@@ -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,3 @@
1
+ %h1 Multiple Contents
2
+ .content= yield
3
+ .foo= yield :foo
@@ -0,0 +1,4 @@
1
+ %h1 Other Template
2
+
3
+ .content
4
+ = yield
@@ -0,0 +1,4 @@
1
+ %h1 Wrapper Template
2
+
3
+ .content
4
+ = yield
@@ -0,0 +1,2 @@
1
+ var data = { content: '<%= yield %>' }
2
+ my_function(data);
@@ -0,0 +1,4 @@
1
+ %h1 Wrapper Template XML
2
+
3
+ .content
4
+ = yield
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'wrapt'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'rack'
7
+ require 'haml'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
@@ -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
+