context_exposer 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -16
- data/README.md +65 -8
- data/lib/context_exposer.rb +1 -0
- data/lib/context_exposer/base_controller.rb +26 -3
- data/lib/context_exposer/resource_controller.rb +47 -0
- data/lib/context_exposer/version.rb +1 -1
- data/spec/context_exposer/expose_resource_spec.rb +103 -0
- data/spec/context_exposer/expose_spec.rb +26 -6
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2452c12a649755432297fcee4e4fefb40b864313
|
4
|
+
data.tar.gz: 8ace695b9b00d9f114874aa9b5719064c64a0c83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78721b922904ab3222e41024042691c3998103414314a5f4adf75bf8b34fd6c9a529c7acee68c23af948219b3577727276ffb1c617fd8d1ed21dc93a92484d47
|
7
|
+
data.tar.gz: c0bcbf8cb1781b7fc39f0b1d6246c7b11f931056925f64becd31ab19f3e76606b996b4faa5e67470ec8c407c4dc86bb9ba4c369fe7bfae23330a33f1914bec34
|
data/Gemfile
CHANGED
@@ -3,20 +3,6 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in context_exposer.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem 'pry'
|
7
6
|
gem 'rails', '>= 3.1'
|
8
|
-
|
9
|
-
gem
|
10
|
-
|
11
|
-
group :test do
|
12
|
-
# gem 'factory_girl_rails', :require => false
|
13
|
-
# gem "capybara"
|
14
|
-
# gem "capybara-webkit"
|
15
|
-
# gem 'growl'
|
16
|
-
# gem "spork"
|
17
|
-
# gem "guard"
|
18
|
-
# gem "guard-bundler"
|
19
|
-
# gem "guard-rspec"
|
20
|
-
# gem "guard-spork"
|
21
|
-
# gem "launchy"
|
22
|
-
end
|
7
|
+
gem "rspec-rails", '>= 2.0', group: [:test, :development]
|
8
|
+
gem 'pry', group: [:development]
|
data/README.md
CHANGED
@@ -36,6 +36,14 @@ class PostsController < ActionController::Base
|
|
36
36
|
end
|
37
37
|
```
|
38
38
|
|
39
|
+
HAML view example
|
40
|
+
|
41
|
+
```haml
|
42
|
+
%h1 Posts
|
43
|
+
= context.posts.each do |post|
|
44
|
+
%h2 = post.name
|
45
|
+
```
|
46
|
+
|
39
47
|
You can also define your own subclass of `ViewContext` and designate an instance of this custom class as your "exposed" target, via `view_context_class`method.
|
40
48
|
|
41
49
|
Example:
|
@@ -47,7 +55,7 @@ class PostsController < ActionController::Base
|
|
47
55
|
view_context_class :posts_view_context
|
48
56
|
|
49
57
|
exposed(:post) { Post.find params[:id] }
|
50
|
-
exposed(:posts) { Post.
|
58
|
+
exposed(:posts) { Post.all }
|
51
59
|
end
|
52
60
|
```
|
53
61
|
|
@@ -78,29 +86,78 @@ class PostsViewContext < ContextExposer::ViewContext
|
|
78
86
|
end
|
79
87
|
```
|
80
88
|
|
89
|
+
HAML view example
|
90
|
+
|
91
|
+
```haml
|
92
|
+
%h1 Admin Posts
|
93
|
+
= context.admin_posts.each do |post|
|
94
|
+
%h2 = post.name
|
95
|
+
```
|
96
|
+
|
97
|
+
|
81
98
|
This opens up some amazing possibilities to really put the logic where it belongs.The custom ViewContext would benefit from having the "admin" and "user" logic extracted either to separate modules or a custom ViewContext base class ;)
|
82
99
|
|
83
100
|
This approach opens up many new exciting ways to slice and dice your logic in a much better way, a new *MVC-C* architecture, the extra "C" for *Context*.
|
84
101
|
|
102
|
+
### ResourceController
|
85
103
|
|
86
|
-
|
104
|
+
The `ResourceController` automatically sets up the typical singular and plural-form resource helpers.
|
87
105
|
|
88
|
-
|
89
|
-
Also add some basic modules to integrate with typical authentication solutions etc. Get inspiration from other similar gems, fx `decent_exposure`. Allow for integration between these different solutions.
|
106
|
+
This simplifies the above `PostsController` example to this:
|
90
107
|
|
91
|
-
|
108
|
+
```ruby
|
109
|
+
class PostsController < ActionController::Base
|
110
|
+
include ContextExposer::ResourceController
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
`ResourceController` uses the following internal logic for its default functionality. You can override these methods to customize your behavior as needed.
|
92
115
|
|
93
|
-
|
116
|
+
```ruby
|
117
|
+
module ContextExposer::ResourceController
|
118
|
+
# ...
|
119
|
+
|
120
|
+
protected
|
121
|
+
|
122
|
+
def resource_id
|
123
|
+
params[:id]
|
124
|
+
end
|
125
|
+
|
126
|
+
def find_single_resource
|
127
|
+
self.class._the_resource.find resource_id
|
128
|
+
end
|
129
|
+
|
130
|
+
def find_all_resources
|
131
|
+
self.class._the_resource.all
|
132
|
+
end
|
133
|
+
```
|
94
134
|
|
95
|
-
|
135
|
+
## Integration with decent_exposure gem
|
136
|
+
|
137
|
+
Initial integration support is included for `decent_exposure`, another popular gem with similar functionality. To add methods exposed by `decent_exposure` `#expose` to the context object, simply call `#context_expose_decently` or the alias method `#expose_decently`.
|
96
138
|
|
97
139
|
```ruby
|
140
|
+
# using gem 'decent_exposure'
|
141
|
+
# auto-included in ActionController::Base
|
142
|
+
|
98
143
|
class PostsController < ActionController::Base
|
99
144
|
include ContextExposer::ResourceController
|
145
|
+
|
146
|
+
expose(:posts)
|
147
|
+
expose(:post) { Post.first}
|
148
|
+
expose(:postal)
|
149
|
+
|
150
|
+
context_expose_decently except: 'postal'
|
100
151
|
end
|
101
152
|
```
|
102
153
|
|
103
|
-
|
154
|
+
HAML view example
|
155
|
+
|
156
|
+
```haml
|
157
|
+
%h1 Posts
|
158
|
+
= context.posts.each do |post|
|
159
|
+
%h2 = post.name
|
160
|
+
```
|
104
161
|
|
105
162
|
## Contributing
|
106
163
|
|
data/lib/context_exposer.rb
CHANGED
@@ -5,6 +5,8 @@ module ContextExposer::BaseController
|
|
5
5
|
before_filter :configure_exposed_context
|
6
6
|
|
7
7
|
expose_context :context
|
8
|
+
|
9
|
+
# set_callback :process_action, :before, :configure_exposed_context
|
8
10
|
end
|
9
11
|
|
10
12
|
def view_context
|
@@ -18,6 +20,26 @@ module ContextExposer::BaseController
|
|
18
20
|
exposure_storage[name.to_sym] = block
|
19
21
|
end
|
20
22
|
|
23
|
+
# expose all exposures exposed by decent_exposure to context
|
24
|
+
def context_expose_decently options = {}
|
25
|
+
transfer_keys = _exposures.keys
|
26
|
+
except = (options[:except] || {}).map(&:to_sym)
|
27
|
+
only = (options[:only] || {}).map(&:to_sym)
|
28
|
+
|
29
|
+
transfer_keys = transfer_keys - except
|
30
|
+
|
31
|
+
unless only.empty?
|
32
|
+
transfer_keys.select {|k| only.include? k.to_sym }
|
33
|
+
end
|
34
|
+
|
35
|
+
transfer_keys.each do |exposure|
|
36
|
+
exposed exposure do
|
37
|
+
send(exposure)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias_method :expose_decently, :context_expose_decently
|
42
|
+
|
21
43
|
def view_context_class name
|
22
44
|
define_method :view_context_class do
|
23
45
|
@view_context_class ||= name.kind_of?(Class) ? name : name.to_s.camelize.constantize
|
@@ -28,6 +50,7 @@ module ContextExposer::BaseController
|
|
28
50
|
|
29
51
|
def expose_context name
|
30
52
|
return if exposed_view_context?
|
53
|
+
|
31
54
|
if ActionController::Base.instance_methods.include?(name.to_sym)
|
32
55
|
Kernel.warn "[WARNING] You are exposing the `#{name}` method, " \
|
33
56
|
"which overrides an existing ActionController method of the same name. " \
|
@@ -40,7 +63,7 @@ module ContextExposer::BaseController
|
|
40
63
|
end
|
41
64
|
|
42
65
|
def exposed_view_context?
|
43
|
-
@exposed_view_context
|
66
|
+
@exposed_view_context == true
|
44
67
|
end
|
45
68
|
|
46
69
|
def exposure_storage
|
@@ -57,10 +80,10 @@ module ContextExposer::BaseController
|
|
57
80
|
return if configured_exposed_context?
|
58
81
|
clazz = self.class
|
59
82
|
exposed_methods = clazz.send(:exposure_hash)[clazz.to_s] || []
|
60
|
-
# puts "exposed_methods for: #{clazz} - #{exposed_methods}"
|
61
83
|
exposed_methods.each do |name, procedure|
|
84
|
+
this = self
|
62
85
|
view_context.send :define_singleton_method, name do
|
63
|
-
procedure
|
86
|
+
this.instance_eval(&procedure)
|
64
87
|
end
|
65
88
|
end
|
66
89
|
@configured_exposed_context = true
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ContextExposer::ResourceController
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
include ContextExposer::BaseController
|
4
|
+
|
5
|
+
included do
|
6
|
+
puts "included: #{_normalized_resource_name}"
|
7
|
+
|
8
|
+
exposed(_normalized_resource_name.singularize) do
|
9
|
+
find_single_resource
|
10
|
+
end
|
11
|
+
|
12
|
+
exposed(_normalized_resource_name.pluralize) { find_all_resources }
|
13
|
+
exposed(_normalized_resource_list) { find_all_resources.to_a }
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def resource_id
|
19
|
+
params[:id]
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_single_resource
|
23
|
+
self.class._the_resource.find resource_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_all_resources
|
27
|
+
self.class._the_resource.all
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def _the_resource
|
32
|
+
clazz_name = self.to_s.sub(/Controller$/, '').singularize
|
33
|
+
clazz_name.constantize
|
34
|
+
rescue NameError => e
|
35
|
+
raise "Resource #{clazz_name} is not defined. #{e}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def _normalized_resource_list
|
39
|
+
_normalized_resource_name.pluralize + '_list'
|
40
|
+
end
|
41
|
+
|
42
|
+
def _normalized_resource_name
|
43
|
+
self.to_s.demodulize.sub(/Controller$/, '').underscore
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'context_exposer'
|
2
|
+
# require 'rails'
|
3
|
+
require 'action_controller'
|
4
|
+
|
5
|
+
class Post
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
def initialize name
|
9
|
+
@name = name
|
10
|
+
Post.add self
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find id
|
14
|
+
list.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.all
|
18
|
+
Post.list
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def self.add post
|
24
|
+
list << post
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.list
|
28
|
+
@list ||= []
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class PostsController < ActionController::Base
|
33
|
+
include ContextExposer::ResourceController
|
34
|
+
|
35
|
+
def show
|
36
|
+
configure_exposed_context
|
37
|
+
end
|
38
|
+
|
39
|
+
def index
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def params
|
45
|
+
{id: 1}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ContextExposer::ResourceController do
|
50
|
+
describe "controller" do
|
51
|
+
subject { controller }
|
52
|
+
|
53
|
+
let(:controller) { PostsController.new }
|
54
|
+
|
55
|
+
before :all do
|
56
|
+
@post1 = Post.new 'My 1st post'
|
57
|
+
@post2 = Post.new 'My 2nd post'
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'show post' do
|
61
|
+
# run action post
|
62
|
+
before :each do
|
63
|
+
controller.show
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'defines :show as an action_method' do
|
67
|
+
expect(subject.action_methods).to include('show')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "defines a method context" do
|
71
|
+
expect(subject).to respond_to(:context)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "exposes the context to the view layer as a helper" do
|
75
|
+
expect(subject._helper_methods).to include(:context)
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'context' do
|
79
|
+
subject { controller.context }
|
80
|
+
|
81
|
+
it "is an instance of ContextExposer::ViewContext" do
|
82
|
+
expect(subject).to be_a ContextExposer::ViewContext
|
83
|
+
end
|
84
|
+
|
85
|
+
it "defines a method :post" do
|
86
|
+
expect(subject).to respond_to(:post)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "defines a method :posts" do
|
90
|
+
expect(subject).to respond_to(:posts)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "calling method :post returns 'My 1st post' " do
|
94
|
+
expect(subject.post.name).to eq @post1.name
|
95
|
+
end
|
96
|
+
|
97
|
+
it "calling method :posts returns all posts " do
|
98
|
+
expect(subject.posts).to eq [@post1, @post2]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -4,10 +4,20 @@ require 'action_controller'
|
|
4
4
|
class MyController < ActionController::Base
|
5
5
|
include ContextExposer::BaseController
|
6
6
|
|
7
|
-
exposed(:
|
7
|
+
exposed(:bird) { "Bird" }
|
8
8
|
|
9
|
-
|
9
|
+
# since: extend DecentExposure::Exposure
|
10
|
+
def self._exposures
|
11
|
+
{decent: 'hi', hello: 'yo!'}
|
12
|
+
end
|
13
|
+
|
14
|
+
expose_decently except: %w{hello}
|
15
|
+
|
16
|
+
def show
|
17
|
+
configure_exposed_context
|
10
18
|
end
|
19
|
+
|
20
|
+
protected
|
11
21
|
end
|
12
22
|
|
13
23
|
class MyCoolController < ActionController::Base
|
@@ -21,7 +31,9 @@ class MyCoolController < ActionController::Base
|
|
21
31
|
configure_exposed_context
|
22
32
|
end
|
23
33
|
|
24
|
-
|
34
|
+
protected
|
35
|
+
|
36
|
+
def params; end
|
25
37
|
end
|
26
38
|
|
27
39
|
class MegaCoolViewContext < ContextExposer::ViewContext
|
@@ -43,11 +55,11 @@ describe ContextExposer::BaseController do
|
|
43
55
|
|
44
56
|
# run action post
|
45
57
|
before :each do
|
46
|
-
controller.
|
58
|
+
controller.show
|
47
59
|
end
|
48
60
|
|
49
|
-
it 'defines :
|
50
|
-
expect(subject.action_methods).to include('
|
61
|
+
it 'defines :show as an action_method' do
|
62
|
+
expect(subject.action_methods).to include('show')
|
51
63
|
end
|
52
64
|
|
53
65
|
it "defines a method context" do
|
@@ -77,6 +89,14 @@ describe ContextExposer::BaseController do
|
|
77
89
|
expect(subject).to respond_to(:bird)
|
78
90
|
end
|
79
91
|
|
92
|
+
it "defines a method :decent" do
|
93
|
+
expect(subject).to respond_to(:decent)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "does not defines a decent method :hello" do
|
97
|
+
expect(subject).to_not respond_to(:hello)
|
98
|
+
end
|
99
|
+
|
80
100
|
it "calling method :bird returns 'Bird' " do
|
81
101
|
expect(subject.bird).to eq "Bird"
|
82
102
|
end
|
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.0
|
4
|
+
version: 0.1.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-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -55,9 +55,11 @@ files:
|
|
55
55
|
- context_exposer.gemspec
|
56
56
|
- lib/context_exposer.rb
|
57
57
|
- lib/context_exposer/base_controller.rb
|
58
|
+
- lib/context_exposer/resource_controller.rb
|
58
59
|
- lib/context_exposer/version.rb
|
59
60
|
- lib/context_exposer/view_context.rb
|
60
61
|
- spec/app/posts_spec.rb
|
62
|
+
- spec/context_exposer/expose_resource_spec.rb
|
61
63
|
- spec/context_exposer/expose_spec.rb
|
62
64
|
- spec/dummy/README.rdoc
|
63
65
|
- spec/dummy/Rakefile
|
@@ -122,6 +124,7 @@ summary: The Context object becomes the single communication point between View
|
|
122
124
|
Controller
|
123
125
|
test_files:
|
124
126
|
- spec/app/posts_spec.rb
|
127
|
+
- spec/context_exposer/expose_resource_spec.rb
|
125
128
|
- spec/context_exposer/expose_spec.rb
|
126
129
|
- spec/dummy/README.rdoc
|
127
130
|
- spec/dummy/Rakefile
|