nestive-rails 1.0.1 → 1.0.2

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