adequate_exposure 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|