context_exposer 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|