nestive-rails 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
- require 'nestive-rails/version'
2
-
3
- module NestiveRails
4
-
5
- autoload :LayoutHelper, 'nestive-rails/layout_helper'
6
-
7
- require 'nestive-rails/railtie'
8
-
9
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'nestive-rails/version'
4
+
5
+ module NestiveRails
6
+ autoload :LayoutHelper, 'nestive-rails/layout_helper'
7
+
8
+ require 'nestive-rails/railtie'
9
+ end
@@ -1,245 +1,260 @@
1
- module NestiveRails
2
-
3
- # The Nestive 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
- #
60
- # @example Extending the `application` layout to create an `admin` layout
61
- #
62
- # # app/views/layouts/admin.html.erb
63
- # <%= extends :application do %>
64
- # ...
65
- # <% end %>
66
- #
67
- # @example Extending the `admin` layout in a view (you'll need to render the view with `layout: nil`)
68
- #
69
- # # app/controllers/admin/posts_controller.rb
70
- # class Admin::PostsController < ApplicationController
71
- # # You can disable Rails' layout rendering for all actions
72
- # layout nil
73
- #
74
- # # Or disable Rails' layout rendering per-controller
75
- # def index
76
- # render layout: nil
77
- # end
78
- # end
79
- #
80
- # # app/views/admin/posts/index.html.erb
81
- # <%= extends :admin do %>
82
- # ...
83
- # <% end %>
84
- def extends layout, &block
85
- # Make sure it's a string
86
- layout = layout.to_s
87
-
88
- # If there's no directory component, presume a plain layout name
89
- layout = "layouts/#{layout}" unless layout.include?('/')
90
-
91
- # Capture the content to be placed inside the extended layout
92
- @view_flow.get(:layout).replace capture(&block).to_s
93
-
94
- render file: layout
95
- end
96
-
97
- # Defines an area of content in your layout that can be modified or replaced by child layouts
98
- # that extend it. You can optionally add content to an area using either a String, or a block.
99
- #
100
- # Areas are declared in a parent layout and modified by a child layout, but since Nestive
101
- # allows for multiple levels of inheritance, a child layout can also declare an area for it's
102
- # children to modify.
103
- #
104
- # @example Define an area without adding content to it:
105
- # <%= area :sidebar %>
106
- #
107
- # @example Define an area and add a String of content to it:
108
- # <%= area :sidebar, "Some content." %>
109
- #
110
- # @example Define an area and add content to it with a block:
111
- # <%= area :sidebar do %>
112
- # Some content.
113
- # <% end %>
114
- #
115
- # @example Define an area in a child layout:
116
- # <%= extends :global do %>
117
- # <%= area :sidebar do %>
118
- # Some content.
119
- # <% end %>
120
- # <% end %>
121
- #
122
- # @param [Symbol] name
123
- # A unique name to identify this area of content.
124
- #
125
- # @param [String] content
126
- # An optional String of content to add to the area as you declare it.
127
- def area name, content=nil, &block
128
- content = capture(&block) if block_given?
129
- append name, content
130
- render_area name
131
- end
132
-
133
- # Appends content to an area previously defined or modified in parent layout(s). You can provide
134
- # the content using either a String, or a block.
135
- #
136
- # @example Appending content with a String
137
- # <% append :sidebar, "Some content." %>
138
- #
139
- # @example Appending content with a block:
140
- # <% append :sidebar do %>
141
- # Some content.
142
- # <% end %>
143
- #
144
- # @param [Symbol] name
145
- # A name to identify the area of content you wish to append to
146
- #
147
- # @param [String] content
148
- # Optionally provide a String of content, instead of a block. A block will take precedence.
149
- def append name, content=nil, &block
150
- content = capture(&block) if block_given?
151
- add_instruction_to_area name, :push, content
152
- end
153
-
154
- # Prepends content to an area previously declared or modified in parent layout(s). You can
155
- # provide the content using either a String, or a block.
156
- #
157
- # @example Prepending content with a String
158
- # <% prepend :sidebar, "Some content." %>
159
- #
160
- # @example Prepending content with a block:
161
- # <% prepend :sidebar do %>
162
- # Some content.
163
- # <% end %>
164
- #
165
- # @param [Symbol] name
166
- # A name to identify the area of content you wish to prepend to
167
- #
168
- # @param [String] content
169
- # Optionally provide a String of content, instead of a block. A block will take precedence.
170
- def prepend name, content=nil, &block
171
- content = capture(&block) if block_given?
172
- add_instruction_to_area name, :unshift, content
173
- end
174
-
175
- # Replaces the content of an area previously declared or modified in parent layout(s). You can
176
- # provide the content using either a String, or a block.
177
- #
178
- # @example Replacing content with a String
179
- # <% replace :sidebar, "New content." %>
180
- #
181
- # @example Replacing content with a block:
182
- # <% replace :sidebar do %>
183
- # New content.
184
- # <% end %>
185
- #
186
- # @param [Symbol] name
187
- # A name to identify the area of content you wish to replace
188
- #
189
- # @param [String] content
190
- # Optionally provide a String of content, instead of a block. A block will take precedence.
191
- def replace name, content=nil, &block
192
- content = capture(&block) if block_given?
193
- add_instruction_to_area name, :replace, [content]
194
- end
195
-
196
- # Purge the content of an area previously declared or modified in parent layout(s).
197
- #
198
- # @example Purge content
199
- # <% purge :sidebar %>
200
- #
201
- # @param names
202
- # A list of area names to purge
203
- def purge *names
204
- names.each{ |name| replace(name, nil) }
205
- end
206
-
207
- private
208
-
209
- # We record the instructions (declaring, appending, prepending and replacing) for an area of
210
- # content into an array that we can later retrieve and replay. Instructions are stored in an
211
- # instance variable Hash `@_area_for`, with each key representing an area name, and each value
212
- # an Array of instructions. Each instruction is a two element array containing a instruction
213
- # method (eg `:push`, `:unshift`, `:replace`) and a value (content String).
214
- #
215
- # @_area_for[:sidebar] # => [ [:push,"World"], [:unshift,"Hello"] ]
216
- #
217
- # Due to the way we extend layouts (render the parent layout after the child), the instructions
218
- # are captured in reverse order. `render_area` reversed them and plays them back at rendering
219
- # time.
220
- #
221
- # @example
222
- # add_instruction_to_area(:sidebar, :push, "More content.")
223
- def add_instruction_to_area name, instruction, value
224
- @_area_for ||= {}
225
- @_area_for[name] ||= []
226
- @_area_for[name] << [instruction, value]
227
- nil
228
- end
229
-
230
- # Take the instructions we've gathered for the area and replay them one after the other on
231
- # an empty array. These instructions will push, unshift or replace items into our output array,
232
- # which we then join and mark as html_safe.
233
- #
234
- # These instructions are reversed and replayed when we render the block (rather than as they
235
- # happen) due to the way they are gathered by the layout extension process (in reverse).
236
- def render_area name
237
- [].tap do |output|
238
- @_area_for.fetch(name, []).reverse_each do |method_name, content|
239
- output.public_send method_name, content
240
- end
241
- end.join.html_safe
242
- end
243
-
244
- end
245
- end
1
+ # frozen_string_literal: true
2
+
3
+ module NestiveRails
4
+ # The Nestive LayoutHelper provides a handful of helper methods for use in
5
+ # your layouts and views.
6
+ #
7
+ # See the documentation for each individual method for detailed information,
8
+ # but at a high level, your parent layouts define `area`s of content. You can
9
+ # define an area and optionally add content to it at the same time using
10
+ # either a String, or a block:
11
+ #
12
+ # # app/views/layouts/global.html.erb
13
+ # <html>
14
+ # <head>
15
+ # <title><%= area :title, "MySite.com" %></title>
16
+ # </head>
17
+ # <body>
18
+ # <div id="content">
19
+ # <%= area :content %>
20
+ # </div>
21
+ # <div id="sidebar">
22
+ # <%= area :sidebar do %>
23
+ # <h2>About MySite.com</h2>
24
+ # <p>...</p>
25
+ # <% end %>
26
+ # </div>
27
+ # </body>
28
+ # </html>
29
+ #
30
+ # Your child layouts (or views) inherit and modify the parent by wrapping in
31
+ # an `extends` block helper. You can then either `append`, `prepend` or
32
+ # `replace` the content that has previously been assigned to each area by
33
+ # parent layouts.
34
+ #
35
+ # The `append`, `prepend` or `replace` helpers are *similar* to Rails' own
36
+ # `content_for`, which accepts content for the named area with either a String
37
+ # or with a block). They're different to `content_for` because they're only
38
+ # used modify the content assigned to the area, not retrieve it:
39
+ #
40
+ # # app/views/layouts/admin.html.erb
41
+ # <%= extends :global do %>
42
+ # <% prepend :title, "Admin :: " %>
43
+ # <% replace :sidebar do %>
44
+ # <h2>Quick Links</h2>
45
+ # <ul>
46
+ # <li>...</li>
47
+ # </ul>
48
+ # <% end %>
49
+ # <% end %>
50
+ #
51
+ # # app/views/admin/posts/index.html.erb
52
+ # <%= extends :admin do %>
53
+ # <% prepend :title, "Posts ::" %>
54
+ # <% replace :content do %>
55
+ # Normal view stuff goes here.
56
+ # <% end %>
57
+ # <% end %>
58
+ module LayoutHelper
59
+ # Declares that the current layour (or view) is inheriting from and
60
+ # extending another layout.
61
+ #
62
+ # @param [String] layout
63
+ # The base name of the file in `layouts/` that you wish to extend (eg
64
+ # `application` for `layouts/application.html.erb`)
65
+ #
66
+ # @example Extending the `application` layout to create an `admin` layout
67
+ #
68
+ # # app/views/layouts/admin.html.erb
69
+ # <%= extends :application do %>
70
+ # ...
71
+ # <% end %>
72
+ #
73
+ # @example Extending the `admin` layout in a view (you'll need to render the
74
+ # view with `layout: nil`)
75
+ #
76
+ # # app/controllers/admin/posts_controller.rb
77
+ # class Admin::PostsController < ApplicationController
78
+ # # You can disable Rails' layout rendering for all actions
79
+ # layout nil
80
+ #
81
+ # # Or disable Rails' layout rendering per-controller
82
+ # def index
83
+ # render layout: nil
84
+ # end
85
+ # end
86
+ #
87
+ # # app/views/admin/posts/index.html.erb
88
+ # <%= extends :admin do %>
89
+ # ...
90
+ # <% end %>
91
+ def extends(layout, &block)
92
+ # Make sure it's a string
93
+ layout = layout.to_s
94
+
95
+ # If there's no directory component, presume a plain layout name
96
+ layout = "layouts/#{layout}" unless layout.include?('/')
97
+
98
+ # Capture the content to be placed inside the extended layout
99
+ @view_flow.get(:layout).replace capture(&block).to_s
100
+
101
+ render file: layout
102
+ end
103
+
104
+ # Defines an area of content in your layout that can be modified or replaced
105
+ # by child layouts that extend it. You can optionally add content to an area
106
+ # using either a String, or a block.
107
+ #
108
+ # Areas are declared in a parent layout and modified by a child layout, but
109
+ # since Nestive allows for multiple levels of inheritance, a child layout
110
+ # can also declare an area for it's children to modify.
111
+ #
112
+ # @example Define an area without adding content to it:
113
+ # <%= area :sidebar %>
114
+ #
115
+ # @example Define an area and add a String of content to it:
116
+ # <%= area :sidebar, "Some content." %>
117
+ #
118
+ # @example Define an area and add content to it with a block:
119
+ # <%= area :sidebar do %>
120
+ # Some content.
121
+ # <% end %>
122
+ #
123
+ # @example Define an area in a child layout:
124
+ # <%= extends :global do %>
125
+ # <%= area :sidebar do %>
126
+ # Some content.
127
+ # <% end %>
128
+ # <% end %>
129
+ #
130
+ # @param [Symbol] name
131
+ # A unique name to identify this area of content.
132
+ #
133
+ # @param [String] content
134
+ # An optional String of content to add to the area as you declare it.
135
+ def area(name, content = nil, &block)
136
+ content = capture(&block) if block_given?
137
+ append name, content
138
+ render_area name
139
+ end
140
+
141
+ # Appends content to an area previously defined or modified in parent
142
+ # layout(s). You can provide the content using either a String, or a block.
143
+ #
144
+ # @example Appending content with a String
145
+ # <% append :sidebar, "Some content." %>
146
+ #
147
+ # @example Appending content with a block:
148
+ # <% append :sidebar do %>
149
+ # Some content.
150
+ # <% end %>
151
+ #
152
+ # @param [Symbol] name
153
+ # A name to identify the area of content you wish to append to
154
+ #
155
+ # @param [String] content
156
+ # Optionally provide a String of content, instead of a block. A block will
157
+ # take precedence.
158
+ def append(name, content = nil, &block)
159
+ content = capture(&block) if block_given?
160
+ add_instruction_to_area name, :push, content
161
+ end
162
+
163
+ # Prepends content to an area previously declared or modified in parent
164
+ # layout(s). You can provide the content using either a String, or a block.
165
+ #
166
+ # @example Prepending content with a String
167
+ # <% prepend :sidebar, "Some content." %>
168
+ #
169
+ # @example Prepending content with a block:
170
+ # <% prepend :sidebar do %>
171
+ # Some content.
172
+ # <% end %>
173
+ #
174
+ # @param [Symbol] name
175
+ # A name to identify the area of content you wish to prepend to
176
+ #
177
+ # @param [String] content
178
+ # Optionally provide a String of content, instead of a block. A block will
179
+ # take precedence.
180
+ def prepend(name, content = nil, &block)
181
+ content = capture(&block) if block_given?
182
+ add_instruction_to_area name, :unshift, content
183
+ end
184
+
185
+ # Replaces the content of an area previously declared or modified in parent
186
+ # layout(s). You can provide the content using either a String, or a block.
187
+ #
188
+ # @example Replacing content with a String
189
+ # <% replace :sidebar, "New content." %>
190
+ #
191
+ # @example Replacing content with a block:
192
+ # <% replace :sidebar do %>
193
+ # New content.
194
+ # <% end %>
195
+ #
196
+ # @param [Symbol] name
197
+ # A name to identify the area of content you wish to replace
198
+ #
199
+ # @param [String] content
200
+ # Optionally provide a String of content, instead of a block. A block will
201
+ # take precedence.
202
+ def replace(name, content = nil, &block)
203
+ content = capture(&block) if block_given?
204
+ add_instruction_to_area name, :replace, [content]
205
+ end
206
+
207
+ # Purge the content of an area previously declared or modified in parent
208
+ # layout(s).
209
+ #
210
+ # @example Purge content
211
+ # <% purge :sidebar %>
212
+ #
213
+ # @param names
214
+ # A list of area names to purge
215
+ def purge(*names)
216
+ names.each { |name| replace(name, nil) }
217
+ end
218
+
219
+ private
220
+
221
+ # We record the instructions (declaring, appending, prepending and
222
+ # replacing) for an area of content into an array that we can later retrieve
223
+ # and replay. Instructions are stored in an instance variable Hash
224
+ # `@_area_for`, with each key representing an area name, and each value an
225
+ # Array of instructions. Each instruction is a two element array containing
226
+ # a instruction method (eg `:push`, `:unshift`, `:replace`) and a value
227
+ # (content String).
228
+ #
229
+ # @_area_for[:sidebar] # => [ [:push,"World"], [:unshift,"Hello"] ]
230
+ #
231
+ # Due to the way we extend layouts (render the parent layout after the
232
+ # child), the instructions are captured in reverse order. `render_area`
233
+ # reversed them and plays them back at rendering time.
234
+ #
235
+ # @example
236
+ # add_instruction_to_area(:sidebar, :push, "More content.")
237
+ def add_instruction_to_area(name, instruction, value)
238
+ @_area_for ||= {}
239
+ @_area_for[name] ||= []
240
+ @_area_for[name] << [instruction, value]
241
+ nil
242
+ end
243
+
244
+ # Take the instructions we've gathered for the area and replay them one
245
+ # after the other on an empty array. These instructions will push, unshift
246
+ # or replace items into our output array, which we then join and mark as
247
+ # html_safe.
248
+ #
249
+ # These instructions are reversed and replayed when we render the block
250
+ # (rather than as they happen) due to the way they are gathered by the
251
+ # layout extension process (in reverse).
252
+ def render_area(name)
253
+ [].tap do |output|
254
+ @_area_for.fetch(name, []).reverse_each do |method_name, content|
255
+ output.public_send method_name, content
256
+ end
257
+ end.join.html_safe
258
+ end
259
+ end
260
+ end