nestive_rendering 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +274 -0
- data/lib/nestive_rendering/layout_helper.rb +262 -0
- data/lib/nestive_rendering/railtie.rb +11 -0
- data/lib/nestive_rendering/version.rb +3 -0
- data/lib/nestive_rendering.rb +6 -0
- data/spec/controllers/nestive_spec.rb +122 -0
- data/spec/internal/app/controllers/application_controller.rb +2 -0
- data/spec/internal/app/controllers/nestive_controller.rb +17 -0
- data/spec/internal/app/views/layouts/extend_one.html.erb +5 -0
- data/spec/internal/app/views/layouts/extend_two.html.erb +6 -0
- data/spec/internal/app/views/layouts/locals.html.erb +6 -0
- data/spec/internal/app/views/layouts/needs_options.html.erb +5 -0
- data/spec/internal/app/views/layouts/nestive.html.erb +15 -0
- data/spec/internal/app/views/nestive/_extended_features.html.erb +5 -0
- data/spec/internal/app/views/nestive/_extended_features_options.html.haml +3 -0
- data/spec/internal/app/views/nestive/_features.html.erb +4 -0
- data/spec/internal/app/views/nestive/_features_options.html.erb +9 -0
- data/spec/internal/app/views/nestive/append.html.erb +6 -0
- data/spec/internal/app/views/nestive/extended_one.html.erb +1 -0
- data/spec/internal/app/views/nestive/extended_partial.html.erb +1 -0
- data/spec/internal/app/views/nestive/extended_partial_options.html.haml +1 -0
- data/spec/internal/app/views/nestive/extended_three.html.erb +1 -0
- data/spec/internal/app/views/nestive/extended_two.html.erb +1 -0
- data/spec/internal/app/views/nestive/index.html.erb +1 -0
- data/spec/internal/app/views/nestive/locals.html.erb +1 -0
- data/spec/internal/app/views/nestive/prepend.html.erb +6 -0
- data/spec/internal/app/views/nestive/purge_multiple.html.erb +3 -0
- data/spec/internal/app/views/nestive/purge_single.html.erb +3 -0
- data/spec/internal/app/views/nestive/replace.html.erb +7 -0
- data/spec/internal/config/routes.rb +3 -0
- data/spec/internal/log/test.log +43 -0
- data/spec/spec_helper.rb +15 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 099ff10f13d97d6e59b72959b44445ebc9919d52
|
4
|
+
data.tar.gz: d3c8a453d1c30dfb6131f50ef7e51b7cf5735fde
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 463152fc1c35aac30f7d01b57495ce50315d5a0394056563c7799c31022353da41445a38bed1fc04e0489a3a8ce6755c6537691fa50bde160cecaefe0e5883b7
|
7
|
+
data.tar.gz: ed95fd4b280fecbd6721834bb2340f2c3db1dd8446a2b73fcd2fe464fdd0e69abefc4a15cc504f036b27388ec6b28e03c2a07bc2c37e1d5886f8349e7da89032
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Justin French
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
# Nestive Rendering [![Build Status](https://travis-ci.org/mdeering/nestive_rendering.png)](https://travis-ci.org/mdeering/nestive_rendering) [![Code Climate](https://codeclimate.com/github/mdeering/nestive_rendering.png)](https://codeclimate.com/github/mdeering/nestive_rendering)
|
2
|
+
## A Nested Inheritable Layouts and Partial Helpers for Rails
|
3
|
+
|
4
|
+
## Forked from [Nestive](https://github.com/rwz/nestive) to add option passing and the ability to extend partials.
|
5
|
+
|
6
|
+
Nestive Rendering adds powerful layout, template and partial view helpers to your Rails app. It's similar
|
7
|
+
to the nested layout technique [already documented in the Rails
|
8
|
+
guides](http://guides.rubyonrails.org/layouts_and_rendering.html#using-nested-layouts)
|
9
|
+
and found in many other nested layout plugins (a technique using `content_for`
|
10
|
+
and rendering the parent layout at the end of the child layout). There's a
|
11
|
+
bunch of problems with this technique, including:
|
12
|
+
|
13
|
+
* you can only *append* content to the content buffer with `content_for` (you
|
14
|
+
can't prepend to content, you can't replace it)
|
15
|
+
* when combined with this nested layout technique, `content_for` actually
|
16
|
+
*prepends* new content to the buffer, because each parent layout is rendered
|
17
|
+
*after* it's child
|
18
|
+
|
19
|
+
Nestive Rendering is *better* because it addresses these problems.
|
20
|
+
|
21
|
+
## Just seven methods (so far)
|
22
|
+
|
23
|
+
### Declaring an area of content with `area`:
|
24
|
+
|
25
|
+
The `area` helper is a lot like Rails' own `<%= yield :foo %>`, and is used in
|
26
|
+
layouts to define and render a chunk of content in your layout:
|
27
|
+
|
28
|
+
```erb
|
29
|
+
<%= area :sidebar %>
|
30
|
+
```
|
31
|
+
|
32
|
+
Unlike `yield`, `area` will allow your parent layouts to add content to the
|
33
|
+
area at the same time using either a String or a block:
|
34
|
+
|
35
|
+
```erb
|
36
|
+
<%= area :sidebar, "Some Content Here" %>
|
37
|
+
|
38
|
+
<%= area :sidebar do %>
|
39
|
+
Some Content Here
|
40
|
+
<% end %>
|
41
|
+
```
|
42
|
+
|
43
|
+
It's important to note that this isn't *default* content, it *is* the content
|
44
|
+
(unless a child changes it).
|
45
|
+
|
46
|
+
### Appending content to an area with `append`:
|
47
|
+
|
48
|
+
The implementation details are quite different, but the `append` helper works
|
49
|
+
much like Rails' built-in `content_for`. It will work with either a String or
|
50
|
+
block, adding the new content onto the end of any content previously provided
|
51
|
+
by parent layouts:
|
52
|
+
|
53
|
+
```erb
|
54
|
+
<%= extends :application do %>
|
55
|
+
<% append :sidebar, "More content." %>
|
56
|
+
<% append :sidebar do %>
|
57
|
+
More content.
|
58
|
+
<% end %>
|
59
|
+
<% end %>
|
60
|
+
```
|
61
|
+
|
62
|
+
### Prepending content to an area with `prepend`:
|
63
|
+
|
64
|
+
Exactly what you think it is. The reverse of `append` (duh), adding the new
|
65
|
+
content at the start of any content previously provided by parent layouts:
|
66
|
+
|
67
|
+
``` erb
|
68
|
+
<%= extends :application do %>
|
69
|
+
<%= prepend :sidebar, "Content." %>
|
70
|
+
<%= prepend :sidebar do %>
|
71
|
+
Content.
|
72
|
+
<% end %>
|
73
|
+
<% end %>
|
74
|
+
```
|
75
|
+
|
76
|
+
### Replacing content with `replace`
|
77
|
+
|
78
|
+
You can also replace any content provided by parent layouts:
|
79
|
+
|
80
|
+
``` erb
|
81
|
+
<%= extends :application do %>
|
82
|
+
<%= replace :sidebar, "New content." %>
|
83
|
+
<%= replace :sidebar do %>
|
84
|
+
New content.
|
85
|
+
<% end %>
|
86
|
+
<% end %>
|
87
|
+
```
|
88
|
+
|
89
|
+
### Removing content with `purge`
|
90
|
+
|
91
|
+
You can remove the content in the single or in multiple areas
|
92
|
+
|
93
|
+
``` erb
|
94
|
+
<% purge :sidebar %>
|
95
|
+
<% purge :sidebar, :banner %>
|
96
|
+
```
|
97
|
+
|
98
|
+
... which is equal to:
|
99
|
+
|
100
|
+
``` erb
|
101
|
+
<% replace :sidebar, nil %>
|
102
|
+
```
|
103
|
+
|
104
|
+
### Extending a layout in a child layout (or view) with `extends`
|
105
|
+
|
106
|
+
Any layout (or view) can declare that it wants to inherit from and extend a
|
107
|
+
parent layout, in this case we're extending
|
108
|
+
`app/views/layouts/application.html.erb`:
|
109
|
+
|
110
|
+
``` erb
|
111
|
+
<%= extends :application do %>
|
112
|
+
...
|
113
|
+
<% end %>
|
114
|
+
```
|
115
|
+
|
116
|
+
You can nest many levels deep:
|
117
|
+
|
118
|
+
`app/views/layouts/application.html.erb`:
|
119
|
+
|
120
|
+
``` erb
|
121
|
+
<!DOCTYPE html>
|
122
|
+
<html>
|
123
|
+
<head>
|
124
|
+
<%= area :head do %>
|
125
|
+
<title><%= area :title, 'Nestive' %></title>
|
126
|
+
<% end %>
|
127
|
+
</head>
|
128
|
+
<body>
|
129
|
+
<%= yield %>
|
130
|
+
</body>
|
131
|
+
</html>
|
132
|
+
```
|
133
|
+
|
134
|
+
`app/views/layouts/with_sidebar.html.erb`:
|
135
|
+
|
136
|
+
``` erb
|
137
|
+
<%= extends :application do %>
|
138
|
+
<div class="sidebar"><%= area(:sidebar) do %>
|
139
|
+
here goes sidebar
|
140
|
+
<% end %></div>
|
141
|
+
<%= yield -%>
|
142
|
+
<% end %>
|
143
|
+
```
|
144
|
+
|
145
|
+
`app/views/layouts/blog_posts.html.erb`:
|
146
|
+
|
147
|
+
``` erb
|
148
|
+
<%= extends :with_sidebar do %>
|
149
|
+
<% append :sidebar do %>
|
150
|
+
Blog archive:
|
151
|
+
<%= render_blog_archive %>
|
152
|
+
<% end %>
|
153
|
+
|
154
|
+
<% append :head do %>
|
155
|
+
<%= javascript_include_tag 'fancy_blog_archive_tag_cloud' %>
|
156
|
+
<% end %>
|
157
|
+
|
158
|
+
<%= yield %>
|
159
|
+
<% end %>
|
160
|
+
```
|
161
|
+
|
162
|
+
## The token blog example
|
163
|
+
|
164
|
+
Set-up a global layout defining some content areas.
|
165
|
+
|
166
|
+
`app/views/layouts/application.html.erb`:
|
167
|
+
|
168
|
+
``` erb
|
169
|
+
<!DOCTYPE html>
|
170
|
+
<html>
|
171
|
+
<head>
|
172
|
+
<meta charset="utf-8">
|
173
|
+
<title><%= area :title, "JustinFrench.com" %></title>
|
174
|
+
<meta name="description" content="<%= area :description, "This is my website." %>">
|
175
|
+
<meta name="keywords" content="<%= area :keywords, "justin, french, ruby, design" %>">
|
176
|
+
</head>
|
177
|
+
<body>
|
178
|
+
<div id="wrapper">
|
179
|
+
<div id="content">
|
180
|
+
<%= area :content do %>
|
181
|
+
<p>Default content goes here.</p>
|
182
|
+
<% end %>
|
183
|
+
</div>
|
184
|
+
<div id="sidebar">
|
185
|
+
<%= area :sidebar do %>
|
186
|
+
<h2>About Me</h2>
|
187
|
+
<p>...</p>
|
188
|
+
<% end %>
|
189
|
+
</div>
|
190
|
+
</div>
|
191
|
+
<%= yield %>
|
192
|
+
</body>
|
193
|
+
</html>
|
194
|
+
```
|
195
|
+
|
196
|
+
Next, we set-up a `blog` layout that extends `application`, replacing,
|
197
|
+
appending & prepending content to the areas we defined earlier.
|
198
|
+
|
199
|
+
`app/views/layouts/blog.html.erb`:
|
200
|
+
|
201
|
+
``` erb
|
202
|
+
<%= extends :application do %>
|
203
|
+
<% replace :title, "My Blog – " %>
|
204
|
+
<% replace :description, "Justin French blogs here on Ruby, Rails, Design, Formtastic, etc" %>
|
205
|
+
<% prepend :keywords, "blog, weblog, design links, ruby links, formtastic release notes, " %>
|
206
|
+
<%= yield %>
|
207
|
+
<% end %>
|
208
|
+
```
|
209
|
+
|
210
|
+
Now in our blog index view we can use `blog` layout and fill in the areas with
|
211
|
+
content specific to the index action.
|
212
|
+
|
213
|
+
|
214
|
+
`app/views/posts/index.html.erb`:
|
215
|
+
|
216
|
+
``` erb
|
217
|
+
<% replace :content do %>
|
218
|
+
<h1>My Blog</h1>
|
219
|
+
<%= render @articles %>
|
220
|
+
<% end %>
|
221
|
+
|
222
|
+
<% append :sidebar do %>
|
223
|
+
<h2>Blog Roll</h2>
|
224
|
+
<%= render @links %>
|
225
|
+
<% end %>
|
226
|
+
```
|
227
|
+
|
228
|
+
We also need to instruct the `PostsController` to use this `blog` layout:
|
229
|
+
|
230
|
+
`app/controllers/posts_controller.rb`:
|
231
|
+
|
232
|
+
``` ruby
|
233
|
+
class PostsController < ApplicationController
|
234
|
+
layout 'blog'
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
### Extending a parital in a child partial (or view) with `extends_partial`
|
239
|
+
|
240
|
+
Any partial (or view) can declare that it wants to inherit from and extend a
|
241
|
+
parent partial.
|
242
|
+
|
243
|
+
|
244
|
+
## Caching
|
245
|
+
Nestive works the same way `content_for` does and has the same caching
|
246
|
+
drawbacks. That means that nestive helpers are completely ignored when called
|
247
|
+
from within cached block. You probably don't want to use fragment caching
|
248
|
+
around dynamic nestive areas and have to be extra careful what and how you
|
249
|
+
cache to avoid unpleasant surprises.
|
250
|
+
|
251
|
+
## Installation
|
252
|
+
|
253
|
+
* add `gem 'nestive', '~> 0.5'` to your Gemfile
|
254
|
+
* run `bundle`
|
255
|
+
|
256
|
+
## Compatibility
|
257
|
+
|
258
|
+
Nestive should work properly with any Rails 3 and 4. Since version 0.5 only
|
259
|
+
Ruby 1.9.3 and newer are supported. For 1.8 compatibility use version 0.4.
|
260
|
+
|
261
|
+
|
262
|
+
*Nestive doesn't monkey patch or fiddle with any default behaviors in Rails.* Use it when you want to, don't when you don't.
|
263
|
+
|
264
|
+
## You can help with...
|
265
|
+
|
266
|
+
* feedback
|
267
|
+
* reporting issues
|
268
|
+
* fixing issues with pull requests
|
269
|
+
* performance testing
|
270
|
+
|
271
|
+
## Twitter
|
272
|
+
|
273
|
+
* [@rwz](https://twitter.com/rwz) — current maintainer
|
274
|
+
* [@justinfrench](http://twitter.com/justinfrench) — author
|
@@ -0,0 +1,262 @@
|
|
1
|
+
module NestiveRendering
|
2
|
+
|
3
|
+
# The Nestive Rendering LayoutHelper provides a handful of helper methods for use in your layouts and views.
|
4
|
+
#
|
5
|
+
# See the documentation for each individual method for detailed information, but at a high level,
|
6
|
+
# your parent layouts define `area`s of content. You can define an area and optionally add content
|
7
|
+
# to it at the same time using either a String, or a block:
|
8
|
+
#
|
9
|
+
# # app/views/layouts/global.html.erb
|
10
|
+
# <html>
|
11
|
+
# <head>
|
12
|
+
# <title><%= area :title, "MySite.com" %></title>
|
13
|
+
# </head>
|
14
|
+
# <body>
|
15
|
+
# <div id="content">
|
16
|
+
# <%= area :content %>
|
17
|
+
# </div>
|
18
|
+
# <div id="sidebar">
|
19
|
+
# <%= area :sidebar do %>
|
20
|
+
# <h2>About MySite.com</h2>
|
21
|
+
# <p>...</p>
|
22
|
+
# <% end %>
|
23
|
+
# </div>
|
24
|
+
# </body>
|
25
|
+
# </html>
|
26
|
+
#
|
27
|
+
# Your child layouts (or views) inherit and modify the parent by wrapping in an `extends` block
|
28
|
+
# helper. You can then either `append`, `prepend` or `replace` the content that has previously
|
29
|
+
# been assigned to each area by parent layouts.
|
30
|
+
#
|
31
|
+
# The `append`, `prepend` or `replace` helpers are *similar* to Rails' own `content_for`, which
|
32
|
+
# accepts content for the named area with either a String or with a block). They're different to
|
33
|
+
# `content_for` because they're only used modify the content assigned to the area, not retrieve it:
|
34
|
+
#
|
35
|
+
# # app/views/layouts/admin.html.erb
|
36
|
+
# <%= extends :global do %>
|
37
|
+
# <% prepend :title, "Admin :: " %>
|
38
|
+
# <% replace :sidebar do %>
|
39
|
+
# <h2>Quick Links</h2>
|
40
|
+
# <ul>
|
41
|
+
# <li>...</li>
|
42
|
+
# </ul>
|
43
|
+
# <% end %>
|
44
|
+
# <% end %>
|
45
|
+
#
|
46
|
+
# # app/views/admin/posts/index.html.erb
|
47
|
+
# <%= extends :admin do %>
|
48
|
+
# <% prepend :title, "Posts ::" %>
|
49
|
+
# <% replace :content do %>
|
50
|
+
# Normal view stuff goes here.
|
51
|
+
# <% end %>
|
52
|
+
# <% end %>
|
53
|
+
module LayoutHelper
|
54
|
+
|
55
|
+
# Declares that the current layour (or view) is inheriting from and extending another layout.
|
56
|
+
#
|
57
|
+
# @param [String] layout
|
58
|
+
# The base name of the file in `layouts/` that you wish to extend (eg `application` for `layouts/application.html.erb`)
|
59
|
+
# @param [Hash] options
|
60
|
+
# Any options such as locals that you want to pass through to the layout rendering
|
61
|
+
#
|
62
|
+
# @example Extending the `application` layout to create an `admin` layout
|
63
|
+
#
|
64
|
+
# # app/views/layouts/admin.html.erb
|
65
|
+
# <%= extends :application do %>
|
66
|
+
# ...
|
67
|
+
# <% end %>
|
68
|
+
#
|
69
|
+
# @example Extending the `admin` layout in a view (you'll need to render the view with `layout: nil`)
|
70
|
+
#
|
71
|
+
# # app/controllers/admin/posts_controller.rb
|
72
|
+
# class Admin::PostsController < ApplicationController
|
73
|
+
# # You can disable Rails' layout rendering for all actions
|
74
|
+
# layout nil
|
75
|
+
#
|
76
|
+
# # Or disable Rails' layout rendering per-controller
|
77
|
+
# def index
|
78
|
+
# render layout: nil
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# # app/views/admin/posts/index.html.erb
|
83
|
+
# <%= extends :admin do %>
|
84
|
+
# ...
|
85
|
+
# <% end %>
|
86
|
+
def extends(layout, options = {}, &block)
|
87
|
+
# Make sure it's a string
|
88
|
+
layout = layout.to_s
|
89
|
+
|
90
|
+
# If there's no directory component, presume a plain layout name
|
91
|
+
layout = "layouts/#{layout}" unless layout.include?('/')
|
92
|
+
|
93
|
+
# Capture the content to be placed inside the extended layout
|
94
|
+
@view_flow.get(:layout).replace capture(&block)
|
95
|
+
|
96
|
+
render options.merge(file: layout)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Works exactly the same as extends but is targeted at extending partials not
|
100
|
+
# layouts.
|
101
|
+
#
|
102
|
+
# @param [String] partial
|
103
|
+
# The base name of the partial that you wish to extend (eg `header` for `application/_header.html.erb`)
|
104
|
+
# @param [Hash] options
|
105
|
+
# Any options such as the object or locals that you want to pass through to the parital rendering
|
106
|
+
#
|
107
|
+
def extends_partial(partial, options = {}, &block)
|
108
|
+
# Make sure it's a string
|
109
|
+
partial = partial.to_s
|
110
|
+
block.call if block_given?
|
111
|
+
render options.merge(partial: partial)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Defines an area of content in your layout that can be modified or replaced by child layouts
|
115
|
+
# that extend it. You can optionally add content to an area using either a String, or a block.
|
116
|
+
#
|
117
|
+
# Areas are declared in a parent layout and modified by a child layout, but since Nestive Rendering
|
118
|
+
# allows for multiple levels of inheritance, a child layout can also declare an area for it's
|
119
|
+
# children to modify.
|
120
|
+
#
|
121
|
+
# @example Define an area without adding content to it:
|
122
|
+
# <%= area :sidebar %>
|
123
|
+
#
|
124
|
+
# @example Define an area and add a String of content to it:
|
125
|
+
# <%= area :sidebar, "Some content." %>
|
126
|
+
#
|
127
|
+
# @example Define an area and add content to it with a block:
|
128
|
+
# <%= area :sidebar do %>
|
129
|
+
# Some content.
|
130
|
+
# <% end %>
|
131
|
+
#
|
132
|
+
# @example Define an area in a child layout:
|
133
|
+
# <%= extends :global do %>
|
134
|
+
# <%= area :sidebar do %>
|
135
|
+
# Some content.
|
136
|
+
# <% end %>
|
137
|
+
# <% end %>
|
138
|
+
#
|
139
|
+
# @param [Symbol] name
|
140
|
+
# A unique name to identify this area of content.
|
141
|
+
#
|
142
|
+
# @param [String] content
|
143
|
+
# An optional String of content to add to the area as you declare it.
|
144
|
+
def area(name, content=nil, &block)
|
145
|
+
content = capture(&block) if block_given?
|
146
|
+
append name, content
|
147
|
+
render_area name
|
148
|
+
end
|
149
|
+
|
150
|
+
# Appends content to an area previously defined or modified in parent layout(s). You can provide
|
151
|
+
# the content using either a String, or a block.
|
152
|
+
#
|
153
|
+
# @example Appending content with a String
|
154
|
+
# <% append :sidebar, "Some content." %>
|
155
|
+
#
|
156
|
+
# @example Appending content with a block:
|
157
|
+
# <% append :sidebar do %>
|
158
|
+
# Some content.
|
159
|
+
# <% end %>
|
160
|
+
#
|
161
|
+
# @param [Symbol] name
|
162
|
+
# A name to identify the area of content you wish to append to
|
163
|
+
#
|
164
|
+
# @param [String] content
|
165
|
+
# Optionally provide a String of content, instead of a block. A block will take precedence.
|
166
|
+
def append(name, content=nil, &block)
|
167
|
+
content = capture(&block) if block_given?
|
168
|
+
add_instruction_to_area name, :push, content
|
169
|
+
end
|
170
|
+
|
171
|
+
# Prepends content to an area previously declared or modified in parent layout(s). You can
|
172
|
+
# provide the content using either a String, or a block.
|
173
|
+
#
|
174
|
+
# @example Prepending content with a String
|
175
|
+
# <% prepend :sidebar, "Some content." %>
|
176
|
+
#
|
177
|
+
# @example Prepending content with a block:
|
178
|
+
# <% prepend :sidebar do %>
|
179
|
+
# Some content.
|
180
|
+
# <% end %>
|
181
|
+
#
|
182
|
+
# @param [Symbol] name
|
183
|
+
# A name to identify the area of content you wish to prepend to
|
184
|
+
#
|
185
|
+
# @param [String] content
|
186
|
+
# Optionally provide a String of content, instead of a block. A block will take precedence.
|
187
|
+
def prepend(name, content=nil, &block)
|
188
|
+
content = capture(&block) if block_given?
|
189
|
+
add_instruction_to_area name, :unshift, content
|
190
|
+
end
|
191
|
+
|
192
|
+
# Replaces the content of an area previously declared or modified in parent layout(s). You can
|
193
|
+
# provide the content using either a String, or a block.
|
194
|
+
#
|
195
|
+
# @example Replacing content with a String
|
196
|
+
# <% replace :sidebar, "New content." %>
|
197
|
+
#
|
198
|
+
# @example Replacing content with a block:
|
199
|
+
# <% replace :sidebar do %>
|
200
|
+
# New content.
|
201
|
+
# <% end %>
|
202
|
+
#
|
203
|
+
# @param [Symbol] name
|
204
|
+
# A name to identify the area of content you wish to replace
|
205
|
+
#
|
206
|
+
# @param [String] content
|
207
|
+
# Optionally provide a String of content, instead of a block. A block will take precedence.
|
208
|
+
def replace(name, content=nil, &block)
|
209
|
+
content = capture(&block) if block_given?
|
210
|
+
add_instruction_to_area name, :replace, [content]
|
211
|
+
end
|
212
|
+
|
213
|
+
# Purge the content of an area previously declared or modified in parent layout(s).
|
214
|
+
#
|
215
|
+
# @example Purge content
|
216
|
+
# <% purge :sidebar %>
|
217
|
+
#
|
218
|
+
# @param names
|
219
|
+
# A list of area names to purge
|
220
|
+
def purge(*names)
|
221
|
+
names.each{ |name| replace(name, nil)}
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
# We record the instructions (declaring, appending, prepending and replacing) for an area of
|
227
|
+
# content into an array that we can later retrieve and replay. Instructions are stored in an
|
228
|
+
# instance variable Hash `@_area_for`, with each key representing an area name, and each value
|
229
|
+
# an Array of instructions. Each instruction is a two element array containing a instruction
|
230
|
+
# method (eg `:push`, `:unshift`, `:replace`) and a value (content String).
|
231
|
+
#
|
232
|
+
# @_area_for[:sidebar] # => [ [:push,"World"], [:unshift,"Hello"] ]
|
233
|
+
#
|
234
|
+
# Due to the way we extend layouts (render the parent layout after the child), the instructions
|
235
|
+
# are captured in reverse order. `render_area` reversed them and plays them back at rendering
|
236
|
+
# time.
|
237
|
+
#
|
238
|
+
# @example
|
239
|
+
# add_instruction_to_area(:sidebar, :push, "More content.")
|
240
|
+
def add_instruction_to_area(name, instruction, value)
|
241
|
+
@_area_for ||= {}
|
242
|
+
@_area_for[name] ||= []
|
243
|
+
@_area_for[name] << [instruction, value]
|
244
|
+
nil
|
245
|
+
end
|
246
|
+
|
247
|
+
# Take the instructions we've gathered for the area and replay them one after the other on
|
248
|
+
# an empty array. These instructions will push, unshift or replace items into our output array,
|
249
|
+
# which we then join and mark as html_safe.
|
250
|
+
#
|
251
|
+
# These instructions are reversed and replayed when we render the block (rather than as they
|
252
|
+
# happen) due to the way they are gathered by the layout extension process (in reverse).
|
253
|
+
def render_area(name)
|
254
|
+
[].tap do |output|
|
255
|
+
@_area_for.fetch(name, []).reverse_each do |method_name, content|
|
256
|
+
output.public_send method_name, content
|
257
|
+
end
|
258
|
+
end.join.html_safe
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NestiveController do
|
4
|
+
render_views
|
5
|
+
|
6
|
+
context '#area' do
|
7
|
+
it 'is empty by default' do
|
8
|
+
get :index
|
9
|
+
assert_select '#empty-area', ''
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'shows initial value if any' do
|
13
|
+
get :index
|
14
|
+
assert_select 'title', 'Nestive'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can accept blocks as initial value' do
|
18
|
+
get :index
|
19
|
+
assert_select '#some-area', 'Some content'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context '#append' do
|
24
|
+
it 'appends content to area as a string' do
|
25
|
+
get :append
|
26
|
+
assert_select 'title', 'Nestive is awesome'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'appends content to area as a block' do
|
30
|
+
get :append
|
31
|
+
assert_select '#some-area', "Some content\n Another content"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context '#prepend' do
|
36
|
+
it 'prepends content to area as a string' do
|
37
|
+
get :prepend
|
38
|
+
assert_select 'title', 'Awesome Nestive'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'prepends content to area as a block' do
|
42
|
+
get :prepend
|
43
|
+
assert_select '#some-area', "Prepended\n Some content"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context '#replace' do
|
48
|
+
it 'replaces area content with string' do
|
49
|
+
get :replace
|
50
|
+
assert_select 'title', 'Lolwut'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'replaces area content with block' do
|
54
|
+
get :replace
|
55
|
+
assert_select '#some-area', 'replaced'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context '#purge' do
|
60
|
+
it 'purge single area content' do
|
61
|
+
get :purge_single
|
62
|
+
assert_select 'title'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'purge few areas content' do
|
66
|
+
get :purge_multiple
|
67
|
+
assert_select 'title'
|
68
|
+
assert_select '#some-area'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context '#extends' do
|
73
|
+
it 'extends layouts' do
|
74
|
+
get :extended_one
|
75
|
+
assert_select 'p', 'extended: one'
|
76
|
+
assert_select 'title', 'extended: one'
|
77
|
+
assert_select 'h2', 'extended: one'
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'can extend already extended layouts' do
|
81
|
+
get :extended_two
|
82
|
+
assert_select 'p', 'extended: two'
|
83
|
+
assert_select 'title', 'extended: one'
|
84
|
+
assert_select '#some-area', 'extended: two'
|
85
|
+
assert_select 'h2', 'extended: one'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'extends empty layout' do
|
89
|
+
get :extended_three
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context '#locals' do
|
94
|
+
it 'allows for options to be passed through to the file render' do
|
95
|
+
get :locals
|
96
|
+
assert_select 'title', 'Passed in as a local'
|
97
|
+
assert_select '#some-area', 'locals: title'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context '#extends_partial' do
|
102
|
+
it 'nestive works great with partials also!' do
|
103
|
+
get :extended_partial
|
104
|
+
assert_select 'h1', 'Features'
|
105
|
+
assert_select '#basic-features', 'Basic Features'
|
106
|
+
assert_select '#extended-features', 'Extended Features'
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'partials are a lot more fun with options' do
|
110
|
+
get :extended_partial_options
|
111
|
+
assert_select 'h1', 'Features'
|
112
|
+
assert_select '#basic-feature-1', 'Basic Features 1'
|
113
|
+
assert_select '#basic-feature-2', 'Basic Features 2'
|
114
|
+
assert_select '#extended-features', 'Extended Features'
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should only render the extensions on the partial a single time!' do
|
118
|
+
get :extended_partial_options
|
119
|
+
assert_select '.feature', 3
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class NestiveController < ApplicationController
|
2
|
+
def extended_one
|
3
|
+
render layout: 'extend_one'
|
4
|
+
end
|
5
|
+
|
6
|
+
def extended_two
|
7
|
+
render layout: 'extend_two'
|
8
|
+
end
|
9
|
+
|
10
|
+
def extended_three
|
11
|
+
render layout: 'extend_one'
|
12
|
+
end
|
13
|
+
|
14
|
+
def locals
|
15
|
+
render layout: 'locals'
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= area :title, 'Nestive' %></title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<%= yield %>
|
8
|
+
<div id="some-area">
|
9
|
+
<%= area :some_area do -%>
|
10
|
+
Some content
|
11
|
+
<%- end -%>
|
12
|
+
</div>
|
13
|
+
<div id="empty-area"><%= area :empty_area %></div>
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<h1>Features</h1>
|
2
|
+
<%= area :features_list do %>
|
3
|
+
<%- features.each do |feature| %>
|
4
|
+
<div class='feature' id='basic-feature-<%= feature %>'>Basic Features <%= feature %></div>
|
5
|
+
<%- end %>
|
6
|
+
<% end %>
|
7
|
+
<%= area :features_summary do %>
|
8
|
+
<p>Here is a summary or something like that...</p>
|
9
|
+
<%- end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<p>extended: one</p>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render 'extended_features' %>
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'extended_features_options'
|
@@ -0,0 +1 @@
|
|
1
|
+
<% append :title, 'lol' %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<p>extended: two</p>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Hello World</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Locals</h1>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Processing by NestiveController#index as HTML
|
2
|
+
Rendered nestive/index.html.erb within layouts/nestive (0.6ms)
|
3
|
+
Completed 200 OK in 3.6ms (Views: 3.5ms)
|
4
|
+
Processing by NestiveController#index as HTML
|
5
|
+
Completed 200 OK in 0.3ms (Views: 0.2ms)
|
6
|
+
Processing by NestiveController#index as HTML
|
7
|
+
Completed 200 OK in 0.2ms (Views: 0.2ms)
|
8
|
+
Processing by NestiveController#append as HTML
|
9
|
+
Completed 200 OK in 0.8ms (Views: 0.7ms)
|
10
|
+
Processing by NestiveController#append as HTML
|
11
|
+
Completed 200 OK in 0.3ms (Views: 0.2ms)
|
12
|
+
Processing by NestiveController#prepend as HTML
|
13
|
+
Completed 200 OK in 0.7ms (Views: 0.6ms)
|
14
|
+
Processing by NestiveController#prepend as HTML
|
15
|
+
Completed 200 OK in 0.2ms (Views: 0.2ms)
|
16
|
+
Processing by NestiveController#replace as HTML
|
17
|
+
Completed 200 OK in 0.8ms (Views: 0.7ms)
|
18
|
+
Processing by NestiveController#replace as HTML
|
19
|
+
Completed 200 OK in 0.2ms (Views: 0.2ms)
|
20
|
+
Processing by NestiveController#purge_single as HTML
|
21
|
+
Completed 200 OK in 0.7ms (Views: 0.6ms)
|
22
|
+
Processing by NestiveController#purge_multiple as HTML
|
23
|
+
Completed 200 OK in 0.9ms (Views: 0.7ms)
|
24
|
+
Processing by NestiveController#extended_one as HTML
|
25
|
+
Completed 200 OK in 1.2ms (Views: 1.1ms)
|
26
|
+
Processing by NestiveController#extended_two as HTML
|
27
|
+
Completed 200 OK in 1.2ms (Views: 1.1ms)
|
28
|
+
Processing by NestiveController#extended_three as HTML
|
29
|
+
Completed 200 OK in 1.1ms (Views: 0.9ms)
|
30
|
+
Processing by NestiveController#locals as HTML
|
31
|
+
Completed 200 OK in 1.7ms (Views: 1.6ms)
|
32
|
+
Processing by NestiveController#extended_partial as HTML
|
33
|
+
Rendered nestive/_features.html.erb (0.3ms)
|
34
|
+
Rendered nestive/_extended_features.html.erb (1.0ms)
|
35
|
+
Completed 200 OK in 3.1ms (Views: 3.0ms)
|
36
|
+
Processing by NestiveController#extended_partial_options as HTML
|
37
|
+
Rendered nestive/_features_options.html.erb (0.4ms)
|
38
|
+
Rendered nestive/_extended_features_options.html.haml (1.5ms)
|
39
|
+
Completed 200 OK in 3.0ms (Views: 2.9ms)
|
40
|
+
Processing by NestiveController#extended_partial_options as HTML
|
41
|
+
Rendered nestive/_features_options.html.erb (0.1ms)
|
42
|
+
Rendered nestive/_extended_features_options.html.haml (0.3ms)
|
43
|
+
Completed 200 OK in 0.7ms (Views: 0.7ms)
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'rails'
|
6
|
+
require 'combustion'
|
7
|
+
require 'nestive_rendering'
|
8
|
+
|
9
|
+
Combustion.initialize! :action_controller
|
10
|
+
|
11
|
+
require 'rspec/rails'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.infer_spec_type_from_file_location!
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nestive_rendering
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin French
|
8
|
+
- Pavel Pravosud
|
9
|
+
- Michael Deering
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-12-08 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: 3.0.0
|
29
|
+
description: A Rails gem for awesome nested templates, layouts and paritals
|
30
|
+
email:
|
31
|
+
- justin@indent.com.au
|
32
|
+
- pavel@pravosud.com
|
33
|
+
- mdeering@mdeering.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- MIT-LICENSE
|
39
|
+
- README.md
|
40
|
+
- lib/nestive_rendering.rb
|
41
|
+
- lib/nestive_rendering/layout_helper.rb
|
42
|
+
- lib/nestive_rendering/railtie.rb
|
43
|
+
- lib/nestive_rendering/version.rb
|
44
|
+
- spec/controllers/nestive_spec.rb
|
45
|
+
- spec/internal/app/controllers/application_controller.rb
|
46
|
+
- spec/internal/app/controllers/nestive_controller.rb
|
47
|
+
- spec/internal/app/views/layouts/extend_one.html.erb
|
48
|
+
- spec/internal/app/views/layouts/extend_two.html.erb
|
49
|
+
- spec/internal/app/views/layouts/locals.html.erb
|
50
|
+
- spec/internal/app/views/layouts/needs_options.html.erb
|
51
|
+
- spec/internal/app/views/layouts/nestive.html.erb
|
52
|
+
- spec/internal/app/views/nestive/_extended_features.html.erb
|
53
|
+
- spec/internal/app/views/nestive/_extended_features_options.html.haml
|
54
|
+
- spec/internal/app/views/nestive/_features.html.erb
|
55
|
+
- spec/internal/app/views/nestive/_features_options.html.erb
|
56
|
+
- spec/internal/app/views/nestive/append.html.erb
|
57
|
+
- spec/internal/app/views/nestive/extended_one.html.erb
|
58
|
+
- spec/internal/app/views/nestive/extended_partial.html.erb
|
59
|
+
- spec/internal/app/views/nestive/extended_partial_options.html.haml
|
60
|
+
- spec/internal/app/views/nestive/extended_three.html.erb
|
61
|
+
- spec/internal/app/views/nestive/extended_two.html.erb
|
62
|
+
- spec/internal/app/views/nestive/index.html.erb
|
63
|
+
- spec/internal/app/views/nestive/locals.html.erb
|
64
|
+
- spec/internal/app/views/nestive/prepend.html.erb
|
65
|
+
- spec/internal/app/views/nestive/purge_multiple.html.erb
|
66
|
+
- spec/internal/app/views/nestive/purge_single.html.erb
|
67
|
+
- spec/internal/app/views/nestive/replace.html.erb
|
68
|
+
- spec/internal/config/routes.rb
|
69
|
+
- spec/internal/log/test.log
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
homepage: https://github.com/mdeering/nestive_rendering
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.9.3
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.4.2
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: A Rails gem for awesome nested templates, layouts and paritals
|
95
|
+
test_files:
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
- spec/controllers/nestive_spec.rb
|
98
|
+
- spec/internal/config/routes.rb
|
99
|
+
- spec/internal/app/controllers/nestive_controller.rb
|
100
|
+
- spec/internal/app/controllers/application_controller.rb
|
101
|
+
- spec/internal/app/views/nestive/_features.html.erb
|
102
|
+
- spec/internal/app/views/nestive/extended_partial_options.html.haml
|
103
|
+
- spec/internal/app/views/nestive/replace.html.erb
|
104
|
+
- spec/internal/app/views/nestive/extended_one.html.erb
|
105
|
+
- spec/internal/app/views/nestive/_features_options.html.erb
|
106
|
+
- spec/internal/app/views/nestive/extended_partial.html.erb
|
107
|
+
- spec/internal/app/views/nestive/extended_three.html.erb
|
108
|
+
- spec/internal/app/views/nestive/_extended_features_options.html.haml
|
109
|
+
- spec/internal/app/views/nestive/prepend.html.erb
|
110
|
+
- spec/internal/app/views/nestive/index.html.erb
|
111
|
+
- spec/internal/app/views/nestive/purge_single.html.erb
|
112
|
+
- spec/internal/app/views/nestive/locals.html.erb
|
113
|
+
- spec/internal/app/views/nestive/purge_multiple.html.erb
|
114
|
+
- spec/internal/app/views/nestive/_extended_features.html.erb
|
115
|
+
- spec/internal/app/views/nestive/extended_two.html.erb
|
116
|
+
- spec/internal/app/views/nestive/append.html.erb
|
117
|
+
- spec/internal/app/views/layouts/nestive.html.erb
|
118
|
+
- spec/internal/app/views/layouts/needs_options.html.erb
|
119
|
+
- spec/internal/app/views/layouts/locals.html.erb
|
120
|
+
- spec/internal/app/views/layouts/extend_one.html.erb
|
121
|
+
- spec/internal/app/views/layouts/extend_two.html.erb
|
122
|
+
- spec/internal/log/test.log
|