adequate_exposure 0.0.4 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 08518a93835d972d60b024e436f478f894b811c4
4
- data.tar.gz: 7d0c3042b2d662a44e1d22ec6415fc46c1957078
3
+ metadata.gz: 331663a8f718896cab6be3800c0af9fc98379e8b
4
+ data.tar.gz: e942a3866cdd940adf9dd9e08e979b68b8456446
5
5
  SHA512:
6
- metadata.gz: 3925a14260bd04bf95bba1e8785595ccb2771526b056f42bcc63e88978ab218520bc911462a61b124cef4df0c8103f08e1a2314c63e5623007552387d5786f8a
7
- data.tar.gz: 027d750fbafb02bcee26be876daa877e04c033d5656a035c8df117f0289b8ffa5cc3f4becb93563e952f8b1a40ed95c5ac57efd797136eaebaa204af7389ccdd
6
+ metadata.gz: 4ce222e1500bce49ee95bc6eec47bc7f4956591070fba3b9acf5e5a3e3585296da02c79bb82c6532e65acf7049e39833709e8efe8032a8de58b18a6da26eaf59
7
+ data.tar.gz: 9e292f24fbf0242ee15b8bb41483a2aa73def2316373612645d94c99592430c31ba41bfc3be9d243326e29f5ee62084ec7e408b3da4b12a5201dd07dcf7645d2
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.9
3
+ - 2.0
4
+ - 2.1
data/README.md CHANGED
@@ -1,22 +1,23 @@
1
1
  # Adequate Exposure
