adequate_exposure 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +32 -36
- data/adequate_exposure.gemspec +1 -1
- data/lib/adequate_exposure/context.rb +0 -2
- data/lib/adequate_exposure/controller.rb +7 -6
- data/lib/adequate_exposure/exposure.rb +85 -8
- data/lib/adequate_exposure/flow.rb +17 -38
- data/lib/adequate_exposure/version.rb +1 -1
- data/lib/adequate_exposure.rb +1 -1
- data/spec/controller_spec.rb +120 -19
- data/spec/support/rails_app.rb +0 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82a9cfe00dccb013cca09b85f68073902bb5928d
|
4
|
+
data.tar.gz: 15ec7db35c84401f82a3d8bab5af8079ccf5ea81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ade244f9a2785594a66b5ba042b2639a15157eb39f72234f3e2133d21a27bffe2dcecf3d61a6a79d9768b4a0d6ab5605cd3336600c3d49e848767708385c22a
|
7
|
+
data.tar.gz: 84260440dbd08e8444ce307994f4c564e97b76efc48a5e554d349a5018ba8c3d7d4ec0cf7801d860876cd306ba014ef1b5c2ff0f396b3ded2fdbe1faaedd7660
|
data/README.md
CHANGED
@@ -2,19 +2,24 @@
|
|
2
2
|
|
3
3
|
This is WIP. Please don't send pull requests yet, I'm still actively rewriting things.
|
4
4
|
|
5
|
-
|
5
|
+
Exposing things, adequately.
|
6
6
|
|
7
|
-
Adequate exposure is a lightweight alternative to [Decent
|
7
|
+
Adequate exposure is a lightweight alternative to [Decent
|
8
|
+
Exposure](https://github.com/voxdolo/decent_exposure). With it's narrowly
|
9
|
+
focused api you can get exactly what you need without all the extra dressing.
|
8
10
|
|
9
|
-
*Note: It is not the intent of the author to imply that Decent Exposure is
|
11
|
+
*Note: It is not the intent of the author to imply that Decent Exposure is
|
12
|
+
inadequate.)*
|
10
13
|
|
11
|
-
Installation is as simple as: `$ gem install adequate_exposure`. Once you have
|
14
|
+
Installation is as simple as: `$ gem install adequate_exposure`. Once you have
|
15
|
+
that down we can start talking about the API.
|
12
16
|
|
13
17
|
## API
|
14
18
|
|
15
19
|
The whole API consists of one `expose` method.
|
16
20
|
|
17
|
-
In the simplest scenario you'll just use it to expose a model in the
|
21
|
+
In the simplest scenario you'll just use it to expose a model in the
|
22
|
+
controller:
|
18
23
|
|
19
24
|
```ruby
|
20
25
|
class ThingsController < ApplicationController
|
@@ -22,23 +27,12 @@ class ThingsController < ApplicationController
|
|
22
27
|
end
|
23
28
|
```
|
24
29
|
|
25
|
-
Now every time you call `thing` in your controller or view, it'll look for an
|
30
|
+
Now every time you call `thing` in your controller or view, it'll look for an
|
31
|
+
id and try to perform `Thing.find(id)` or `Thing.new` if the id is not found.
|
32
|
+
It'll also memoize the result in `@exposed_thing` instance variable.
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
```ruby
|
30
|
-
class ThingsController < ApplicationController
|
31
|
-
expose(:thing){ Thing.find(get_thing_id_somehow) }
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def get_thing_id_somehow
|
36
|
-
42
|
37
|
-
end
|
38
|
-
end
|
39
|
-
```
|
40
|
-
|
41
|
-
The default resolving workflow if pretty powerful and customizable. It could be expressed with the following pseudocode:
|
34
|
+
The default resolving workflow if pretty powerful and customizable. It could be
|
35
|
+
expressed with the following pseudocode:
|
42
36
|
|
43
37
|
```ruby
|
44
38
|
def fetch(scope, id)
|
@@ -70,11 +64,22 @@ def decorate(thing)
|
|
70
64
|
end
|
71
65
|
```
|
72
66
|
|
73
|
-
Each step
|
67
|
+
Each step could be overrided with options. The acceptable options to the
|
68
|
+
`expose` macro are:
|
69
|
+
|
70
|
+
**fetch**
|
71
|
+
|
72
|
+
This is the entry point. Fetch proc defines how to resolve your exposure in the
|
73
|
+
first place.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
expose :thing, fetch: ->{ get_thing_some_way_or_another }
|
77
|
+
```
|
74
78
|
|
75
79
|
**find**
|
76
80
|
|
77
|
-
|
81
|
+
Defines how to perform the finding. Could be useful if you don't want to use standard
|
82
|
+
Rails finder.
|
78
83
|
|
79
84
|
```ruby
|
80
85
|
expose :thing, find: ->(id, scope){ scope.find_by(slug: id) }
|
@@ -90,7 +95,7 @@ expose :thing, build: ->(scope){ Thing.build_with_defaults }
|
|
90
95
|
|
91
96
|
**id**
|
92
97
|
|
93
|
-
|
98
|
+
Specifies how to extract id from parameters hash.
|
94
99
|
|
95
100
|
```ruby
|
96
101
|
# default
|
@@ -112,12 +117,11 @@ Defines the scope that's used in `find` and `build` steps.
|
|
112
117
|
|
113
118
|
```ruby
|
114
119
|
expose :thing, scope: ->{ current_user.things }
|
115
|
-
expose :thing, scope: :current_user # the same as above
|
116
120
|
```
|
117
121
|
|
118
122
|
**model**
|
119
123
|
|
120
|
-
Specify the model to use.
|
124
|
+
Specify the model class to use.
|
121
125
|
|
122
126
|
```ruby
|
123
127
|
expose :thing, model: ->{ AnotherThing }
|
@@ -125,18 +129,10 @@ expose :thing, model: AnotherThing
|
|
125
129
|
expose :thing, model: :another_thing
|
126
130
|
```
|
127
131
|
|
128
|
-
**fetch**
|
129
|
-
|
130
|
-
Allows to override the `fetch` logic that's happening when you first call exposed helper.
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
expose :thing, fetch: ->{ get_thing_some_way_or_another }
|
134
|
-
expose(:thing){ get_thing_some_way_or_another }
|
135
|
-
```
|
136
132
|
|
137
133
|
**decorate**
|
138
134
|
|
139
|
-
Allows to define a block that wraps
|
135
|
+
Allows to define a block that wraps an instance before it's returned. Useful for decorators.
|
140
136
|
|
141
137
|
```ruby
|
142
138
|
expose :thing, decorate: ->(thing){ ThingDecorator.new(thing) }
|
@@ -144,7 +140,7 @@ expose :thing, decorate: ->(thing){ ThingDecorator.new(thing) }
|
|
144
140
|
|
145
141
|
## Contributing
|
146
142
|
|
147
|
-
1. Fork it (
|
143
|
+
1. Fork it (https://github.com/rwz/adequate_exposure/fork)
|
148
144
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
149
145
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
150
146
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/adequate_exposure.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = AdequateExposure::VERSION
|
9
9
|
spec.authors = ["Pavel Pravosud"]
|
10
10
|
spec.email = ["pavel@pravosud.com"]
|
11
|
-
spec.summary = "
|
11
|
+
spec.summary = "Exposing things, adequately"
|
12
12
|
spec.homepage = "https://github.com/rwz/adequate_exposure"
|
13
13
|
spec.license = "MIT"
|
14
14
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -1,11 +1,12 @@
|
|
1
|
-
require "active_support/core_ext/hash/reverse_merge"
|
2
|
-
|
3
1
|
module AdequateExposure
|
4
2
|
module Controller
|
5
|
-
def expose(
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
def expose(*args, &block)
|
4
|
+
Exposure.expose! self, *args, &block
|
5
|
+
end
|
6
|
+
|
7
|
+
def expose!(name, *args, &block)
|
8
|
+
expose name, *args, &block
|
9
|
+
before_action name
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -1,27 +1,92 @@
|
|
1
1
|
module AdequateExposure
|
2
2
|
class Exposure
|
3
|
-
attr_reader :options
|
3
|
+
attr_reader :controller, :options
|
4
4
|
|
5
|
-
def
|
6
|
-
|
5
|
+
def self.expose!(*args, &block)
|
6
|
+
new(*args, &block).expose!
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
9
|
+
def initialize(controller, name, fetch_block=nil, **options, &block)
|
10
|
+
@controller = controller
|
11
|
+
@options = options.with_indifferent_access.merge(name: name)
|
12
|
+
|
13
|
+
merge_lambda_option :fetch, fetch_block if fetch_block
|
14
|
+
merge_lambda_option :fetch, block if block_given?
|
15
|
+
|
16
|
+
assert_singleton_option :fetch
|
17
|
+
assert_singleton_option :from
|
18
|
+
assert_incompatible_options_pair :parent, :model
|
19
|
+
assert_incompatible_options_pair :parent, :scope
|
20
|
+
|
21
|
+
normalize_options
|
22
|
+
end
|
23
|
+
|
24
|
+
def expose!
|
25
|
+
expose_attribute!
|
26
|
+
expose_helper_methods!
|
12
27
|
end
|
13
28
|
|
14
29
|
private
|
15
30
|
|
16
|
-
def expose_attribute!
|
31
|
+
def expose_attribute!
|
17
32
|
attribute.expose! controller
|
18
33
|
end
|
19
34
|
|
20
|
-
def expose_helper_methods!
|
35
|
+
def expose_helper_methods!
|
21
36
|
helper_methods = [ attribute.getter_method_name, attribute.setter_method_name ]
|
22
37
|
controller.helper_method *helper_methods
|
23
38
|
end
|
24
39
|
|
40
|
+
def normalize_options
|
41
|
+
exposure_name = options.fetch(:name)
|
42
|
+
|
43
|
+
normalize_non_proc_option :id do |ids|
|
44
|
+
->{ Array.wrap(ids).map{ |id| params[id] }.find(&:present?) }
|
45
|
+
end
|
46
|
+
|
47
|
+
normalize_non_proc_option :model do |value|
|
48
|
+
model = if [String, Symbol].include?(value.class)
|
49
|
+
value.to_s.classify.constantize
|
50
|
+
else
|
51
|
+
value
|
52
|
+
end
|
53
|
+
|
54
|
+
->{ model }
|
55
|
+
end
|
56
|
+
|
57
|
+
normalize_non_proc_option :build do |params_method_name|
|
58
|
+
->(scope){ scope.new(send(params_method_name)) }
|
59
|
+
end
|
60
|
+
|
61
|
+
normalize_non_proc_option :scope do |custom_scope|
|
62
|
+
->(model){ model.send(custom_scope) }
|
63
|
+
end
|
64
|
+
|
65
|
+
if parent = options.delete(:parent)
|
66
|
+
merge_lambda_option :scope, ->{ send(parent).send(exposure_name.to_s.pluralize) }
|
67
|
+
end
|
68
|
+
|
69
|
+
if from = options.delete(:from)
|
70
|
+
merge_lambda_option :fetch, ->{ send(from).send(exposure_name) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def normalize_non_proc_option(name)
|
75
|
+
option_value = options[name]
|
76
|
+
return if Proc === option_value
|
77
|
+
if option_value.present?
|
78
|
+
merge_lambda_option name, yield(option_value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def merge_lambda_option(name, body)
|
83
|
+
if previous_value = options[name] and Proc === previous_value
|
84
|
+
fail ArgumentError, "#{name.to_s.titleize} block is already defined"
|
85
|
+
end
|
86
|
+
|
87
|
+
options[name] = body
|
88
|
+
end
|
89
|
+
|
25
90
|
def attribute
|
26
91
|
@attribute ||= begin
|
27
92
|
local_options = options
|
@@ -37,5 +102,17 @@ module AdequateExposure
|
|
37
102
|
)
|
38
103
|
end
|
39
104
|
end
|
105
|
+
|
106
|
+
def assert_incompatible_options_pair(key1, key2)
|
107
|
+
if options.key?(key1) && options.key?(key2)
|
108
|
+
fail ArgumentError, "Using #{key1.inspect} option with #{key2.inspect} doesn't make sense"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def assert_singleton_option(name)
|
113
|
+
if options.except(name, :name).any? && options.key?(name)
|
114
|
+
fail ArgumentError, "Using #{name.inspect} option with other options doesn't make sense"
|
115
|
+
end
|
116
|
+
end
|
40
117
|
end
|
41
118
|
end
|
@@ -1,14 +1,10 @@
|
|
1
|
-
require "active_support/hash_with_indifferent_access"
|
2
|
-
require "active_support/core_ext/array/wrap"
|
3
|
-
require "active_support/core_ext/string/inflections"
|
4
|
-
|
5
1
|
module AdequateExposure
|
6
2
|
class Flow
|
7
3
|
attr_reader :controller, :options
|
8
4
|
delegate :params, to: :controller
|
9
5
|
|
10
|
-
def initialize(controller,
|
11
|
-
@controller, @options = controller,
|
6
|
+
def initialize(controller, options)
|
7
|
+
@controller, @options = controller, options.with_indifferent_access
|
12
8
|
end
|
13
9
|
|
14
10
|
def name
|
@@ -26,19 +22,20 @@ module AdequateExposure
|
|
26
22
|
protected
|
27
23
|
|
28
24
|
def default_fetch
|
29
|
-
|
25
|
+
computed_scope = scope(model)
|
26
|
+
id ? decorate(find(id, computed_scope)) : decorate(build(computed_scope))
|
30
27
|
end
|
31
28
|
|
32
29
|
def default_id
|
33
|
-
|
30
|
+
params["#{name}_id"] || params[:id]
|
34
31
|
end
|
35
32
|
|
36
|
-
def default_scope
|
33
|
+
def default_scope(model)
|
37
34
|
model
|
38
35
|
end
|
39
36
|
|
40
37
|
def default_model
|
41
|
-
|
38
|
+
name.to_s.classify.constantize
|
42
39
|
end
|
43
40
|
|
44
41
|
def default_find(id, scope)
|
@@ -46,32 +43,25 @@ module AdequateExposure
|
|
46
43
|
end
|
47
44
|
|
48
45
|
def default_build(scope)
|
49
|
-
scope.new
|
46
|
+
scope.new(exposure_params)
|
50
47
|
end
|
51
48
|
|
52
49
|
def default_decorate(instance)
|
53
50
|
instance
|
54
51
|
end
|
55
52
|
|
56
|
-
def
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def handle_custom_scope(value)
|
61
|
-
scope_parent = controller.instance_exec{ send value }
|
62
|
-
scope_parent.send(name.to_s.pluralize)
|
63
|
-
end
|
53
|
+
def exposure_params
|
54
|
+
params_method_name = "#{name}_params"
|
64
55
|
|
65
|
-
|
66
|
-
|
56
|
+
if controller.respond_to?(params_method_name, true)
|
57
|
+
controller.send(params_method_name)
|
58
|
+
else
|
59
|
+
{}
|
60
|
+
end
|
67
61
|
end
|
68
62
|
|
69
63
|
private
|
70
64
|
|
71
|
-
def id_attribute_name
|
72
|
-
Array.wrap(possible_id_keys).detect{ |key| params.key?(key) }
|
73
|
-
end
|
74
|
-
|
75
65
|
def handle_action(name, *args)
|
76
66
|
if options.key?(name)
|
77
67
|
handle_custom_action(name, *args)
|
@@ -84,22 +74,11 @@ module AdequateExposure
|
|
84
74
|
value = options[name]
|
85
75
|
|
86
76
|
if Proc === value
|
77
|
+
args = args.first(value.parameters.length)
|
87
78
|
controller.instance_exec(*args, &value)
|
88
79
|
else
|
89
|
-
|
80
|
+
fail ArgumentError, "Can't handle #{name.inspect} => #{value.inspect} option"
|
90
81
|
end
|
91
82
|
end
|
92
|
-
|
93
|
-
def symbol_to_class(symbol)
|
94
|
-
symbol.to_s.classify.constantize
|
95
|
-
end
|
96
|
-
|
97
|
-
def fetch_first_defined_param(keys)
|
98
|
-
Array.wrap(keys).each do |key|
|
99
|
-
return params[key] if params.key?(key)
|
100
|
-
end
|
101
|
-
|
102
|
-
nil
|
103
|
-
end
|
104
83
|
end
|
105
84
|
end
|
data/lib/adequate_exposure.rb
CHANGED
data/spec/controller_spec.rb
CHANGED
@@ -43,10 +43,15 @@ describe AdequateExposure::Controller do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
context "
|
47
|
-
|
48
|
-
|
46
|
+
context ".expose!" do
|
47
|
+
it "supports eager expose" do
|
48
|
+
expect(controller_klass).to receive(:before_action).with(:thing)
|
49
|
+
controller_klass.expose! :thing
|
49
50
|
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with block" do
|
54
|
+
before{ expose(:thing){ compute_thing } }
|
50
55
|
|
51
56
|
it "executes block to calculate the value" do
|
52
57
|
allow(controller).to receive(:compute_thing).and_return(42)
|
@@ -63,6 +68,24 @@ describe AdequateExposure::Controller do
|
|
63
68
|
controller.thing = :foobar
|
64
69
|
expect(controller.thing).to eq(:foobar)
|
65
70
|
end
|
71
|
+
|
72
|
+
it "throws and error when providing options with block" do
|
73
|
+
action = ->{ expose(:thing, id: :some_id){ some_code } }
|
74
|
+
expect(&action).to raise_error(ArgumentError, "Using :fetch option with other options doesn't make sense")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "passing fetch block as an argument instead of block" do
|
79
|
+
it "is equivalent to passing block" do
|
80
|
+
expose :thing, ->{ compute_thing }
|
81
|
+
expect(controller).to receive(:compute_thing).and_return(42)
|
82
|
+
expect(controller.thing).to eq(42)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "throws an error when passing both block and block-argument" do
|
86
|
+
action = ->{ expose(:thing, ->{}){} }
|
87
|
+
expect(&action).to raise_error(ArgumentError, "Fetch block is already defined")
|
88
|
+
end
|
66
89
|
end
|
67
90
|
|
68
91
|
context "redefine fetch" do
|
@@ -77,14 +100,36 @@ describe AdequateExposure::Controller do
|
|
77
100
|
end
|
78
101
|
|
79
102
|
context "default behaviour" do
|
80
|
-
before{ expose :thing }
|
81
103
|
|
82
|
-
|
83
|
-
|
104
|
+
context "build" do
|
105
|
+
let(:thing){ double("Thing") }
|
106
|
+
|
107
|
+
after{ expect(controller.thing).to eq(thing) }
|
108
|
+
|
109
|
+
it "builds a new instance with empty hash when strong parameters method is not available" do
|
110
|
+
expose :thing
|
111
|
+
expect(Thing).to receive(:new).with({}).and_return(thing)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "builds a new instance with attributes when strong parameters method is available" do
|
115
|
+
expose :thing
|
116
|
+
expect(Thing).to receive(:new).with(foo: :bar).and_return(thing)
|
117
|
+
expect(controller).to receive(:thing_params).and_return(foo: :bar)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "allows to specify strong parameters method name with a symbol passed to build option" do
|
121
|
+
expose :thing, build: :custom_params_method_name
|
122
|
+
expect(Thing).to receive(:new).with(foo: :bar).and_return(thing)
|
123
|
+
expect(controller).to receive(:custom_params_method_name).and_return(foo: :bar)
|
124
|
+
end
|
84
125
|
end
|
85
126
|
|
86
127
|
context "find" do
|
87
|
-
before
|
128
|
+
before do
|
129
|
+
expose :thing
|
130
|
+
expect(Thing).to receive(:find).with(10)
|
131
|
+
end
|
132
|
+
|
88
133
|
after{ controller.thing }
|
89
134
|
|
90
135
|
it "finds Thing if thing_id param is provided" do
|
@@ -97,8 +142,46 @@ describe AdequateExposure::Controller do
|
|
97
142
|
end
|
98
143
|
end
|
99
144
|
|
145
|
+
context "parent option" do
|
146
|
+
context "with scope/model options" do
|
147
|
+
it "throws an error when used with scope option" do
|
148
|
+
action = ->{ expose :thing, scope: :foo, parent: :something }
|
149
|
+
expect(&action).to raise_error(ArgumentError, "Using :parent option with :scope doesn't make sense")
|
150
|
+
end
|
151
|
+
|
152
|
+
it "throws an error when used with model option" do
|
153
|
+
action = ->{ expose :thing, model: :foo, parent: :something }
|
154
|
+
expect(&action).to raise_error(ArgumentError, "Using :parent option with :model doesn't make sense")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "build/find" do
|
159
|
+
let(:current_user){ double("User") }
|
160
|
+
let(:scope){ double("Scope") }
|
161
|
+
|
162
|
+
before do
|
163
|
+
expect(controller).to receive(:current_user).and_return(current_user)
|
164
|
+
expect(current_user).to receive(:things).and_return(scope)
|
165
|
+
expose :thing, parent: :current_user
|
166
|
+
end
|
167
|
+
|
168
|
+
after{ expect(controller.thing).to eq(42) }
|
169
|
+
|
170
|
+
it "sets the scope to belong to parent defined by controller method" do
|
171
|
+
expect(scope).to receive(:new).with({}).and_return(42)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "scopes the find to proper scope" do
|
175
|
+
controller.params.merge! thing_id: 10
|
176
|
+
expect(scope).to receive(:find).with(10).and_return(42)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
100
181
|
context "override model" do
|
101
|
-
|
182
|
+
let(:different_thing){ double("DifferentThing") }
|
183
|
+
before{ expect(DifferentThing).to receive(:new).with({}).and_return(different_thing) }
|
184
|
+
after{ expect(controller.thing).to eq(different_thing) }
|
102
185
|
|
103
186
|
it "allows overriding model class with proc" do
|
104
187
|
expose :thing, model: ->{ DifferentThing }
|
@@ -111,6 +194,10 @@ describe AdequateExposure::Controller do
|
|
111
194
|
it "allows overriding model class with symbol" do
|
112
195
|
expose :thing, model: :different_thing
|
113
196
|
end
|
197
|
+
|
198
|
+
it "allows overriding model class with string" do
|
199
|
+
expose :thing, model: "DifferentThing"
|
200
|
+
end
|
114
201
|
end
|
115
202
|
|
116
203
|
context "override scope" do
|
@@ -121,17 +208,12 @@ describe AdequateExposure::Controller do
|
|
121
208
|
expect(controller.thing).to eq(42)
|
122
209
|
end
|
123
210
|
|
124
|
-
it "allows overriding
|
125
|
-
current_user = double("User")
|
211
|
+
it "allows overriding model scope using symbol" do
|
126
212
|
scope = double("Scope")
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
expect(
|
131
|
-
expect(scope).to receive(:new).and_return(scoped_thing)
|
132
|
-
expose :thing, scope: :current_user
|
133
|
-
|
134
|
-
expect(controller.thing).to eq(scoped_thing)
|
213
|
+
expect(Thing).to receive(:custom_scope).and_return(scope)
|
214
|
+
expect(scope).to receive(:new).and_return(42)
|
215
|
+
expose :thing, scope: :custom_scope
|
216
|
+
expect(controller.thing).to eq(42)
|
135
217
|
end
|
136
218
|
end
|
137
219
|
|
@@ -160,8 +242,27 @@ describe AdequateExposure::Controller do
|
|
160
242
|
context "override decorator" do
|
161
243
|
it "allows specify decorator" do
|
162
244
|
expose :thing, decorate: ->(thing){ decorate(thing) }
|
163
|
-
|
245
|
+
thing = double("Thing")
|
246
|
+
expect(Thing).to receive(:new).with({}).and_return(thing)
|
247
|
+
expect(controller).to receive(:decorate).with(thing)
|
164
248
|
controller.thing
|
165
249
|
end
|
166
250
|
end
|
251
|
+
|
252
|
+
context "from option" do
|
253
|
+
it "allows scope to be called from method" do
|
254
|
+
post = double("Post")
|
255
|
+
comments = double("Comments")
|
256
|
+
allow(controller).to receive(:post).and_return(post)
|
257
|
+
expect(post).to receive(:comments).and_return(comments)
|
258
|
+
expose :comments, from: :post
|
259
|
+
|
260
|
+
expect(controller.comments).to eq(comments)
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should throw error when used with other options" do
|
264
|
+
action = ->{ expose :thing, from: :foo, parent: :bar }
|
265
|
+
expect(&action).to raise_error(ArgumentError, "Using :from option with other options doesn't make sense")
|
266
|
+
end
|
267
|
+
end
|
167
268
|
end
|
data/spec/support/rails_app.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adequate_exposure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Pravosud
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -85,7 +85,7 @@ rubyforge_project:
|
|
85
85
|
rubygems_version: 2.2.2
|
86
86
|
signing_key:
|
87
87
|
specification_version: 4
|
88
|
-
summary:
|
88
|
+
summary: Exposing things, adequately
|
89
89
|
test_files:
|
90
90
|
- spec/controller_spec.rb
|
91
91
|
- spec/integration_spec.rb
|