arcane 0.1.1 → 1.0.0.pre
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 +7 -0
- data/CHANGELOG.md +15 -2
- data/README.md +92 -32
- data/lib/arcane.rb +18 -26
- data/lib/arcane/finder.rb +3 -3
- data/lib/arcane/parameters.rb +77 -0
- data/lib/arcane/version.rb +1 -1
- data/spec/arcane/finder_spec.rb +12 -12
- data/spec/arcane/parameters_spec.rb +84 -0
- data/spec/arcane_spec.rb +13 -90
- data/spec/spec_helper.rb +39 -0
- metadata +21 -41
- data/lib/arcane/chain.rb +0 -43
- data/spec/arcane/chain_spec.rb +0 -66
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c157016d7b457a09a15c6222079d7d96725d8381
|
4
|
+
data.tar.gz: 90e1df401507d8c4281cf709580b23aebc72f958
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 75a7e859ce0552b16632bc9bc777cb3fcc621a7ef10403b6f9ceb24f91a39c96b7313c158908a28d8d8539c1556986c228f7b9c0dc817b26cd2a0c95a5559c91
|
7
|
+
data.tar.gz: d241c9243a4b3a194e92add373e31b56dd9a162f0631ad155ac287930a866e5abd7f1b8b63e8b8f5bb2c9203f5f21e31efbfceb8904d8566f6fd3845377e3abe
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,22 @@
|
|
1
|
-
### Arcane **0.
|
1
|
+
### Arcane **1.0.0.pre** [head] - 2013-07-12
|
2
|
+
* **[deprecation]** The `refine` helper no longer
|
3
|
+
exist, as it's a proposed keyword for ruby 2.0 look
|
4
|
+
to the new features for how to access arcane.
|
5
|
+
|
6
|
+
* **[feature]** Introducing chained methods on `params`
|
7
|
+
to specify for what, who and how you want arcane to
|
8
|
+
refine your parameters. Look in `README.md` for
|
9
|
+
detailed information.
|
10
|
+
|
11
|
+
* **[bugfix]** You can now properly specify
|
12
|
+
`refinery_class` in your model.
|
13
|
+
|
14
|
+
### Arcane **0.1.1** [current] – 2013-07-11
|
2
15
|
* **[feature]** The `refine` helper no longer needs a
|
3
16
|
refinery method, it will try and detect which one to
|
4
17
|
use based on parameters.
|
5
18
|
|
6
|
-
### Arcane **0.1.0** [
|
19
|
+
### Arcane **0.1.0** [old] – 2013-07-11
|
7
20
|
* **[bugfix]** Arcane should no longer error when there is
|
8
21
|
no current_user present.
|
9
22
|
* **[feature]** Added new query syntax for the `refine`
|
data/README.md
CHANGED
@@ -13,16 +13,28 @@ Inspired by [Pundit](https://github.com/elabs/pundit)
|
|
13
13
|
|
14
14
|
## Usage
|
15
15
|
|
16
|
-
This is how easy it
|
16
|
+
This is how easy it is to use:
|
17
17
|
|
18
18
|
```ruby
|
19
|
-
|
19
|
+
def create
|
20
|
+
@article = Article.new params.for(Article).refine
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
@article.find(params[:id])
|
25
|
+
@article.update_attributes params.for(@article).as(current_user).refine
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy
|
29
|
+
@article.find(params[:id])
|
30
|
+
@article.update_attributes params.for(@article).on(:destroy).refine
|
31
|
+
end
|
20
32
|
```
|
21
33
|
|
22
|
-
### Include the
|
34
|
+
### Include the Arcane Module
|
23
35
|
|
24
36
|
Though, we need to do a couple of things before we can get started. First of all include `Arcane` in your
|
25
|
-
controller. This will
|
37
|
+
controller. This will extend strong parameters with all the arcane methods you saw above in the example.
|
26
38
|
|
27
39
|
```ruby
|
28
40
|
# app/controllers/application_controller.rb
|
@@ -33,7 +45,7 @@ end
|
|
33
45
|
|
34
46
|
### Create your first Refinery
|
35
47
|
|
36
|
-
Before you can use the
|
48
|
+
Before you can use the parameter methods, you need a Refinery for the model you want to pass parameters to.
|
37
49
|
Simply create the directory `/app/refineries` in your Rails project. Create a Refinery your model, in this
|
38
50
|
case Article. `/app/refineries/article_refinery.rb`. Create a class in that file called `ArticleRefinery`.
|
39
51
|
|
@@ -41,9 +53,8 @@ Methods defined in the refinery should reflect the controller method for clarity
|
|
41
53
|
want it to be. These methods must return an array containing the same parameters you would otherwise send
|
42
54
|
to strong parameters.
|
43
55
|
|
44
|
-
It can be initiated using a `Struct` which accepts an `object` and a `user`.
|
45
|
-
|
46
|
-
the parameters on.
|
56
|
+
It can be initiated using a `Struct` which accepts an `object` and a `user`. Arcane will automatically send
|
57
|
+
`current_user`, if present to the refinery as well as the object you want to apply the parameters on.
|
47
58
|
|
48
59
|
```ruby
|
49
60
|
# app/refineries/article_refinery.rb
|
@@ -66,60 +77,82 @@ class CommentRefinery < Arcane::Refinery; end
|
|
66
77
|
|
67
78
|
### Using Arcane in your controller
|
68
79
|
|
69
|
-
Next up, using the
|
70
|
-
|
71
|
-
|
80
|
+
Next up, using the Arcane methods. There first three are; `for`, `as`, `on` and can all be called on
|
81
|
+
an instance of rails params, chained, and in any order you want. The fourth one, `refine` you call to
|
82
|
+
pull your parameters through a refinery.
|
83
|
+
|
84
|
+
* `for` - The model or object you want to filter parameters
|
85
|
+
* `as` - The user performing the action, by default `current_user`
|
86
|
+
* `on` - The action or rather, refinery method that is called
|
87
|
+
|
88
|
+
* `refine` - Wraps everything up and finds your desired filter.
|
72
89
|
|
73
90
|
```ruby
|
74
|
-
refined_params =
|
91
|
+
refined_params = params.for(@article).as(current_user).on(:update).refine
|
75
92
|
```
|
76
93
|
|
77
|
-
|
94
|
+
Here's an example of how a controller can look with Arcane paramters.
|
78
95
|
|
79
96
|
```ruby
|
80
|
-
class
|
81
|
-
|
97
|
+
class GameController < ApplicationController
|
82
98
|
def create
|
83
|
-
@
|
84
|
-
@article.save
|
99
|
+
@game = Game.create(params.for(Game).as(user_from_location).refine)
|
85
100
|
end
|
86
101
|
|
87
102
|
def update
|
88
|
-
@article
|
89
|
-
@article.update_attributes(
|
103
|
+
@article.find(params[:id])
|
104
|
+
@article.update_attributes params.for(@article).as(current_user).refine
|
90
105
|
end
|
91
106
|
|
92
|
-
|
107
|
+
def update_many
|
108
|
+
@games = Game.find(params[:ids])
|
109
|
+
@games.each do |game|
|
110
|
+
game.update_attributes(params.for(@game).on(:update).refine)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
93
115
|
|
116
|
+
def user_from_location
|
117
|
+
# ...
|
118
|
+
end
|
119
|
+
end
|
94
120
|
```
|
95
121
|
|
96
122
|
## Features
|
97
123
|
|
98
|
-
###
|
99
|
-
|
100
|
-
|
124
|
+
### Invokable anywhere.
|
125
|
+
As arcane extends ActionController::Parameters you can invoke in anywhere and start toying around with
|
126
|
+
the arcane methods. This is good if you have some other way of getting data in to your application outside
|
127
|
+
the context of a controller.
|
101
128
|
|
102
129
|
```ruby
|
103
|
-
|
104
|
-
|
105
|
-
|
130
|
+
@user, @post = User.find(1), Post.find(24)
|
131
|
+
|
132
|
+
my_params = ActionController::Parameters.new({ post: { content: "Hello" } })
|
133
|
+
my_params.for(@post).as(@user).on(:create)
|
106
134
|
```
|
107
135
|
|
108
136
|
### Automatic Method Detection
|
109
|
-
If you have specified no refinery
|
110
|
-
what method to use.
|
111
|
-
on the parameters and use your refinery. *If you want to know how to handle fallbacks, see next feature.*
|
137
|
+
If you have specified no refinery action in your chain to params, Arcane tries to find out for itself
|
138
|
+
what method to use. Arcane uses the action key in the rails parameters to determine the refinery method.
|
112
139
|
|
113
140
|
```ruby
|
114
141
|
class CommentsController < ApplicationController
|
115
142
|
def update
|
116
143
|
@comment = Comment.find(params[:id])
|
117
|
-
@comment.update_attributes
|
144
|
+
@comment.update_attributes params.for(@comment)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class CommentRefinery < Arcane::Refinery
|
149
|
+
def update
|
150
|
+
[:email,:name,:text]
|
118
151
|
end
|
119
152
|
end
|
120
153
|
```
|
121
154
|
|
122
|
-
### Default
|
155
|
+
### Default parameters
|
123
156
|
You are able to specify a `default` method in your refinery which will be prioritized if no the method
|
124
157
|
you call does not exist. If default is not specified it will be as the refinery returned an empty array.
|
125
158
|
|
@@ -131,7 +164,7 @@ class AmbiguityRefinery < Arcane::Refinery
|
|
131
164
|
end
|
132
165
|
```
|
133
166
|
|
134
|
-
###
|
167
|
+
### Custom root requrement
|
135
168
|
You are able to disable or change the root requirement. Let's say you have a sessions endpoint where
|
136
169
|
you don't have your username and password parameters wrapped in a root. Now you can use the root class
|
137
170
|
method and set it to nil or false and it will automatically not require it.
|
@@ -156,6 +189,33 @@ class MeRefinery < UserRefinery
|
|
156
189
|
end
|
157
190
|
```
|
158
191
|
|
192
|
+
### Refinery Inheritence
|
193
|
+
Say you have quite similar needs between two different models, one of them might even have inherited
|
194
|
+
from the other. As arcane's refineries are just regular ruby models you can easily inherit from one
|
195
|
+
to another and it will just work.
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
class Square
|
199
|
+
attr :height, :width
|
200
|
+
end
|
201
|
+
|
202
|
+
class Cube < Square
|
203
|
+
attr :depth
|
204
|
+
end
|
205
|
+
|
206
|
+
class SquareRefinery
|
207
|
+
def create
|
208
|
+
[:height,:width]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
class CubeRefinery
|
213
|
+
def create
|
214
|
+
[:depth] + super
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
159
219
|
## Requirements
|
160
220
|
|
161
221
|
Currently this gem is only supported for Rails and with any of these ruby versions:
|
data/lib/arcane.rb
CHANGED
@@ -1,49 +1,41 @@
|
|
1
|
-
require "arcane/version"
|
2
|
-
require "arcane/finder"
|
3
|
-
require "arcane/chain"
|
4
|
-
require "arcane/refinery"
|
5
|
-
|
6
1
|
require 'active_support/concern'
|
7
2
|
require 'active_support/core_ext/string/inflections'
|
8
3
|
require 'active_support/core_ext/object/blank'
|
9
4
|
require 'strong_parameters'
|
10
5
|
|
6
|
+
require "arcane/version"
|
7
|
+
require "arcane/finder"
|
8
|
+
require "arcane/refinery"
|
9
|
+
require "arcane/parameters"
|
10
|
+
|
11
11
|
module Arcane
|
12
12
|
|
13
13
|
extend ActiveSupport::Concern
|
14
14
|
|
15
15
|
included do
|
16
|
+
|
16
17
|
if respond_to?(:helper_method)
|
17
18
|
helper_method :refine
|
19
|
+
helper_method :current_params_user
|
18
20
|
end
|
21
|
+
|
19
22
|
if respond_to?(:hide_action)
|
20
23
|
hide_action :refine
|
24
|
+
hide_action :current_params_user
|
21
25
|
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def refine(object,*args)
|
25
|
-
|
26
|
-
current_user = nil unless respond_to?(:current_user)
|
27
26
|
|
28
|
-
|
27
|
+
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
elsif [Hash,HashWithIndifferentAccess,ActionController::Parameters].any? { |c| arg.kind_of?(c) }
|
34
|
-
opts[:params] ||= arg
|
35
|
-
elsif current_user.nil?
|
36
|
-
opts[:user] ||= arg
|
37
|
-
end
|
38
|
-
end
|
29
|
+
def current_params_user
|
30
|
+
respond_to?(:current_user) ? current_user : nil
|
31
|
+
end
|
39
32
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
opts[:object] ||= object.respond_to?(:new) ? object.new : object
|
33
|
+
def params
|
34
|
+
@_params ||= ActionController::Parameters.new(request.parameters).as(current_params_user)
|
35
|
+
end
|
44
36
|
|
45
|
-
|
46
|
-
|
37
|
+
def params=(val)
|
38
|
+
@_params = val.kind_of?(Hash) ? ActionController::Parameters.new(val).as(current_params_user) : val.as(current_params_user)
|
47
39
|
end
|
48
40
|
|
49
41
|
end
|
data/lib/arcane/finder.rb
CHANGED
@@ -8,7 +8,7 @@ module Arcane
|
|
8
8
|
@object = object
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def refinery
|
12
12
|
klass = find
|
13
13
|
klass = klass.constantize if klass.is_a?(String)
|
14
14
|
klass
|
@@ -33,9 +33,9 @@ module Arcane
|
|
33
33
|
|
34
34
|
def find
|
35
35
|
if object.respond_to?(:arcane_class)
|
36
|
-
object.
|
36
|
+
object.refinery_class
|
37
37
|
elsif object.class.respond_to?(:arcane_class)
|
38
|
-
object.class.
|
38
|
+
object.class.refinery_class
|
39
39
|
else
|
40
40
|
klass = self.class.object_name(object)
|
41
41
|
"#{klass}Refinery"
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Arcane
|
2
|
+
|
3
|
+
module Parameters
|
4
|
+
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
|
9
|
+
attr_accessor :user, :object, :action
|
10
|
+
|
11
|
+
def dup
|
12
|
+
self.class.new(self).tap do |duplicate|
|
13
|
+
duplicate.user = user
|
14
|
+
duplicate.object = object
|
15
|
+
duplicate.action = action
|
16
|
+
duplicate.default = default
|
17
|
+
duplicate.instance_variable_set :@permitted, @permitted
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def for(object)
|
24
|
+
params = self.dup
|
25
|
+
params.object = object
|
26
|
+
return params
|
27
|
+
end
|
28
|
+
|
29
|
+
def as(user)
|
30
|
+
params = self.dup
|
31
|
+
params.user = user
|
32
|
+
return params
|
33
|
+
end
|
34
|
+
|
35
|
+
def on(action)
|
36
|
+
params = self.dup
|
37
|
+
params.action = action
|
38
|
+
return params
|
39
|
+
end
|
40
|
+
|
41
|
+
def refine(opts={})
|
42
|
+
params = self.dup
|
43
|
+
|
44
|
+
params.action = opts[:action] || action || params[:action]
|
45
|
+
params.user = opts[:user] || user
|
46
|
+
params.object = opts[:object] || object
|
47
|
+
|
48
|
+
refinery = Arcane::Finder.new(params.object).refinery.new(params.object, params.user)
|
49
|
+
|
50
|
+
args = if params.action.nil?
|
51
|
+
[]
|
52
|
+
elsif refinery.respond_to?(params.action)
|
53
|
+
refinery.public_send(params.action)
|
54
|
+
elsif refinery.respond_to?(:default)
|
55
|
+
refinery.default
|
56
|
+
else
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
|
60
|
+
root = if refinery.respond_to?(:root)
|
61
|
+
refinery.root
|
62
|
+
elsif refinery.class.respond_to?(:root)
|
63
|
+
refinery.class.root
|
64
|
+
else
|
65
|
+
Arcane::Finder.object_name(params.object)
|
66
|
+
end
|
67
|
+
|
68
|
+
return root.present? ? params.require(root.underscore).permit(*args) : params.permit(*args)
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
ActionController::Parameters.send :include, Arcane::Parameters
|
data/lib/arcane/version.rb
CHANGED
data/spec/arcane/finder_spec.rb
CHANGED
@@ -2,34 +2,34 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Arcane::Finder do
|
4
4
|
|
5
|
-
let(:
|
6
|
-
let(:
|
5
|
+
let(:object_with_refinery) { Task.new }
|
6
|
+
let(:object_without_refinery) { Shape.new }
|
7
7
|
|
8
|
-
before(:each) { @
|
8
|
+
before(:each) { @refinery = Arcane::Finder.new(object_with_refinery) }
|
9
9
|
|
10
10
|
describe '.new' do
|
11
11
|
it 'sets the object' do
|
12
|
-
@
|
12
|
+
@refinery.object.should eq(object_with_refinery)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '#find' do
|
17
17
|
|
18
|
-
it 'finds existing
|
19
|
-
@
|
18
|
+
it 'finds existing refinery' do
|
19
|
+
@refinery.send(:find).should eq "TaskRefinery"
|
20
20
|
end
|
21
21
|
|
22
22
|
end
|
23
23
|
|
24
|
-
describe '#
|
24
|
+
describe '#refinery' do
|
25
25
|
|
26
|
-
it 'returns
|
27
|
-
@
|
26
|
+
it 'returns refinery' do
|
27
|
+
@refinery.refinery.should eq TaskRefinery
|
28
28
|
end
|
29
29
|
|
30
|
-
it 'returns base
|
31
|
-
@
|
32
|
-
@
|
30
|
+
it 'returns base refinery class when no refinery exists' do
|
31
|
+
@refinery = Arcane::Finder.new(object_without_refinery)
|
32
|
+
@refinery.refinery.should eq Arcane::Refinery
|
33
33
|
end
|
34
34
|
|
35
35
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Arcane::Parameters do
|
4
|
+
|
5
|
+
let(:user) { double }
|
6
|
+
let(:object) { NilModel.new }
|
7
|
+
let(:action) { :unknown }
|
8
|
+
let(:params) { nil_model_params }
|
9
|
+
let(:refinery) { NilModelRefinery }
|
10
|
+
|
11
|
+
let(:subject) { subject_class.new(params).for(object).on(action).as(user) }
|
12
|
+
let(:subject_class) { ActionController::Parameters }
|
13
|
+
|
14
|
+
describe '#for' do
|
15
|
+
it { subject.for(object).should be_a ActionController::Parameters }
|
16
|
+
it { subject.for(object).object.should eq object }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#as' do
|
20
|
+
it { subject.as(user).should be_a ActionController::Parameters }
|
21
|
+
it { subject.as(user).user.should eq user }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#on' do
|
25
|
+
it { subject.on(action).should be_a ActionController::Parameters }
|
26
|
+
it { subject.on(action).action.should eq action }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#refine' do
|
30
|
+
|
31
|
+
it { subject.refine.should be_a ActionController::Parameters }
|
32
|
+
|
33
|
+
context 'with exstensive parameters' do
|
34
|
+
|
35
|
+
let(:user) { double }
|
36
|
+
let(:object) { Article.new }
|
37
|
+
let(:params) { article_params }
|
38
|
+
|
39
|
+
it 'filters correctly' do
|
40
|
+
subject.on(:update).refine.should eq expected_params(:article,:title,:content)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'filters nested object parameters correctly' do
|
44
|
+
subject.on(:create).refine.should eq expected_params(:article,:title,:content,:links)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'filters nested scalar parameters correctly' do
|
48
|
+
subject.on(:publish).refine.should eq expected_params(:article,:title,:content,:tags)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'action is not set' do
|
54
|
+
|
55
|
+
let(:params) { nil_model_params action: 'create' }
|
56
|
+
let(:subject) { subject_class.new(params).for(object).as(user) }
|
57
|
+
|
58
|
+
it 'uses the params to determine refinery action' do
|
59
|
+
NilModelRefinery.any_instance.should_receive :create
|
60
|
+
subject.refine
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'uses the options to determine refinery action' do
|
64
|
+
NilModelRefinery.any_instance.should_receive :create
|
65
|
+
subject.refine action: :create
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'user is not set' do
|
71
|
+
|
72
|
+
let(:user) { double(name: :test) }
|
73
|
+
let(:subject) { subject_class.new(params).for(object).on(action) }
|
74
|
+
|
75
|
+
it 'uses user from options' do
|
76
|
+
expect(subject).to receive(:user).once
|
77
|
+
subject.refine(user: user)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/spec/arcane_spec.rb
CHANGED
@@ -2,99 +2,22 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Arcane do
|
4
4
|
|
5
|
-
let(:user)
|
6
|
-
let(:
|
7
|
-
let(:
|
8
|
-
let(:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
content: "world",
|
14
|
-
links: [
|
15
|
-
{ blog: "http://blog.example.com" },
|
16
|
-
{ site: "http://www.example.com" },
|
17
|
-
],
|
18
|
-
tags: ["test","greeting"]
|
19
|
-
}
|
20
|
-
})
|
21
|
-
end
|
22
|
-
let(:custom_params) do
|
23
|
-
HashWithIndifferentAccess.new({
|
24
|
-
article: {
|
25
|
-
tags: ["test","greeting"]
|
26
|
-
}
|
27
|
-
})
|
28
|
-
end
|
29
|
-
|
30
|
-
describe '#refine' do
|
31
|
-
|
32
|
-
it { controller.refine(article).should be_a Arcane::Chain }
|
33
|
-
it { controller.refine(article,:update).should be_a ActionController::Parameters }
|
34
|
-
it { controller.refine(article).update.should be_a ActionController::Parameters }
|
35
|
-
it { controller.refine(Article)._object.should be_a Article }
|
36
|
-
|
37
|
-
context 'without supplying a refinery method' do
|
38
|
-
|
39
|
-
let(:params) do
|
40
|
-
HashWithIndifferentAccess.new({
|
41
|
-
action: 'create',
|
42
|
-
comment: {
|
43
|
-
content: "Awesome!",
|
44
|
-
score: 5
|
45
|
-
}
|
46
|
-
})
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'still returns a parameters hash' do
|
50
|
-
controller.refine(comment).should be_a ActionController::Parameters
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'finds the right method' do
|
54
|
-
controller.refine(comment).should eq expected_params(:comment,:score,:content)
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'using a missing refinery method' do
|
58
|
-
|
59
|
-
let(:params) do
|
60
|
-
HashWithIndifferentAccess.new({
|
61
|
-
action: 'update',
|
62
|
-
comment: {
|
63
|
-
content: "Awesome!",
|
64
|
-
score: 5
|
65
|
-
}
|
66
|
-
})
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'falls back on default' do
|
70
|
-
controller.refine(comment).should eq expected_params(:comment,:score)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'filters parameters correctly' do
|
78
|
-
controller.refine(article).update.should eq expected_params(:article,:title,:content)
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'filters nested object parameters correctly' do
|
82
|
-
controller.refine(article).create.should eq expected_params(:article,:title,:content,:links)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'filters nested scalar parameters correctly' do
|
86
|
-
controller.refine(article).publish.should eq expected_params(:article,:title,:content,:tags)
|
5
|
+
let(:user) { double(name: :user) }
|
6
|
+
let(:parameters) { nil_model_params }
|
7
|
+
let(:controller) { double(request: request, current_user: user).tap { |c| c.extend(Arcane) } }
|
8
|
+
let(:request) { double(parameters: parameters) }
|
9
|
+
|
10
|
+
describe '#params' do
|
11
|
+
it 'sets the user for parameters' do
|
12
|
+
controller.params.user.should eq user
|
87
13
|
end
|
14
|
+
end
|
88
15
|
|
89
|
-
|
90
|
-
|
91
|
-
controller.
|
16
|
+
describe '#params=' do
|
17
|
+
it 'sets the user for parameters' do
|
18
|
+
controller.params = { foo: :bar }
|
19
|
+
controller.instance_variable_get(:@_params).user.should eq user
|
92
20
|
end
|
93
|
-
|
94
21
|
end
|
95
22
|
|
96
|
-
end
|
97
|
-
|
98
|
-
def expected_params(object_name,*includes)
|
99
|
-
params[object_name].reject { |k,_| !includes.include? k.to_sym }
|
100
23
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,19 @@ require "pry"
|
|
3
3
|
require "active_support/core_ext"
|
4
4
|
require "active_model/naming"
|
5
5
|
|
6
|
+
class NilModel; end
|
7
|
+
class NilModelRefinery < Struct.new(:object,:user)
|
8
|
+
|
9
|
+
def create
|
10
|
+
[:attribute]
|
11
|
+
end
|
12
|
+
|
13
|
+
def default
|
14
|
+
create
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
6
19
|
class Article; end
|
7
20
|
class ArticleRefinery < Arcane::Refinery
|
8
21
|
|
@@ -46,4 +59,30 @@ class CommentRefinery < Arcane::Refinery
|
|
46
59
|
[:score]
|
47
60
|
end
|
48
61
|
|
62
|
+
end
|
63
|
+
|
64
|
+
def article_params
|
65
|
+
ActionController::Parameters.new({
|
66
|
+
action: 'create',
|
67
|
+
article: {
|
68
|
+
title: "hello",
|
69
|
+
content: "world",
|
70
|
+
links: [
|
71
|
+
{ blog: "http://blog.example.com" },
|
72
|
+
{ site: "http://www.example.com" },
|
73
|
+
],
|
74
|
+
tags: ["test","greeting"]
|
75
|
+
}
|
76
|
+
})
|
77
|
+
end
|
78
|
+
|
79
|
+
def nil_model_params(opts={})
|
80
|
+
ActionController::Parameters.new({
|
81
|
+
action: 'unknown',
|
82
|
+
nil_model: { attribute: :value }
|
83
|
+
}).merge(opts)
|
84
|
+
end
|
85
|
+
|
86
|
+
def expected_params(object_name,*includes)
|
87
|
+
params[object_name].reject { |k,_| !includes.include? k.to_sym }
|
49
88
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arcane
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0.pre
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Philip Vieira
|
@@ -10,60 +9,53 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-12 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: activesupport
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - '>='
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: 3.0.0
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
|
-
- -
|
25
|
+
- - '>='
|
29
26
|
- !ruby/object:Gem::Version
|
30
27
|
version: 3.0.0
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: strong_parameters
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
|
-
- -
|
32
|
+
- - '>='
|
37
33
|
- !ruby/object:Gem::Version
|
38
34
|
version: 0.2.0
|
39
35
|
type: :runtime
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
|
-
- -
|
39
|
+
- - '>='
|
45
40
|
- !ruby/object:Gem::Version
|
46
41
|
version: 0.2.0
|
47
42
|
- !ruby/object:Gem::Dependency
|
48
43
|
name: activerecord
|
49
44
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
45
|
requirements:
|
52
|
-
- -
|
46
|
+
- - '>='
|
53
47
|
- !ruby/object:Gem::Version
|
54
48
|
version: 3.0.0
|
55
49
|
type: :development
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
none: false
|
59
52
|
requirements:
|
60
|
-
- -
|
53
|
+
- - '>='
|
61
54
|
- !ruby/object:Gem::Version
|
62
55
|
version: 3.0.0
|
63
56
|
- !ruby/object:Gem::Dependency
|
64
57
|
name: rspec
|
65
58
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
59
|
requirements:
|
68
60
|
- - ~>
|
69
61
|
- !ruby/object:Gem::Version
|
@@ -71,7 +63,6 @@ dependencies:
|
|
71
63
|
type: :development
|
72
64
|
prerelease: false
|
73
65
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
66
|
requirements:
|
76
67
|
- - ~>
|
77
68
|
- !ruby/object:Gem::Version
|
@@ -79,33 +70,29 @@ dependencies:
|
|
79
70
|
- !ruby/object:Gem::Dependency
|
80
71
|
name: pry
|
81
72
|
requirement: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
73
|
requirements:
|
84
|
-
- -
|
74
|
+
- - '>='
|
85
75
|
- !ruby/object:Gem::Version
|
86
76
|
version: '0'
|
87
77
|
type: :development
|
88
78
|
prerelease: false
|
89
79
|
version_requirements: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
80
|
requirements:
|
92
|
-
- -
|
81
|
+
- - '>='
|
93
82
|
- !ruby/object:Gem::Version
|
94
83
|
version: '0'
|
95
84
|
- !ruby/object:Gem::Dependency
|
96
85
|
name: rake
|
97
86
|
requirement: !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
87
|
requirements:
|
100
|
-
- -
|
88
|
+
- - '>='
|
101
89
|
- !ruby/object:Gem::Version
|
102
90
|
version: '0'
|
103
91
|
type: :development
|
104
92
|
prerelease: false
|
105
93
|
version_requirements: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
94
|
requirements:
|
108
|
-
- -
|
95
|
+
- - '>='
|
109
96
|
- !ruby/object:Gem::Version
|
110
97
|
version: '0'
|
111
98
|
description: Parameter filter done OO, extending strong parameters.
|
@@ -125,49 +112,42 @@ files:
|
|
125
112
|
- Rakefile
|
126
113
|
- arcane.gemspec
|
127
114
|
- lib/arcane.rb
|
128
|
-
- lib/arcane/chain.rb
|
129
115
|
- lib/arcane/finder.rb
|
116
|
+
- lib/arcane/parameters.rb
|
130
117
|
- lib/arcane/refinery.rb
|
131
118
|
- lib/arcane/version.rb
|
132
|
-
- spec/arcane/chain_spec.rb
|
133
119
|
- spec/arcane/finder_spec.rb
|
120
|
+
- spec/arcane/parameters_spec.rb
|
134
121
|
- spec/arcane/refinery_spec.rb
|
135
122
|
- spec/arcane_spec.rb
|
136
123
|
- spec/spec_helper.rb
|
137
124
|
homepage: https://github.com/cloudsdaleapp/arcane
|
138
125
|
licenses:
|
139
126
|
- MIT
|
127
|
+
metadata: {}
|
140
128
|
post_install_message:
|
141
129
|
rdoc_options: []
|
142
130
|
require_paths:
|
143
131
|
- lib
|
144
132
|
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
133
|
requirements:
|
147
|
-
- -
|
134
|
+
- - '>='
|
148
135
|
- !ruby/object:Gem::Version
|
149
136
|
version: '0'
|
150
|
-
segments:
|
151
|
-
- 0
|
152
|
-
hash: 1025235848978620495
|
153
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
-
none: false
|
155
138
|
requirements:
|
156
|
-
- -
|
139
|
+
- - '>'
|
157
140
|
- !ruby/object:Gem::Version
|
158
|
-
version:
|
159
|
-
segments:
|
160
|
-
- 0
|
161
|
-
hash: 1025235848978620495
|
141
|
+
version: 1.3.1
|
162
142
|
requirements: []
|
163
143
|
rubyforge_project:
|
164
|
-
rubygems_version:
|
144
|
+
rubygems_version: 2.0.3
|
165
145
|
signing_key:
|
166
|
-
specification_version:
|
146
|
+
specification_version: 4
|
167
147
|
summary: Extension for strong_parameters.
|
168
148
|
test_files:
|
169
|
-
- spec/arcane/chain_spec.rb
|
170
149
|
- spec/arcane/finder_spec.rb
|
150
|
+
- spec/arcane/parameters_spec.rb
|
171
151
|
- spec/arcane/refinery_spec.rb
|
172
152
|
- spec/arcane_spec.rb
|
173
153
|
- spec/spec_helper.rb
|
data/lib/arcane/chain.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module Arcane
|
2
|
-
|
3
|
-
class Chain
|
4
|
-
|
5
|
-
attr_reader :_params, :_user, :_object, :_arcane, :_arcane_class
|
6
|
-
|
7
|
-
def initialize(_params,_object,_user)
|
8
|
-
@_user = _user
|
9
|
-
@_object = _object
|
10
|
-
@_params = ActionController::Parameters.new(_params)
|
11
|
-
@_arcane_class = Arcane::Finder.new(_object).arcane
|
12
|
-
@_arcane = @_arcane_class.new(_object,_user)
|
13
|
-
end
|
14
|
-
|
15
|
-
def method_missing(_arcane_method,*args)
|
16
|
-
|
17
|
-
if _arcane.respond_to?(_arcane_method)
|
18
|
-
_computed = _arcane.public_send(_arcane_method)
|
19
|
-
elsif _arcane.respond_to?(:default)
|
20
|
-
_computed = _arcane.default
|
21
|
-
else
|
22
|
-
_computed = []
|
23
|
-
end
|
24
|
-
|
25
|
-
if _arcane.respond_to?(:root)
|
26
|
-
_root = arcane.root
|
27
|
-
elsif _arcane_class.respond_to?(:root)
|
28
|
-
_root = _arcane_class.root
|
29
|
-
else
|
30
|
-
_root = Arcane::Finder.object_name(_object)
|
31
|
-
end
|
32
|
-
|
33
|
-
if _root.present?
|
34
|
-
_params.require(_root.parameterize).permit(*_computed)
|
35
|
-
else
|
36
|
-
_params.permit(*_computed)
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
data/spec/arcane/chain_spec.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Arcane::Chain do
|
4
|
-
|
5
|
-
let(:chain) { Arcane::Chain.new(params,object,user) }
|
6
|
-
|
7
|
-
let(:user) { double }
|
8
|
-
let(:object) { Article.new }
|
9
|
-
let(:arcane_class) { ArticleRefinery }
|
10
|
-
let(:params) { ActionController::Parameters.new(hash_params) }
|
11
|
-
let(:hash_params) do
|
12
|
-
{
|
13
|
-
article: {
|
14
|
-
title: "hello",
|
15
|
-
content: "world",
|
16
|
-
links: [
|
17
|
-
{ blog: "http://blog.example.com" },
|
18
|
-
{ site: "http://www.example.com" },
|
19
|
-
]
|
20
|
-
}
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '.new' do
|
25
|
-
|
26
|
-
it 'sets attributes' do
|
27
|
-
chain._params.should eq(params)
|
28
|
-
chain._object.should eq(object)
|
29
|
-
chain._user.should eq(user)
|
30
|
-
chain._arcane.should be_a(arcane_class)
|
31
|
-
chain._arcane_class.should eq(arcane_class)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'converts the object to ActionController::Parameters' do
|
35
|
-
chain = Arcane::Chain.new(hash_params,object,user)
|
36
|
-
chain._params.should be_a ActionController::Parameters
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
describe '#method_missing' do
|
42
|
-
|
43
|
-
it 'returns the filtered parameters' do
|
44
|
-
chain.void_method.should be_a ActionController::Parameters
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'filters the same as the default constraint' do
|
48
|
-
chain.void_method.should eq chain.default
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'without root in params' do
|
52
|
-
let(:chain) { Arcane::Chain.new(params[:article],object,user) }
|
53
|
-
it 'raises an error' do
|
54
|
-
expect { chain.void_method }.to raise_error ActionController::ParameterMissing
|
55
|
-
end
|
56
|
-
it 'successds with nil root in arcane' do
|
57
|
-
arcane_class.stub(:root) { false }
|
58
|
-
expect { chain.void_method }.to_not raise_error
|
59
|
-
arcane_class.stub(:root) { nil }
|
60
|
-
expect { chain.void_method }.to_not raise_error
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|