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.
@@ -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
+