context_exposer 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +93 -3
- data/lib/context_exposer/base_controller.rb +80 -0
- data/lib/context_exposer/core_ext/string.rb +13 -0
- data/lib/context_exposer/integrations/with_draper.rb +22 -0
- data/lib/context_exposer/page/resource.rb +49 -0
- data/lib/context_exposer/page.rb +44 -0
- data/lib/context_exposer/page_context.rb +27 -0
- data/lib/context_exposer/patch/decorates_before_rendering.rb +32 -16
- data/lib/context_exposer/resource_controller.rb +5 -9
- data/lib/context_exposer/version.rb +1 -1
- data/lib/context_exposer/view_context.rb +21 -2
- data/lib/context_exposer/view_helpers.rb +15 -0
- data/lib/context_exposer.rb +6 -0
- data/spec/context_exposer/expose_resource_spec.rb +15 -5
- data/spec/context_exposer/expose_spec.rb +70 -4
- data/spec/dummy/app/views/items/index.html.erb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 636d3dfdd4dc2b214e8f8b4b21be110979c458b2
|
4
|
+
data.tar.gz: 1ee51b21d57d43d0320a7096445c6bfe1609b6a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 093d90e0c742c7516b8dfd3caba617758a0d7ba7febcd5ea129b9552e262c8a9583cd8b4a6652ff514039557bafb96b6565baf69f81f19117846706ad801fb82
|
7
|
+
data.tar.gz: 5607a5cacf2b0ba969b498dd61d4a0e4b2a6dc6debe90b000907dd6bc05c32470f648e4b7d80999210a2cbc605e61e731637325653d40d9a4f47545e44998ac1
|
data/README.md
CHANGED
@@ -12,6 +12,7 @@ The gem comes with integrations ready for easy migration or symbiosis with exist
|
|
12
12
|
* exposing of instance variables (Rails default strategy)
|
13
13
|
* decent_exposure gem (expose methods)
|
14
14
|
* decorates_before_rendering gem (expose decorated instance vars)
|
15
|
+
* draper
|
15
16
|
|
16
17
|
For more on integration (and migration path) see below ;)
|
17
18
|
|
@@ -98,7 +99,7 @@ class PostsController < ActionController::Base
|
|
98
99
|
exposed(:posts) { Post.all }
|
99
100
|
|
100
101
|
# Array of model instances
|
101
|
-
exposed(:
|
102
|
+
exposed(:post_list) { Post.all.to_a }
|
102
103
|
end
|
103
104
|
```
|
104
105
|
|
@@ -148,7 +149,7 @@ The `ResourceController` automatically sets up the typical singular and plural-f
|
|
148
149
|
|
149
150
|
* `post` - one Post instance
|
150
151
|
* `posts` - Search Relatation (for lazy load or further scoping)
|
151
|
-
* `
|
152
|
+
* `post_list` - Array of Post instances
|
152
153
|
|
153
154
|
This simplifies the above `PostsController` example to this:
|
154
155
|
|
@@ -161,7 +162,7 @@ class PostsController < ActionController::Base
|
|
161
162
|
end
|
162
163
|
```
|
163
164
|
|
164
|
-
The macro `expose_resources` optionally takes a list of the types of resource you want to expose. Valid types are `:one`, `:many` and `:list` respectively (for fx: `post`, `posts` and `
|
165
|
+
The macro `expose_resources` optionally takes a list of the types of resource you want to expose. Valid types are `:one`, `:many` and `:list` respectively (for fx: `post`, `posts` and `post_list`).
|
165
166
|
|
166
167
|
`ContextExposer::ResourceController` uses the following internal logic for its default functionality. You can override these methods to customize your behavior as needed.
|
167
168
|
|
@@ -264,6 +265,23 @@ HAML view example
|
|
264
265
|
%h2 = post.name
|
265
266
|
```
|
266
267
|
|
268
|
+
## Draper
|
269
|
+
|
270
|
+
The `draper` gem adds a `decorates_assigned` method since version *1.1* (see [pull request](https://github.com/drapergem/draper/pull/461)).
|
271
|
+
|
272
|
+
```ruby
|
273
|
+
decorates_assigned :article, with: FancyArticleDecorator
|
274
|
+
decorates_assigned :articles, with: PaginatingCollectionDecorator
|
275
|
+
```
|
276
|
+
|
277
|
+
Since this functionality is very similar to fx `decent_exposure`, it can be used with `ctx` in a similar way. Simply use the `context_expose_assigned` macro.
|
278
|
+
|
279
|
+
`context_expose_assigned :post, :posts`
|
280
|
+
|
281
|
+
In the near future there should be even better integration, so you don't have to specify the method names to expose all, just like for `context_expose_decently` ;)
|
282
|
+
|
283
|
+
See [commit comment](https://github.com/haines/draper/commit/afa97bb401666f47ef380d7c9e8e94a8b472597d#commitcomment-2844631)
|
284
|
+
|
267
285
|
## Decorates before rendering
|
268
286
|
|
269
287
|
A patch for the `decorates_before_render` gem is currently made available.
|
@@ -306,6 +324,78 @@ end
|
|
306
324
|
|
307
325
|
If the auto-decoration can't find a decorator for an exposed variable (or method), it will either ignore it (not decorate it) or call `__handle_decorate_error_(error)` which by default will log a Rails warning. Override this error handler as it suits you.
|
308
326
|
|
327
|
+
## Globalizing the page context
|
328
|
+
|
329
|
+
As you have the `ctx` object encapsulate all the view state in one place, you can simplify
|
330
|
+
your partial calls to `render partial: 'my/partial/template', locals: {ctx: ctx}`.
|
331
|
+
However, if you use nested partials it quickly feels repetitive...
|
332
|
+
|
333
|
+
Which is why this pattern is now encapsulated in the view helper `render_ctx` which auto-populates the `:locals` hash with a local `page_context` variable that points to a `ContextExposer::PageContext.instance` which contains the `ctx` object :)
|
334
|
+
|
335
|
+
Furthermore, a delegation of `ctx` to `page_context.ctx` is defined so you can still access `ctx` directly from within the views.
|
336
|
+
|
337
|
+
So you then only have to use the locals hash if you want to pass on variables not part of `ctx`.
|
338
|
+
|
339
|
+
```ruby
|
340
|
+
render_ctx partial: 'my/partial/template'
|
341
|
+
```
|
342
|
+
|
343
|
+
### Page object
|
344
|
+
|
345
|
+
To further help in making page rendering decissions, a `ContextExposer::Page` instance is
|
346
|
+
created and populated on each request, which can contain the following data:
|
347
|
+
|
348
|
+
`:name, :id, :action, :mode, :controller_name, :type, :resource`
|
349
|
+
|
350
|
+
The Page instance will attempt to calculate the resource name from the `normalized_resource_name` method of the `ContextExposer::BaseController`. Override this method to calculate a custom resource name for the controller.
|
351
|
+
|
352
|
+
The page name will normally be calculated by concatenating action, resource name and type, so a `PostController#show` action will have the default name `'show_post_item'`. Resource `type` is either `:list` or `:item` and will be attempted calculated using the action name and looking up in the `list_actions` and `item_actions` class methods on the controller.
|
353
|
+
|
354
|
+
By default these methods will use the `base_list_actions` (index) and `base_item_actions` (show, new, edit). You can override/extend these conventions and provide your own `list_actions` and `item_actions` class methods for each controller. Macros are provided to generate these methods from a simple list.
|
355
|
+
|
356
|
+
```ruby
|
357
|
+
class Admin::BirdLocationController < ActionController::Base
|
358
|
+
# expose, decorate etc left out
|
359
|
+
|
360
|
+
# use macros to configure extra REST-like actions
|
361
|
+
list_actions :manage
|
362
|
+
item_actions :map
|
363
|
+
|
364
|
+
# custom page object config just before render
|
365
|
+
after_filter :set_page_mode
|
366
|
+
|
367
|
+
# manage many birds
|
368
|
+
def manage
|
369
|
+
Bird.all
|
370
|
+
end
|
371
|
+
|
372
|
+
# show a single bird location on the map
|
373
|
+
def map
|
374
|
+
Bird.find params[:id]
|
375
|
+
end
|
376
|
+
|
377
|
+
protected
|
378
|
+
|
379
|
+
def set_page_mode
|
380
|
+
ctx.page.mode = mode
|
381
|
+
end
|
382
|
+
|
383
|
+
# custom calculated page name using fx action_name method and params etc
|
384
|
+
def page_name
|
385
|
+
"#{action_name}_#{mode}"
|
386
|
+
end
|
387
|
+
|
388
|
+
# map, details or normal mode ?
|
389
|
+
def mode
|
390
|
+
params[:mode]
|
391
|
+
end
|
392
|
+
|
393
|
+
def self.normalized_resource_name
|
394
|
+
:bird
|
395
|
+
end
|
396
|
+
end
|
397
|
+
```
|
398
|
+
|
309
399
|
## Testing
|
310
400
|
|
311
401
|
The tests have been written in rspec 2 and capybara.
|
@@ -8,6 +8,8 @@ module ContextExposer::BaseController
|
|
8
8
|
# before_filter :configure_exposed_context
|
9
9
|
set_callback :process_action, :before, :configure_exposed_context
|
10
10
|
|
11
|
+
set_callback :process_action, :after, :save_exposed_context
|
12
|
+
|
11
13
|
expose_context :ctx
|
12
14
|
end
|
13
15
|
|
@@ -17,6 +19,10 @@ module ContextExposer::BaseController
|
|
17
19
|
alias_method :ctx, :view_ctx
|
18
20
|
|
19
21
|
module ClassMethods
|
22
|
+
def normalized_resource_name
|
23
|
+
self.to_s.demodulize.sub(/Controller$/, '').underscore.singularize
|
24
|
+
end
|
25
|
+
|
20
26
|
def exposed name, options = {}, &block
|
21
27
|
_exposure_storage[name.to_sym] = {options: options, proc: block}
|
22
28
|
end
|
@@ -31,6 +37,30 @@ module ContextExposer::BaseController
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
40
|
+
def base_list_actions
|
41
|
+
[:index]
|
42
|
+
end
|
43
|
+
|
44
|
+
def base_item_actions
|
45
|
+
[:show, :new, :edit]
|
46
|
+
end
|
47
|
+
|
48
|
+
def list_actions *names
|
49
|
+
return if names.blank?
|
50
|
+
names = names.flatten.map(&:to_sym)
|
51
|
+
(class << self; end).define_method :list_actions do
|
52
|
+
names | base_list_actions
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def item_actions *names
|
57
|
+
return if names.blank?
|
58
|
+
names = names.flatten.map(&:to_sym)
|
59
|
+
(class << self; end).define_method :item_actions do
|
60
|
+
names | base_item_actions
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
34
64
|
def integrate_with *names
|
35
65
|
names.flatten.compact.each do |name|
|
36
66
|
self.send :include, "ContextExposer::Integrations::With#{name.to_s.camelize}".constantize
|
@@ -83,6 +113,56 @@ module ContextExposer::BaseController
|
|
83
113
|
@configured_exposed_context = true
|
84
114
|
end
|
85
115
|
|
116
|
+
def save_exposed_context
|
117
|
+
ContextExposer::PageContext.instance.configure ctx, page_obj
|
118
|
+
end
|
119
|
+
|
120
|
+
def page_obj
|
121
|
+
@page ||= build_page_obj
|
122
|
+
end
|
123
|
+
|
124
|
+
# TODO: cleanup!
|
125
|
+
def build_page_obj
|
126
|
+
return @page if @page
|
127
|
+
@page = ContextExposer::Page.instance
|
128
|
+
@page.clear!
|
129
|
+
clazz = self.class
|
130
|
+
|
131
|
+
# single or list resource ?
|
132
|
+
@page.resource.type = calc_resource_type if calc_resource_type
|
133
|
+
|
134
|
+
# also attempts to auto-caluclate resource.type if not set
|
135
|
+
@page.resource.name = if clazz.respond_to?(:normalized_resource_name, true)
|
136
|
+
clazz.normalized_resource_name
|
137
|
+
else
|
138
|
+
clazz.resource_name if clazz.respond_to?(:resource_name, true)
|
139
|
+
end
|
140
|
+
|
141
|
+
@page.controller = self
|
142
|
+
|
143
|
+
@page.name = if respond_to?(:page_name, true)
|
144
|
+
page_name
|
145
|
+
else
|
146
|
+
@page_name if @page_name
|
147
|
+
end
|
148
|
+
|
149
|
+
@page
|
150
|
+
end
|
151
|
+
|
152
|
+
def calc_resource_type
|
153
|
+
return @resource_type if @resource_type
|
154
|
+
clazz = self.class
|
155
|
+
|
156
|
+
if clazz.respond_to?(:list_actions, true) && !clazz.list_actions.blank?
|
157
|
+
resource_type = :list if clazz.list_actions[action_name.to_sym]
|
158
|
+
end
|
159
|
+
|
160
|
+
if !resource_type && clazz.respond_to?(:item_actions, true) && !clazz.item_actions.blank?
|
161
|
+
resource_type = :item if clazz.item_actions[action_name.to_sym]
|
162
|
+
end
|
163
|
+
@resource_type = resource_type
|
164
|
+
end
|
165
|
+
|
86
166
|
def configured_exposed_context?
|
87
167
|
@configured_exposed_context == true
|
88
168
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ContextExposer::Integrations
|
2
|
+
module WithDecentExposure
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
# expose all exposures exposed by decent_exposure to context
|
7
|
+
def context_expose_assigned *names
|
8
|
+
options = names.extract_options!
|
9
|
+
expose_keys = names
|
10
|
+
expose_keys = _assigned.keys if expose_keys.empty? && respond_to? :_assigned
|
11
|
+
return if expose_keys.blank?
|
12
|
+
|
13
|
+
_exposure_filter(expose_keys, options).each do |exposure|
|
14
|
+
exposed exposure do
|
15
|
+
send(exposure)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
alias_method :expose_decently, :context_expose_decently
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ContextExposer
|
2
|
+
class Page
|
3
|
+
class Resource
|
4
|
+
attr_accessor :name, :type, :controller
|
5
|
+
|
6
|
+
def initialize name = nil, type = nil
|
7
|
+
self.name = name
|
8
|
+
self.type = type if type
|
9
|
+
end
|
10
|
+
|
11
|
+
def type= type
|
12
|
+
validate_type! type
|
13
|
+
@type = type.to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
def name= name
|
17
|
+
@name = name.to_s
|
18
|
+
unless @type
|
19
|
+
@type = calc_type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def page_context
|
26
|
+
ContextExposer::PageContext.instance
|
27
|
+
end
|
28
|
+
|
29
|
+
def calc_type
|
30
|
+
return nil if name.blank?
|
31
|
+
name.to_s.plural? ? :list : :item
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate_type! type
|
35
|
+
unless valid_type? type
|
36
|
+
raise ArgumentError, "type must be one of: #{valid_types}, was: #{type}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid_type? type
|
41
|
+
valid_types.include? type.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_types
|
45
|
+
[:list, :item]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'context_exposer/page/resource'
|
2
|
+
|
3
|
+
module ContextExposer
|
4
|
+
class Page
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_accessor :name, :id, :action, :mode, :controller_name, :type, :resource
|
8
|
+
|
9
|
+
def configure name = nil, options = {}
|
10
|
+
self.name = name
|
11
|
+
self.type = options[:type]
|
12
|
+
self.resource.name = options[:resource_name]
|
13
|
+
self.resource.type = options[:resource_type]
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear!
|
17
|
+
instance_variables.each do |inst_var|
|
18
|
+
var = inst_var.to_s.sub('@', '')
|
19
|
+
self.send("#{var}=", nil)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# action= 'show', resource.name = 'post' and resource.type = :item
|
24
|
+
# show_post_item
|
25
|
+
# action= 'manage', resource.name = 'post' and resource.type = :list
|
26
|
+
# manage_post_list
|
27
|
+
def name
|
28
|
+
@name ||= [action, resource.name, resource.type].compact.map(&:to_s).join('_').underscore
|
29
|
+
end
|
30
|
+
|
31
|
+
def controller= controller
|
32
|
+
@action = controller.action_name
|
33
|
+
@controller_name = controller.controller_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def resource
|
37
|
+
@resource ||= Resource.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def map?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ContextExposer
|
2
|
+
class PageContext
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
attr_accessor :ctx
|
6
|
+
|
7
|
+
def configure ctx, page = nil
|
8
|
+
self.ctx = ctx
|
9
|
+
self.page = page if page
|
10
|
+
end
|
11
|
+
|
12
|
+
def ctx= ctx
|
13
|
+
unless ctx.kind_of? ContextExposer::ViewContext
|
14
|
+
raise ArgumentErorr, "Must be a kind of ContextExposer::ViewContext, was: #{ctx}"
|
15
|
+
end
|
16
|
+
@ctx = ctx
|
17
|
+
end
|
18
|
+
|
19
|
+
def page= page
|
20
|
+
ctx.page = page
|
21
|
+
end
|
22
|
+
|
23
|
+
def page
|
24
|
+
ctx.page if ctx
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -2,11 +2,15 @@ module DecoratesBeforeRendering
|
|
2
2
|
class FindModelError < StandardError; end
|
3
3
|
class DecoratorError < StandardError; end
|
4
4
|
|
5
|
-
|
6
|
-
__auto_decorate_exposed_ones_
|
7
|
-
super(*args)
|
5
|
+
included do
|
6
|
+
after_filter :__auto_decorate_exposed_ones_
|
8
7
|
end
|
9
8
|
|
9
|
+
# def render *args
|
10
|
+
# __auto_decorate_exposed_ones_
|
11
|
+
# super(*args)
|
12
|
+
# end
|
13
|
+
|
10
14
|
def __auto_decorate_exposed_ones_
|
11
15
|
__decorate_ivars__
|
12
16
|
__decorate_exposed_ones_
|
@@ -17,27 +21,41 @@ module DecoratesBeforeRendering
|
|
17
21
|
|
18
22
|
def __handle_decorate_error_ e
|
19
23
|
# puts "Error: #{e}"
|
20
|
-
|
21
24
|
if defined?(::Rails) && (Rails.respond_to? :logger)
|
22
25
|
Rails.logger.warn 'decorates_before_render: auto_decorate error: #{e}'
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
26
29
|
def __exposed_ones_
|
27
|
-
return [] unless
|
28
|
-
@__exposed_ones_ ||=
|
30
|
+
return [] unless _has_exposures?
|
31
|
+
@__exposed_ones_ ||= _exposure_keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def _exposure_keys
|
35
|
+
self.class._exposures.keys
|
36
|
+
end
|
37
|
+
|
38
|
+
def _has_exposures?
|
39
|
+
self.class.respond_to? :_exposures
|
29
40
|
end
|
30
41
|
|
31
42
|
def __ctx_exposed_ones_
|
32
|
-
return [] unless
|
33
|
-
@__ctx_exposed_ones_ ||=
|
43
|
+
return [] unless _has_exposure_storage?
|
44
|
+
@__ctx_exposed_ones_ ||= _cxt_exposed_keys
|
45
|
+
end
|
46
|
+
|
47
|
+
def _cxt_exposed_keys
|
48
|
+
self.class._exposure_storage.keys
|
49
|
+
end
|
50
|
+
|
51
|
+
def _has_exposure_storage?
|
52
|
+
self.class.respond_to? :_exposure_storage
|
34
53
|
end
|
35
54
|
|
36
55
|
def __decorate_exposed_ones_
|
37
56
|
__exposed_ones_.each do |name|
|
38
57
|
ivar_name = "@#{name}"
|
39
|
-
|
40
|
-
decorated = __attempt_to_decorate_(obj)
|
58
|
+
objs = send(name)
|
41
59
|
|
42
60
|
decorated = case objs
|
43
61
|
when Array
|
@@ -73,6 +91,7 @@ module DecoratesBeforeRendering
|
|
73
91
|
end
|
74
92
|
|
75
93
|
def __attempt_to_decorate_ obj
|
94
|
+
return obj if obj.respond_to?(:decorate)
|
76
95
|
if obj
|
77
96
|
src = __src_for__(obj)
|
78
97
|
decorator = __normalized_decorator_for__(src)
|
@@ -81,6 +100,8 @@ module DecoratesBeforeRendering
|
|
81
100
|
end
|
82
101
|
|
83
102
|
def __do_decoration_ decorator, obj
|
103
|
+
return obj if obj.respond_to?(:decorate)
|
104
|
+
|
84
105
|
return if !decorator || !obj
|
85
106
|
__validate_decorator!(decorator)
|
86
107
|
decorator.decorate(obj)
|
@@ -136,18 +157,13 @@ module DecoratesBeforeRendering
|
|
136
157
|
end
|
137
158
|
|
138
159
|
def __decorate_ivars__
|
160
|
+
return unless __has_decorates?
|
139
161
|
__validate_decorates_present_
|
140
162
|
return if __decorates_blank?
|
141
163
|
__decorates__ivars
|
142
164
|
__decorates_collection_ivars__
|
143
165
|
end
|
144
166
|
|
145
|
-
def __validate_decorates_present_
|
146
|
-
unless __has_decorates?
|
147
|
-
raise "Internal method '__decorates__' not found. You need to include the 'decorates_before_render' gem "
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
167
|
def __has_decorates?
|
152
168
|
respond_to?(:__decorates__)
|
153
169
|
end
|
@@ -14,15 +14,15 @@ module ContextExposer::ResourceController
|
|
14
14
|
types = types.empty? ? [:all] : types
|
15
15
|
|
16
16
|
unless expose_resource_method? :one, types
|
17
|
-
_exposing(
|
17
|
+
_exposing(normalized_resource_name.singularize) { find_single_resource }
|
18
18
|
end
|
19
19
|
|
20
20
|
unless expose_resource_method? :many, types
|
21
|
-
_exposing(
|
21
|
+
_exposing(normalized_resource_name.pluralize) { find_all_resources }
|
22
22
|
end
|
23
23
|
|
24
24
|
unless expose_resource_method? :list, types
|
25
|
-
_exposing(
|
25
|
+
_exposing(normalized_resource_list) { find_all_resources.to_a }
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -57,12 +57,8 @@ module ContextExposer::ResourceController
|
|
57
57
|
raise "Resource #{clazz_name} is not defined. #{e}"
|
58
58
|
end
|
59
59
|
|
60
|
-
def
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def _normalized_resource_name
|
65
|
-
self.to_s.demodulize.sub(/Controller$/, '').underscore
|
60
|
+
def normalized_resource_list
|
61
|
+
normalized_resource_name.singularize + '_list'
|
66
62
|
end
|
67
63
|
end
|
68
64
|
end
|
@@ -1,12 +1,31 @@
|
|
1
1
|
class ContextExposer::ViewContext
|
2
|
-
attr_reader
|
2
|
+
attr_reader :controller
|
3
|
+
attr_accessor :page
|
3
4
|
|
4
|
-
def initialize controller = nil
|
5
|
+
def initialize controller = nil, page = nil
|
5
6
|
@controller = controller
|
7
|
+
self.page = page if page
|
8
|
+
end
|
9
|
+
|
10
|
+
def page= page
|
11
|
+
validate_page! page
|
12
|
+
@page = page
|
6
13
|
end
|
7
14
|
|
8
15
|
protected
|
9
16
|
|
17
|
+
def validate_page! page
|
18
|
+
raise ArgumentError, "Must be a kind of #{valid_page_class}, was: #{page}" unless valid_page? page
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid_page? page
|
22
|
+
page.kind_of? valid_page_class
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_page_class
|
26
|
+
ContextExposer::Page
|
27
|
+
end
|
28
|
+
|
10
29
|
def define_singleton_method(name, &block)
|
11
30
|
eigenclass = class<<self; self end
|
12
31
|
eigenclass.class_eval {define_method name, block}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ContextExposer
|
2
|
+
module ViewHelpers
|
3
|
+
def render_ctx *args
|
4
|
+
opts = args.last
|
5
|
+
if opts.kind_of?(Hash) && opts[:locals]
|
6
|
+
args.last[:locals].merge!(page_context: ContextExposer::PageContext.instance)
|
7
|
+
end
|
8
|
+
super *args
|
9
|
+
end
|
10
|
+
|
11
|
+
def ctx
|
12
|
+
page_context.ctx
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/context_exposer.rb
CHANGED
@@ -16,9 +16,15 @@ module ContextExposer
|
|
16
16
|
end
|
17
17
|
|
18
18
|
require "active_support"
|
19
|
+
require "context_exposer/core_ext/string"
|
19
20
|
require "context_exposer/base_controller"
|
20
21
|
require "context_exposer/resource_controller"
|
21
22
|
require "context_exposer/cached_resource_controller"
|
22
23
|
require "context_exposer/view_context"
|
23
24
|
require "context_exposer/macros"
|
24
25
|
require "context_exposer/rails_config"
|
26
|
+
|
27
|
+
require 'singleton'
|
28
|
+
require "context_exposer/page_context"
|
29
|
+
require "context_exposer/page"
|
30
|
+
require "context_exposer/view_helpers"
|
@@ -14,6 +14,8 @@ class PostsController < ActionController::Base
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def index
|
17
|
+
configure_exposed_context
|
18
|
+
render
|
17
19
|
end
|
18
20
|
|
19
21
|
protected
|
@@ -72,8 +74,8 @@ describe ContextExposer::ResourceController do
|
|
72
74
|
expect(subject).to respond_to(:posts)
|
73
75
|
end
|
74
76
|
|
75
|
-
it "defines a method :
|
76
|
-
expect(subject).to respond_to(:
|
77
|
+
it "defines a method :post_list" do
|
78
|
+
expect(subject).to respond_to(:post_list)
|
77
79
|
end
|
78
80
|
|
79
81
|
context 'post' do
|
@@ -93,14 +95,22 @@ describe ContextExposer::ResourceController do
|
|
93
95
|
subject { posts }
|
94
96
|
let(:posts) { ctx.posts }
|
95
97
|
|
98
|
+
before :each do
|
99
|
+
controller.index
|
100
|
+
end
|
101
|
+
|
96
102
|
it "calling method :posts returns all posts " do
|
97
103
|
expect(subject).to eq [@post1, @post2]
|
98
104
|
end
|
99
105
|
end
|
100
106
|
|
101
|
-
context '
|
102
|
-
subject
|
103
|
-
let(:
|
107
|
+
context 'post_list' do
|
108
|
+
subject { post_list }
|
109
|
+
let(:post_list) { ctx.post_list }
|
110
|
+
|
111
|
+
before :each do
|
112
|
+
controller.index
|
113
|
+
end
|
104
114
|
|
105
115
|
it "calling method :posts_list returns all posts " do
|
106
116
|
expect(subject).to eq [@post1, @post2]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class BirdController < ActionController::Base
|
4
4
|
include ContextExposer::BaseController
|
5
5
|
|
6
6
|
exposed(:bird) { "Bird" }
|
@@ -16,9 +16,18 @@ class MyController < ActionController::Base
|
|
16
16
|
|
17
17
|
def show
|
18
18
|
configure_exposed_context
|
19
|
+
save_exposed_context
|
20
|
+
end
|
21
|
+
|
22
|
+
def action_name
|
23
|
+
'show'
|
19
24
|
end
|
20
25
|
|
21
26
|
protected
|
27
|
+
|
28
|
+
def self.resource_name
|
29
|
+
:bird
|
30
|
+
end
|
22
31
|
end
|
23
32
|
|
24
33
|
class MyCoolController < ActionController::Base
|
@@ -30,10 +39,19 @@ class MyCoolController < ActionController::Base
|
|
30
39
|
|
31
40
|
def show
|
32
41
|
configure_exposed_context
|
42
|
+
save_exposed_context
|
43
|
+
end
|
44
|
+
|
45
|
+
def action_name
|
46
|
+
'show'
|
33
47
|
end
|
34
48
|
|
35
49
|
protected
|
36
50
|
|
51
|
+
def self.resource_name
|
52
|
+
"MyCool"
|
53
|
+
end
|
54
|
+
|
37
55
|
def params; end
|
38
56
|
end
|
39
57
|
|
@@ -52,7 +70,7 @@ describe ContextExposer::BaseController do
|
|
52
70
|
describe "controller" do
|
53
71
|
subject { controller }
|
54
72
|
|
55
|
-
let(:controller) {
|
73
|
+
let(:controller) { BirdController.new }
|
56
74
|
|
57
75
|
# run action post
|
58
76
|
before :each do
|
@@ -79,7 +97,7 @@ describe ContextExposer::BaseController do
|
|
79
97
|
expect(subject.configured_exposed_context?).to be_true
|
80
98
|
end
|
81
99
|
|
82
|
-
context '
|
100
|
+
context 'ctx' do
|
83
101
|
subject { controller.ctx }
|
84
102
|
|
85
103
|
it "is an instance of ContextExposer::ViewContext" do
|
@@ -102,6 +120,54 @@ describe ContextExposer::BaseController do
|
|
102
120
|
expect(subject.bird).to eq "Bird"
|
103
121
|
end
|
104
122
|
end
|
123
|
+
|
124
|
+
context 'PageContext' do
|
125
|
+
subject { page_context }
|
126
|
+
|
127
|
+
let(:page_context) { ContextExposer::PageContext.instance }
|
128
|
+
|
129
|
+
it "has a page" do
|
130
|
+
expect(subject.page).to be_a ContextExposer::Page
|
131
|
+
end
|
132
|
+
|
133
|
+
it "has a ctx" do
|
134
|
+
expect(subject.ctx).to be_a ContextExposer::ViewContext
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'page' do
|
138
|
+
subject { page }
|
139
|
+
|
140
|
+
let(:page) { page_context.page }
|
141
|
+
|
142
|
+
it "has a name" do
|
143
|
+
expect(subject.name).to eq "show_bird_item"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "has a type" do
|
147
|
+
expect(subject.type).to eq nil
|
148
|
+
end
|
149
|
+
|
150
|
+
it "has an action" do
|
151
|
+
expect(subject.action).to eq 'show'
|
152
|
+
end
|
153
|
+
|
154
|
+
it "has a resource" do
|
155
|
+
expect(subject.resource).to be_a ContextExposer::Page::Resource
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'resource' do
|
159
|
+
subject { page.resource }
|
160
|
+
|
161
|
+
it "has a name" do
|
162
|
+
expect(subject.name).to eq 'bird'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "has a type" do
|
166
|
+
expect(subject.type).to eq :item
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
105
171
|
end
|
106
172
|
|
107
173
|
describe 'MyCoolController' do
|
@@ -114,7 +180,7 @@ describe ContextExposer::BaseController do
|
|
114
180
|
controller.show
|
115
181
|
end
|
116
182
|
|
117
|
-
context '
|
183
|
+
context 'ctx' do
|
118
184
|
subject { controller.ctx }
|
119
185
|
|
120
186
|
it "inherits from ContextExposer::ViewContext" do
|
@@ -1,2 +1,2 @@
|
|
1
1
|
<h1>Items</h1>
|
2
|
-
<%= ctx.
|
2
|
+
<%= ctx.item_list.map {|i| i.nice_name }.inspect %>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: context_exposer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kristian Mandrup
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-03-
|
11
|
+
date: 2013-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -56,18 +56,24 @@ files:
|
|
56
56
|
- lib/context_exposer.rb
|
57
57
|
- lib/context_exposer/base_controller.rb
|
58
58
|
- lib/context_exposer/cached_resource_controller.rb
|
59
|
+
- lib/context_exposer/core_ext/string.rb
|
59
60
|
- lib/context_exposer/integrations.rb
|
60
61
|
- lib/context_exposer/integrations/base.rb
|
61
62
|
- lib/context_exposer/integrations/key_filter.rb
|
62
63
|
- lib/context_exposer/integrations/with_decent_exposure.rb
|
63
64
|
- lib/context_exposer/integrations/with_decorates_before.rb
|
65
|
+
- lib/context_exposer/integrations/with_draper.rb
|
64
66
|
- lib/context_exposer/integrations/with_instance_vars.rb
|
65
67
|
- lib/context_exposer/macros.rb
|
68
|
+
- lib/context_exposer/page.rb
|
69
|
+
- lib/context_exposer/page/resource.rb
|
70
|
+
- lib/context_exposer/page_context.rb
|
66
71
|
- lib/context_exposer/patch/decorates_before_rendering.rb
|
67
72
|
- lib/context_exposer/rails_config.rb
|
68
73
|
- lib/context_exposer/resource_controller.rb
|
69
74
|
- lib/context_exposer/version.rb
|
70
75
|
- lib/context_exposer/view_context.rb
|
76
|
+
- lib/context_exposer/view_helpers.rb
|
71
77
|
- spec/app/items_spec.rb
|
72
78
|
- spec/app/posts_spec.rb
|
73
79
|
- spec/context_exposer/expose_resource_spec.rb
|