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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a1d34ba1b491cb226abd1ed966b2e1fc51469a5
4
- data.tar.gz: f5a79cc81e6918171764fe3441f81e7da2a372bd
3
+ metadata.gz: 82a9cfe00dccb013cca09b85f68073902bb5928d
4
+ data.tar.gz: 15ec7db35c84401f82a3d8bab5af8079ccf5ea81
5
5
  SHA512:
6
- metadata.gz: 332ca67a8253cbb83e395a95bc79167a9ac355843a772adf1b373569c83086afcc2daed5eb30bbae058a4d57b9fe73992a28d3acaadcc60bac04f47f7bb8eb5d
7
- data.tar.gz: 2558b8622f561444eae1ba3b1c19d46b059cd83f2fe0705e06af4e33bb93e821392b6f02a5d11ebcda03fee01b162066072e60e66fa4cebff0dbdc02b6c01abb
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
- Adequate exposure. Exposing things, adequately.
5
+ Exposing things, adequately.
6
6
 
7
- Adequate exposure is a lightweight alternative to [Decent Exposure](https://github.com/voxdolo/decent_exposure). With it's narrowly focused api you can get exactly what you need without all the extra dressing.
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 inadequate.)*
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 that down we can start talking about the API.
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 controller:
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 id and try to perform `Thing.find(id)` or `Thing.new` if the id is not found. It'll also memoize the result in `@exposed_thing` instance variable.
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
- You can also provide your own logic of how `thing` should be resolved by passing a block that'll be executed in your controller context.
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 is overridable with options. The acceptable options to the `expose` macro are:
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
- How to perform the finding. Could be useful if you don't want to use standard Rails finder.
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
- Allows to specify how to extract id from parameters hash.
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 and instance before it's returned. Useful for decorators.
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 ( https://github.com/[my-github-username]/adequate_exposure/fork )
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`)
@@ -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 = "More adequate than decent"
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,5 +1,3 @@
1
- require "active_support/core_ext/module/delegation"
2
-
3
1
  module AdequateExposure
4
2
  class Context
5
3
  attr_reader :context, :attribute
@@ -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(name, **options, &block)
6
- options = options.merge(name: name)
7
- options.reverse_merge! fetch: block if block_given?
8
- Exposure.new(options).expose! self
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 initialize(options)
6
- @options = options
5
+ def self.expose!(*args, &block)
6
+ new(*args, &block).expose!
7
7
  end
8
8
 
9
- def expose!(controller)
10
- expose_attribute! controller
11
- expose_helper_methods! controller
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!(controller)
31
+ def expose_attribute!
17
32
  attribute.expose! controller
18
33
  end
19
34
 
20
- def expose_helper_methods!(controller)
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, **options)
11
- @controller, @options = controller, HashWithIndifferentAccess.new(options)
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
- id ? decorate(find(id, scope)) : decorate(build(scope))
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
- fetch_first_defined_param %I[#{name}_id id]
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
- symbol_to_class(name)
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 handle_custom_model(value)
57
- Class === value ? value : symbol_to_class(value)
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
- def handle_custom_id(value)
66
- fetch_first_defined_param value
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
- send("handle_custom_#{name}", value, *args)
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
@@ -1,3 +1,3 @@
1
1
  module AdequateExposure
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,4 +1,4 @@
1
- require "active_support/lazy_load_hooks"
1
+ require "active_support/all"
2
2
 
3
3
  module AdequateExposure
4
4
  autoload :Controller, "adequate_exposure/controller"
@@ -43,10 +43,15 @@ describe AdequateExposure::Controller do
43
43
  end
44
44
  end
45
45
 
46
- context "with block" do
47
- before do
48
- expose(:thing){ compute_thing }
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
- it "builds a new instance when id is not provided" do
83
- expect(controller.thing).to be_instance_of(Thing)
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{ expect(Thing).to receive(:find).with(10) }
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
- after{ expect(controller.thing).to be_instance_of(DifferentThing) }
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 with symbol" do
125
- current_user = double("User")
211
+ it "allows overriding model scope using symbol" do
126
212
  scope = double("Scope")
127
- scoped_thing = double("Thing")
128
-
129
- expect(controller).to receive(:current_user).and_return(current_user)
130
- expect(current_user).to receive(:things).and_return(scope)
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
- expect(controller).to receive(:decorate).with(an_instance_of(Thing))
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
@@ -1,5 +1,4 @@
1
1
  require "active_support/all"
2
- require "active_support/dependencies/autoload"
3
2
  require "action_controller"
4
3
  require "action_dispatch"
5
4
  require "rails"
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.1
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-02 00:00:00.000000000 Z
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: More adequate than decent
88
+ summary: Exposing things, adequately
89
89
  test_files:
90
90
  - spec/controller_spec.rb
91
91
  - spec/integration_spec.rb