2
-
3
- This is WIP. Please don't send pull requests yet, I'm still actively rewriting things.
2
+ [![Gem Version](https://img.shields.io/gem/v/adequate_exposure.svg)](https://rubygems.org/gems/adequate_exposure)
3
+ [![Build Status](https://img.shields.io/travis/rwz/adequate_exposure.svg)](http://travis-ci.org/rwz/adequate_exposure)
4
+ [![Code Climate](https://img.shields.io/codeclimate/github/rwz/adequate_exposure.svg)](https://codeclimate.com/github/rwz/adequate_exposure)
4
5
 
5
6
  Exposing things, adequately.
6
7
 
7
8
  Adequate exposure is a lightweight alternative to [Decent
8
- Exposure](https://github.com/voxdolo/decent_exposure). With it's narrowly
9
+ Exposure](https://github.com/voxdolo/decent_exposure). With its narrowly
9
10
  focused api you can get exactly what you need without all the extra dressing.
10
11
 
11
12
  *Note: It is not the intent of the author to imply that Decent Exposure is
12
- inadequate.)*
13
+ inadequate.*
13
14
 
14
15
  Installation is as simple as: `$ gem install adequate_exposure`. Once you have
15
16
  that down we can start talking about the API.
16
17
 
17
18
  ## API
18
19
 
19
- The whole API consists of one `expose` method.
20
+ The whole API consists of two methods so far: `expose` and `expose!`.
20
21
 
21
22
  In the simplest scenario you'll just use it to expose a model in the
22
23
  controller:
@@ -28,28 +29,29 @@ end
28
29
  ```
29
30
 
30
31
  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.
32
+ ID and try to perform `Thing.find(id)`. If the ID isn't found, it'll call
33
+ `Thing.new(things_params)`. The result will be memoized in an `@exposed_thing`
34
+ instance variable.
33
35
 
34
36
  The default resolving workflow if pretty powerful and customizable. It could be
35
37
  expressed with the following pseudocode:
36
38
 
37
39
  ```ruby
38
40
  def fetch(scope, id)
39
- instance = id ? find(id, scope) : build(scope)
41
+ instance = id ? find(id, scope) : build(build_params, scope)
40
42
  decorate(instance)
41
43
  end
42
44
 
43
45
  def id
44
- params[:id] || params[:thing_id]
46
+ params[:thing_id] || params[:id]
45
47
  end
46
48
 
47
49
  def find(id, scope)
48
- scope.find(id) # Thing.find(id)
50
+ scope.find(id)
49
51
  end
50
52
 
51
- def build(scope)
52
- scope.new(build_params) # Thing.new(thing_params)
53
+ def build(params, scope)
54
+ scope.new(params) # Thing.new(params)
53
55
  end
54
56
 
55
57
  def scope
@@ -73,75 +75,176 @@ def decorate(thing)
73
75
  end
74
76
  ```
75
77
 
78
+ The exposure is also lazy, which means that it won't do anything until you call
79
+ the method. To eliminate this lazyness you can use `expose!` macro instead,
80
+ which will try to resolve the exposure in a before filter.
81
+
76
82
  Each step could be overrided with options. The acceptable options to the
77
83
  `expose` macro are:
78
84
 
79
- **fetch**
85
+ ### `fetch`
80
86
 
81
- This is the entry point. Fetch proc defines how to resolve your exposure in the
82
- first place.
87
+ This is the entry point. The `fetch` proc defines how to resolve your exposure
88
+ in the first place.
83
89
 
84
90
  ```ruby
85
91
  expose :thing, fetch: ->{ get_thing_some_way_or_another }
86
92
  ```
87
93
 
88
- **find**
94
+ Because the above behavior overrides the normal workflow, all other options
95
+ would be ignored. However, Adequate Exposure is decent enough to actually blow
96
+ up with an error so you don't accidentally do this.
89
97
 
90
- Defines how to perform the finding. Could be useful if you don't want to use standard
91
- Rails finder.
98
+ There are other less verbose ways to pass the `fetch` block, since you'll
99
+ probably be using it often:
92
100
 
93
101
  ```ruby
94
- expose :thing, find: ->(id, scope){ scope.find_by(slug: id) }
102
+ expose(:thing){ get_thing_some_way_or_another }
95
103
  ```
96
104
 
97
- **build**
105
+ Or if you (like me) absolutely hate parens in side-effect methods:
98
106
 
99
- Allows to override the build process that takes place when id is not provided.
107
+ ```ruby
108
+ expose :thing, ->{ get_thing_some_way_or_another }
109
+ ```
110
+
111
+ There is another shortcut that allows you to redefine entire fetch block with
112
+ less code:
100
113
 
101
114
  ```ruby
102
- expose :thing, build: ->(scope){ Thing.build_with_defaults }
115
+ expose :comments, from: :post
116
+ # equivalent to
117
+ expose :comments, ->{ post.comments }
103
118
  ```
104
119
 
105
- **id**
120
+ ### `id`
121
+
122
+ The default fetch logic relies on the presence of an ID. And of course Adequate
123
+ Exposure allows to to specify how exactly you want the ID to be extracted.
106
124
 
107
- Specifies how to extract id from parameters hash.
125
+ Default behavior could be expressed using following code:
108
126
 
109
127
  ```ruby
110
- # default
111
128
  expose :thing, id: ->{ params[:thing_id] || params[:id] }
129
+ ```
112
130
 
113
- # id is always goona be 42
131
+ But nothing is stopping you from throwing in any arbitrary code:
132
+
133
+ ```ruby
134
+ # id is always gonna be the answer to ultimate question of life, the universe,
135
+ # and everyting
114
136
  expose :thing, id: ->{ 42 }
137
+ ```
115
138
 
139
+ Passing lambdas might not always be fun, so here are couple shortcuts that could
140
+ help making life easier.
141
+
142
+ ```ruby
116
143
  # equivalent to id: ->{ params[:custom_thing_id] }
117
144
  expose :thing, id: :custom_thing_id
118
145
 
119
146
  # equivalent to id: ->{ params[:try_this_id] || params[:or_maybe_that_id] }
120
- expose :thing, id: %i[try_this_id or_maybe_that_id]
147
+ expose :thing, id: [:try_this_id, :or_maybe_that_id]
148
+ ```
149
+
150
+ ### `find`
151
+
152
+ If an ID was provided, Adequate Exposure will try to find the model using it.
153
+ Default behavior could be expressed with this configuration:
154
+
155
+ ```ruby
156
+ expose :thing, find: ->(id, scope){ scope.find(id) }
157
+ ```
158
+
159
+ Where `scope` is a model scope, like `Thing` or `User.active` or
160
+ `Post.published`.
161
+
162
+ Now, if you're using FriendlyId or Stringex or something similar, you'd have to
163
+ customize your finding logic. You code might look somewhat like this:
164
+
165
+ ```ruby
166
+ expose :thing, find: ->(id, scope){ scope.find_by!(slug: id) }
167
+ ```
168
+
169
+ Again, because this is likely to happen a lot, Adequate Exposure gives you a
170
+ decent shortcut so you can get more done by typing less.
171
+
172
+ ```ruby
173
+ expose :thing, find_by: :slug
121
174
  ```
122
175
 
123
- **scope**
176
+ ### `build`
177
+
178
+ When an ID is not present, Adequate Exposure tries to build an object for you. By
179
+ default, it behaves like this:
180
+
181
+ ```ruby
182
+ expose :thing, build: ->(thing_params, scope){ scope.new(thing_params) }
183
+ ```
184
+
185
+ ### `build_params`
186
+
187
+ This options is responsible for calulating params before passing it to the
188
+ build step. The default behavior was modeled with Strong Parameters in mind and
189
+ is somewhat smart: it calls `thing_params` controller method if it's available
190
+ and request method it not `GET`. In all other cases it produces an empty hash.
191
+
192
+ You can easily specify which controller method you want it to call instead of
193
+ `thing_params`, or just provide your own logic:
194
+
195
+ ```ruby
196
+ expose :thing, build_params: :custom_thing_params
197
+ expose :other_thing, build_params: ->{ { foo: "bar" } }
198
+
199
+ private
200
+
201
+ def custom_thing_params
202
+ # strong parameters stuff goes here
203
+ end
204
+ ```
205
+
206
+ ### `scope`
124
207
 
125
208
  Defines the scope that's used in `find` and `build` steps.
126
209
 
127
210
  ```ruby
128
211
  expose :thing, scope: ->{ current_user.things }
212
+ expose :user, scope: ->{ User.active }
213
+ expose :post, scope: ->{ Post.published }
214
+ ```
215
+
216
+ Like before, shortcuts are there to make you happier:
217
+
218
+ ```ruby
219
+ expose :post, scope: :published
220
+ # fully equivalent to
221
+ expose :post, scope: ->{ Post.published }
222
+ ```
223
+
224
+ and
225
+
226
+ ```ruby
227
+ expose :thing, parent: :current_user
228
+ # fully equivalent to:
229
+ expose :thing, scope: ->{ current_user.things }
129
230
  ```
130
231
 
131
- **model**
232
+ ### `model`
132
233
 
133
- Specify the model class to use.
234
+ Allows to specify the model class to use. Pretty straightforward.
134
235
 
135
236
  ```ruby
136
237
  expose :thing, model: ->{ AnotherThing }
137
238
  expose :thing, model: AnotherThing
239
+ expose :thing, model: "AnotherThing"
138
240
  expose :thing, model: :another_thing
139
241
  ```
140
242
 
243
+ ### `decorate`
141
244
 
142
- **decorate**
143
-
144
- Allows to define a block that wraps an instance before it's returned. Useful for decorators.
245
+ Before returning the thing, Adequate Exposure will run it through the
246
+ decoration process. Initially, this does nothing, but you can obviously change
247
+ that:
145
248
 
146
249
  ```ruby
147
250
  expose :thing, decorate: ->(thing){ ThingDecorator.new(thing) }
@@ -1,6 +1,4 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
4
2
  require "adequate_exposure/version"
5
3
 
6
4
  Gem::Specification.new do |spec|
@@ -15,7 +13,7 @@ Gem::Specification.new do |spec|
15
13
  spec.test_files = spec.files.grep(/\Aspec\//)
16
14
  spec.require_path = "lib"
17
15
 
18
- spec.required_ruby_version = "~> 2.0"
16
+ spec.required_ruby_version = ">= 1.9.3"
19
17
 
20
18
  spec.add_dependency "railties", "~> 4.0"
21
19
  spec.add_dependency "activesupport", "~> 4.0"
@@ -2,8 +2,10 @@ module AdequateExposure
2
2
  class Attribute
3
3
  attr_reader :name, :fetch, :ivar_name
4
4
 
5
- def initialize(name:, fetch:, ivar_name:)
6
- @name, @fetch, @ivar_name = name, fetch, ivar_name
5
+ def initialize(options)
6
+ @name = options.fetch(:name)
7
+ @fetch = options.fetch(:fetch)
8
+ @ivar_name = options.fetch(:ivar_name)
7
9
  end
8
10
 
9
11
  def getter_method_name
@@ -6,8 +6,10 @@ module AdequateExposure
6
6
  new(*args, &block).expose!
7
7
  end
8
8
 
9
- def initialize(controller, name, fetch_block=nil, **options, &block)
9
+ def initialize(controller, name, *args, &block)
10
10
  @controller = controller
11
+ options = args.extract_options!
12
+ fetch_block = args.pop
11
13
  @options = options.with_indifferent_access.merge(name: name)
12
14
 
13
15
  merge_lambda_option :fetch, fetch_block if fetch_block
@@ -11,7 +11,7 @@ module AdequateExposure
11
11
  options.fetch(:name)
12
12
  end
13
13
 
14
- %i[fetch find build build_params scope model id decorate].each do |method_name|
14
+ %w[fetch find build build_params scope model id decorate].each do |method_name|
15
15
  define_method method_name do |*args|
16
16
  ivar_name = "@#{method_name}"
17
17
  return instance_variable_get(ivar_name) if instance_variable_defined?(ivar_name)
@@ -23,7 +23,7 @@ module AdequateExposure
23
23
 
24
24
  def default_fetch
25
25
  computed_scope = scope(model)
26
- instance = id ? find(id, computed_scope) : build(computed_scope)
26
+ instance = id ? find(id, computed_scope) : build(build_params, computed_scope)
27
27
  decorate(instance)
28
28
  end
29
29
 
@@ -43,8 +43,8 @@ module AdequateExposure
43
43
  scope.find(id)
44
44
  end
45
45
 
46
- def default_build(scope)
47
- scope.new(build_params)
46
+ def default_build(params, scope)
47
+ scope.new(params)
48
48
  end
49
49
 
50
50
  def default_decorate(instance)
@@ -1,3 +1,3 @@
1
1
  module AdequateExposure
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -22,7 +22,7 @@ describe AdequateExposure::Controller do
22
22
  let(:controller){ controller_klass.new }
23
23
  before{ allow(controller).to receive(:request){ request } }
24
24
 
25
- %i[expose expose!].each do |method_name|
25
+ %w[expose expose!].each do |method_name|
26
26
  define_method method_name do |*args, &block|
27
27
  controller_klass.send method_name, *args, &block
28
28
  end
@@ -274,7 +274,7 @@ describe AdequateExposure::Controller do
274
274
  end
275
275
 
276
276
  it "allows overriding id with an array of symbols" do
277
- expose :thing, id: %i[non-existent-id lolwut another_id_param]
277
+ expose :thing, id: %w[non-existent-id lolwut another_id_param]
278
278
  controller.params.merge! another_id_param: 42
279
279
  end
280
280
  end
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
4
+ version: 0.0.5
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-07 00:00:00.000000000 Z
11
+ date: 2014-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -46,6 +46,7 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - ".gitignore"
49
+ - ".travis.yml"
49
50
  - Gemfile
50
51
  - LICENSE.txt
51
52
  - README.md
@@ -72,9 +73,9 @@ require_paths:
72
73
  - lib
73
74
  required_ruby_version: !ruby/object:Gem::Requirement
74
75
  requirements:
75
- - - "~>"
76
+ - - ">="
76
77
  - !ruby/object:Gem::Version
77
- version: '2.0'
78
+ version: 1.9.3
78
79
  required_rubygems_version: !ruby/object:Gem::Requirement
79
80
  requirements:
80
81
  - - ">="