decent_exposure 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -284,7 +284,7 @@ This block is evaluated and the memoized result is returned whenever you call
284
284
 
285
285
  For the times when custom behavior is needed for resource finding,
286
286
  `decent_exposure` provides a base class for extending. For example, if
287
- scoping a resource from `current_user` is not and option, but you'd like
287
+ scoping a resource from `current_user` is not an option, but you'd like
288
288
  to verify a resource's relationship to the `current_user`, you can use a
289
289
  custom strategy like the following:
290
290
 
@@ -353,4 +353,52 @@ And opt into it like so:
353
353
  expose(:article, config: :sluggable)
354
354
  ```
355
355
 
356
- [1]: http://blog.voxdolo.me/a-diatribe-on-maintaining-state.html
356
+ ## Testing
357
+
358
+ Controller testing remains trivially easy. The shift is that you now set expectations on methods rather than instance variables. With RSpec, this mostly means avoiding `assign` and `assigns`.
359
+
360
+ ```ruby
361
+ describe CompaniesController do
362
+ describe "GET index" do
363
+
364
+ # this...
365
+ it "assigns @companies" do
366
+ company = Company.create
367
+ get :index
368
+ assigns(:companies).should eq([company])
369
+ end
370
+
371
+ # becomes this
372
+ it "exposes companies" do
373
+ company = Company.create
374
+ get :index
375
+ controller.companies.should eq([company])
376
+ end
377
+ end
378
+ end
379
+ ```
380
+
381
+ View specs follow a similar pattern:
382
+
383
+ ```ruby
384
+ describe "people/index.html.erb" do
385
+
386
+ # this...
387
+ it "lists people" do
388
+ assign(:people, [ mock_model(Person, name: 'John Doe') ])
389
+ render
390
+ rendered.should have_content('John Doe')
391
+ end
392
+
393
+ # becomes this
394
+ it "lists people" do
395
+ view.stub(people: [ mock_model(Person, name: 'John Doe') ])
396
+ render
397
+ rendered.should have_content('John Doe')
398
+ end
399
+
400
+ end
401
+ ```
402
+
403
+
404
+ [1]: http://blog.voxdolo.me/a-diatribe-on-maintaining-state.html
@@ -2,19 +2,20 @@ require 'decent_exposure/active_record_strategy'
2
2
 
3
3
  module DecentExposure
4
4
  class ActiveRecordWithEagerAttributesStrategy < ActiveRecordStrategy
5
- delegate :get?, :to => :request
5
+ delegate :get?, :to => :request
6
+ delegate :delete?, :to => :request
6
7
 
7
8
  def singular?
8
9
  !plural?
9
10
  end
10
11
 
11
12
  def attributes
12
- params[inflector.singular]
13
+ params[inflector.singular] || {}
13
14
  end
14
15
 
15
16
  def assign_attributes?
16
17
  return false unless attributes && singular?
17
- !get? || new_record?
18
+ (!get? && !delete?) || new_record?
18
19
  end
19
20
 
20
21
  def new_record?
@@ -7,7 +7,7 @@ module DecentExposure
7
7
  def initialize(name, strategy, options)
8
8
  self.strategy = strategy
9
9
  self.options = options
10
- self.inflector = DecentExposure::Inflector.new(name)
10
+ self.inflector = DecentExposure::Inflector.new(name, options[:model])
11
11
  end
12
12
 
13
13
  def call(controller)
@@ -1,22 +1,23 @@
1
1
  require 'active_support/inflector'
2
- require 'active_support/core_ext/string/inflections'
2
+ require 'active_support/core_ext/string'
3
3
 
4
4
  module DecentExposure
5
5
  class Inflector
6
- attr_reader :string, :original
6
+ attr_reader :string, :original, :model
7
7
  alias name string
8
8
 
9
- def initialize(name)
10
- @original = name
11
- @string = name.to_s.demodulize
9
+ def initialize(name, model=nil)
10
+ @original = name.to_s
11
+ @model = model
12
+ @string = (model || name).to_s.demodulize
12
13
  end
13
14
 
14
15
  def constant(context=Object)
15
- case original
16
+ case model
16
17
  when Module, Class
17
- original
18
+ model
18
19
  else
19
- context.const_get string.classify
20
+ ConstantResolver.new(context, string.classify).constant
20
21
  end
21
22
  end
22
23
 
@@ -25,7 +26,7 @@ module DecentExposure
25
26
  end
26
27
 
27
28
  def singular
28
- string.parameterize
29
+ @singular ||= string.singularize.parameterize
29
30
  end
30
31
 
31
32
  def plural
@@ -34,7 +35,37 @@ module DecentExposure
34
35
  alias collection plural
35
36
 
36
37
  def plural?
37
- plural == string
38
+ original.pluralize == original && !uncountable?
39
+ end
40
+
41
+ def uncountable?
42
+ original.pluralize == original.singularize
43
+ end
44
+
45
+ private
46
+
47
+ ConstantResolver = Struct.new :context, :constant_name do
48
+
49
+ def constant
50
+ immediate_child || namespace_qualified
51
+ end
52
+
53
+ private
54
+
55
+ def immediate_child
56
+ context.constants.map do |c|
57
+ context.const_get(c) if c.to_s == constant_name
58
+ end.compact.first
59
+ end
60
+
61
+ def namespace_qualified
62
+ namespace.const_get(constant_name)
63
+ end
64
+
65
+ def namespace
66
+ path = context.to_s
67
+ path[0...(path.rindex('::') || 0)].constantize
68
+ end
38
69
  end
39
70
  end
40
71
  end
@@ -1,3 +1,3 @@
1
1
  module DecentExposure #:nodoc
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.1"
3
3
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decent_exposure
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
5
4
  prerelease:
5
+ version: 2.0.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Stephen Caudill
@@ -11,72 +11,72 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-10-10 00:00:00.000000000 Z
14
+ date: 2012-12-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
- name: rspec
18
- requirement: !ruby/object:Gem::Requirement
19
- none: false
17
+ version_requirements: !ruby/object:Gem::Requirement
20
18
  requirements:
21
19
  - - ~>
22
20
  - !ruby/object:Gem::Version
23
21
  version: '2.7'
22
+ none: false
23
+ name: rspec
24
24
  type: :development
25
25
  prerelease: false
26
- version_requirements: !ruby/object:Gem::Requirement
27
- none: false
26
+ requirement: !ruby/object:Gem::Requirement
28
27
  requirements:
29
28
  - - ~>
30
29
  - !ruby/object:Gem::Version
31
30
  version: '2.7'
32
- - !ruby/object:Gem::Dependency
33
- name: rspec-rails
34
- requirement: !ruby/object:Gem::Requirement
35
31
  none: false
32
+ - !ruby/object:Gem::Dependency
33
+ version_requirements: !ruby/object:Gem::Requirement
36
34
  requirements:
37
35
  - - ~>
38
36
  - !ruby/object:Gem::Version
39
37
  version: '2.7'
38
+ none: false
39
+ name: rspec-rails
40
40
  type: :development
41
41
  prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- none: false
42
+ requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - ~>
46
45
  - !ruby/object:Gem::Version
47
46
  version: '2.7'
48
- - !ruby/object:Gem::Dependency
49
- name: actionpack
50
- requirement: !ruby/object:Gem::Requirement
51
47
  none: false
48
+ - !ruby/object:Gem::Dependency
49
+ version_requirements: !ruby/object:Gem::Requirement
52
50
  requirements:
53
51
  - - ~>
54
52
  - !ruby/object:Gem::Version
55
53
  version: '3.1'
54
+ none: false
55
+ name: actionpack
56
56
  type: :development
57
57
  prerelease: false
58
- version_requirements: !ruby/object:Gem::Requirement
59
- none: false
58
+ requirement: !ruby/object:Gem::Requirement
60
59
  requirements:
61
60
  - - ~>
62
61
  - !ruby/object:Gem::Version
63
62
  version: '3.1'
64
- - !ruby/object:Gem::Dependency
65
- name: activesupport
66
- requirement: !ruby/object:Gem::Requirement
67
63
  none: false
64
+ - !ruby/object:Gem::Dependency
65
+ version_requirements: !ruby/object:Gem::Requirement
68
66
  requirements:
69
67
  - - ~>
70
68
  - !ruby/object:Gem::Version
71
69
  version: '3.1'
70
+ none: false
71
+ name: activesupport
72
72
  type: :development
73
73
  prerelease: false
74
- version_requirements: !ruby/object:Gem::Requirement
75
- none: false
74
+ requirement: !ruby/object:Gem::Requirement
76
75
  requirements:
77
76
  - - ~>
78
77
  - !ruby/object:Gem::Version
79
78
  version: '3.1'
79
+ none: false
80
80
  description: ! "\n DecentExposure helps you program to an interface, rather than
81
81
  an\n implementation in your Rails controllers. The fact of the matter is that\n
82
82
  \ sharing state via instance variables in controllers promotes close coupling\n
@@ -107,17 +107,17 @@ rdoc_options:
107
107
  require_paths:
108
108
  - lib
109
109
  required_ruby_version: !ruby/object:Gem::Requirement
110
- none: false
111
110
  requirements:
112
111
  - - ! '>='
113
112
  - !ruby/object:Gem::Version
114
113
  version: '0'
115
- required_rubygems_version: !ruby/object:Gem::Requirement
116
114
  none: false
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
116
  requirements:
118
117
  - - ! '>='
119
118
  - !ruby/object:Gem::Version
120
119
  version: 1.3.6
120
+ none: false
121
121
  requirements: []
122
122
  rubyforge_project:
123
123
  rubygems_version: 1.8.24