decent_exposure 3.0.2 → 3.0.4
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 +5 -5
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/decent_exposure.gemspec +13 -12
- data/lib/decent_exposure/attribute.rb +0 -1
- data/lib/decent_exposure/behavior.rb +1 -1
- data/lib/decent_exposure/context.rb +2 -2
- data/lib/decent_exposure/controller.rb +4 -4
- data/lib/decent_exposure/exposure.rb +21 -21
- data/lib/decent_exposure/flow.rb +2 -3
- data/lib/decent_exposure/mailer.rb +1 -1
- data/lib/decent_exposure/version.rb +1 -1
- data/lib/decent_exposure.rb +6 -6
- data/lib/generators/decent_exposure/scaffold_templates_generator.rb +7 -7
- data/spec/decent_exposure/controller_spec.rb +39 -38
- data/spec/features/api_birds_controller_spec.rb +9 -9
- data/spec/features/birds_controller_spec.rb +16 -9
- data/spec/features/birds_mailer_spec.rb +5 -5
- data/spec/generators/decent_exposure/scaffold_templates_generator_spec.rb +19 -20
- data/spec/support/rails_app.rb +8 -6
- metadata +21 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f14b1fe6ed0c7cfea5f043262895e4f17bbd9cdd8f019259d8d0a44fb1f9f98
|
4
|
+
data.tar.gz: b5e0989425e1f94847b6867c4a0e81bd87d07a9fcd2683c9d64412700f7fd0d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 705363f8c4b0fe230b6a25b3e171e74f936d1d1bc34af6a10b809d8283324c2b7a249e00d5455f5c2cec28944cf3aee94f0c2487b1c45f2b99a8ba0e60e732a8
|
7
|
+
data.tar.gz: d784e10c482a0a9e35c4aa21cf51632d6d0d28c0055f1f0b302259505c8b4f2d7feac9208af402a02a799ffca444c81d89f52ed278ef380096f1e6b45b30100c
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -45,7 +45,7 @@ end
|
|
45
45
|
|
46
46
|
Now every time you call `thing` in your controller or view, it will look for an
|
47
47
|
ID and try to perform `Thing.find(id)`. If the ID isn't found, it will call
|
48
|
-
`Thing.new(
|
48
|
+
`Thing.new(thing_params)`. The result will be memoized in an `@exposed_thing`
|
49
49
|
instance variable.
|
50
50
|
|
51
51
|
#### Example Controller
|
@@ -328,7 +328,7 @@ expose :another_thing, with: :cool_build
|
|
328
328
|
|
329
329
|
## Rails Mailers
|
330
330
|
|
331
|
-
Mailers and Controllers use the
|
331
|
+
Mailers and Controllers use the same decent_exposure dsl.
|
332
332
|
|
333
333
|
### Example Mailer
|
334
334
|
|
@@ -386,4 +386,4 @@ rails generate scaffold post title description:text
|
|
386
386
|
|
387
387
|
[](https://hashrocket.com)
|
388
388
|
|
389
|
-
Decent Exposure is supported by the team at [Hashrocket](https://hashrocket.com), a multidisciplinary design & development consultancy. If you'd like to [work with us](https://hashrocket.com/contact
|
389
|
+
Decent Exposure is supported by the team at [Hashrocket](https://hashrocket.com), a multidisciplinary design & development consultancy. If you'd like to [work with us](https://hashrocket.com/contact) or [join our team](https://hashrocket.com/careers), don't hesitate to get in touch.
|
data/decent_exposure.gemspec
CHANGED
@@ -1,29 +1,30 @@
|
|
1
1
|
require File.expand_path("../lib/decent_exposure/version", __FILE__)
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
|
-
spec.name
|
5
|
-
spec.version
|
6
|
-
spec.authors
|
7
|
-
spec.email
|
8
|
-
spec.summary
|
9
|
-
spec.description =
|
4
|
+
spec.name = "decent_exposure"
|
5
|
+
spec.version = DecentExposure::VERSION
|
6
|
+
spec.authors = ["Pavel Pravosud", "Stephen Caudill"]
|
7
|
+
spec.email = ["info@hashrocket.com"]
|
8
|
+
spec.summary = "A helper for creating declarative interfaces in controllers"
|
9
|
+
spec.description = '
|
10
10
|
DecentExposure helps you program to an interface, rather than an
|
11
11
|
implementation in your Rails controllers. The fact of the matter is that
|
12
12
|
sharing state via instance variables in controllers promotes close coupling
|
13
13
|
with views. DecentExposure gives you a declarative manner of exposing an
|
14
14
|
interface to the state that controllers contain and thereby decreasing
|
15
15
|
coupling and improving your testability and overall design.
|
16
|
-
|
17
|
-
spec.homepage
|
18
|
-
spec.license
|
19
|
-
spec.files
|
20
|
-
spec.test_files
|
16
|
+
'
|
17
|
+
spec.homepage = "https://github.com/hashrocket/decent_exposure"
|
18
|
+
spec.license = "MIT"
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
spec.test_files = spec.files.grep(/\Aspec\//)
|
21
21
|
spec.require_path = "lib"
|
22
22
|
|
23
|
-
spec.required_ruby_version = "
|
23
|
+
spec.required_ruby_version = ">= 2.0"
|
24
24
|
|
25
25
|
spec.add_dependency "activesupport", ">= 4.0"
|
26
26
|
spec.add_development_dependency "railties", ">= 4.0"
|
27
27
|
spec.add_development_dependency "actionmailer"
|
28
28
|
spec.add_development_dependency "rspec-rails", "~> 3.0"
|
29
|
+
spec.add_development_dependency "standard"
|
29
30
|
end
|
@@ -20,7 +20,7 @@ module DecentExposure
|
|
20
20
|
#
|
21
21
|
# Returns the attribute's value.
|
22
22
|
def get
|
23
|
-
ivar_defined
|
23
|
+
ivar_defined? ? ivar_get : set(fetch_value)
|
24
24
|
end
|
25
25
|
|
26
26
|
# Public: Write to an attribute on the context Class.
|
@@ -51,7 +51,7 @@ module DecentExposure
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def ivar_name
|
54
|
-
"@#{attribute.ivar_name.gsub(
|
54
|
+
"@#{attribute.ivar_name.gsub("?", "_question_mark_")}"
|
55
55
|
end
|
56
56
|
|
57
57
|
def fetch_value
|
@@ -17,8 +17,8 @@ module DecentExposure
|
|
17
17
|
#
|
18
18
|
# Returns the helper methods that are now defined on the class
|
19
19
|
# where this method is included.
|
20
|
-
def expose(*args, &block)
|
21
|
-
Exposure.expose! self, *args, &block
|
20
|
+
def expose(*args, **options, &block)
|
21
|
+
Exposure.expose! self, *args, **options, &block
|
22
22
|
end
|
23
23
|
|
24
24
|
# Public: Exposes an attribute to a controller Class.
|
@@ -33,8 +33,8 @@ module DecentExposure
|
|
33
33
|
#
|
34
34
|
# Sets the exposed attribute to a before_action callback in the
|
35
35
|
# controller.
|
36
|
-
def expose!(name, *args, &block)
|
37
|
-
expose name, *args, &block
|
36
|
+
def expose!(name, *args, **options, &block)
|
37
|
+
expose name, *args, **options, &block
|
38
38
|
before_action name
|
39
39
|
end
|
40
40
|
|
@@ -13,8 +13,8 @@ module DecentExposure
|
|
13
13
|
# the Proc when called.
|
14
14
|
#
|
15
15
|
# Returns a collection of exposed helper methods.
|
16
|
-
def self.expose!(*args, &block)
|
17
|
-
new(*args, &block).expose!
|
16
|
+
def self.expose!(*args, **options, &block)
|
17
|
+
new(*args, **options, &block).expose!
|
18
18
|
end
|
19
19
|
|
20
20
|
# Public: Initalize an Exposure with a hash of options.
|
@@ -34,7 +34,7 @@ module DecentExposure
|
|
34
34
|
# the Proc.
|
35
35
|
#
|
36
36
|
# Returns a normalized options Hash.
|
37
|
-
def initialize(controller, name, fetch_block=nil, **options, &block)
|
37
|
+
def initialize(controller, name, fetch_block = nil, **options, &block)
|
38
38
|
@controller = controller
|
39
39
|
@options = options.with_indifferent_access.merge(name: name)
|
40
40
|
|
@@ -86,43 +86,43 @@ module DecentExposure
|
|
86
86
|
|
87
87
|
def normalize_fetch_option
|
88
88
|
normalize_non_proc_option :fetch do |method_name|
|
89
|
-
->{ send(method_name) }
|
89
|
+
-> { send(method_name) }
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
93
|
def normalize_find_by_option
|
94
|
-
if find_by = options.delete(:find_by)
|
95
|
-
merge_lambda_option :find, ->(id, scope){ scope.find_by!(find_by => id) }
|
94
|
+
if (find_by = options.delete(:find_by))
|
95
|
+
merge_lambda_option :find, ->(id, scope) { scope.find_by!(find_by => id) }
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
99
|
def normalize_parent_option
|
100
100
|
exposure_name = options.fetch(:name)
|
101
101
|
|
102
|
-
if parent = options.delete(:parent)
|
103
|
-
merge_lambda_option :scope, ->{ send(parent).send(exposure_name.to_s.pluralize) }
|
102
|
+
if (parent = options.delete(:parent))
|
103
|
+
merge_lambda_option :scope, -> { send(parent).send(exposure_name.to_s.pluralize) }
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
107
|
def normalize_from_option
|
108
108
|
exposure_name = options.fetch(:name)
|
109
109
|
|
110
|
-
if from = options.delete(:from)
|
111
|
-
merge_lambda_option :build, ->{ send(from).send(exposure_name) }
|
112
|
-
merge_lambda_option :model, ->{ nil }
|
113
|
-
merge_lambda_option :id, ->{ nil }
|
110
|
+
if (from = options.delete(:from))
|
111
|
+
merge_lambda_option :build, -> { send(from).send(exposure_name) }
|
112
|
+
merge_lambda_option :model, -> { nil }
|
113
|
+
merge_lambda_option :id, -> { nil }
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
117
|
def normalize_with_option
|
118
|
-
if configs = options.delete(:with)
|
119
|
-
Array.wrap(configs).each{ |config| reverse_merge_config! config }
|
118
|
+
if (configs = options.delete(:with))
|
119
|
+
Array.wrap(configs).each { |config| reverse_merge_config! config }
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
123
|
def normalize_id_option
|
124
124
|
normalize_non_proc_option :id do |ids|
|
125
|
-
->{ Array.wrap(ids).map{ |id| params[id] }.find(&:present?) }
|
125
|
+
-> { Array.wrap(ids).map { |id| params[id] }.find(&:present?) }
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
@@ -134,7 +134,7 @@ module DecentExposure
|
|
134
134
|
value
|
135
135
|
end
|
136
136
|
|
137
|
-
->{ model }
|
137
|
+
-> { model }
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
@@ -147,7 +147,7 @@ module DecentExposure
|
|
147
147
|
|
148
148
|
def normalize_scope_options
|
149
149
|
normalize_non_proc_option :scope do |custom_scope|
|
150
|
-
->(model){ model.send(custom_scope) }
|
150
|
+
->(model) { model.send(custom_scope) }
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
@@ -165,7 +165,7 @@ module DecentExposure
|
|
165
165
|
end
|
166
166
|
|
167
167
|
def merge_lambda_option(name, body)
|
168
|
-
if previous_value = options[name]
|
168
|
+
if (previous_value = options[name]) && (Proc === previous_value)
|
169
169
|
fail ArgumentError, "#{name.to_s.titleize} block is already defined"
|
170
170
|
end
|
171
171
|
|
@@ -178,7 +178,7 @@ module DecentExposure
|
|
178
178
|
|
179
179
|
name = options.fetch(:name)
|
180
180
|
ivar_name = "exposed_#{name}"
|
181
|
-
fetch = ->{ Flow.new(self, local_options).fetch }
|
181
|
+
fetch = -> { Flow.new(self, local_options).fetch }
|
182
182
|
|
183
183
|
Attribute.new(
|
184
184
|
name: name,
|
@@ -189,13 +189,13 @@ module DecentExposure
|
|
189
189
|
end
|
190
190
|
|
191
191
|
def assert_incompatible_options_pair(key1, key2)
|
192
|
-
if options.key?(key1) && options.key?(key2)
|
192
|
+
if options.symbolize_keys.key?(key1) && options.symbolize_keys.key?(key2)
|
193
193
|
fail ArgumentError, "Using #{key1.inspect} option with #{key2.inspect} doesn't make sense"
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
197
197
|
def assert_singleton_option(name)
|
198
|
-
if options.except(name, :name, :decorate).any? && options.key?(name)
|
198
|
+
if options.symbolize_keys.except(name, :name, :decorate).any? && options.symbolize_keys.key?(name)
|
199
199
|
fail ArgumentError, "Using #{name.inspect} option with other options doesn't make sense"
|
200
200
|
end
|
201
201
|
end
|
data/lib/decent_exposure/flow.rb
CHANGED
@@ -42,11 +42,11 @@ module DecentExposure
|
|
42
42
|
delegate :params, to: :controller
|
43
43
|
|
44
44
|
def get_request?
|
45
|
-
controller.request.get?
|
45
|
+
controller.request.get? || controller.request.head?
|
46
46
|
end
|
47
47
|
|
48
48
|
def params_method_name
|
49
|
-
options.fetch(:build_params_method){ "#{name}_params" }
|
49
|
+
options.fetch(:build_params_method) { "#{name}_params" }
|
50
50
|
end
|
51
51
|
|
52
52
|
def handle_flow_method(name, *args, &block)
|
@@ -75,7 +75,6 @@ module DecentExposure
|
|
75
75
|
method.bind(self).call(*args, &block)
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
78
|
def fetch_ivar(name)
|
80
79
|
ivar_name = "@#{name}"
|
81
80
|
|
data/lib/decent_exposure.rb
CHANGED
@@ -4,12 +4,12 @@ require "generators/decent_exposure/scaffold_templates_generator"
|
|
4
4
|
|
5
5
|
module DecentExposure
|
6
6
|
autoload :Controller, "decent_exposure/controller"
|
7
|
-
autoload :Mailer,
|
8
|
-
autoload :Exposure,
|
9
|
-
autoload :Attribute,
|
10
|
-
autoload :Context,
|
11
|
-
autoload :Behavior,
|
12
|
-
autoload :Flow,
|
7
|
+
autoload :Mailer, "decent_exposure/mailer"
|
8
|
+
autoload :Exposure, "decent_exposure/exposure"
|
9
|
+
autoload :Attribute, "decent_exposure/attribute"
|
10
|
+
autoload :Context, "decent_exposure/context"
|
11
|
+
autoload :Behavior, "decent_exposure/behavior"
|
12
|
+
autoload :Flow, "decent_exposure/flow"
|
13
13
|
|
14
14
|
ActiveSupport.on_load :action_controller do
|
15
15
|
include Controller
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require "rails/generators"
|
2
2
|
|
3
3
|
module DecentExposure
|
4
4
|
module Generators
|
5
5
|
class ScaffoldTemplatesGenerator < Rails::Generators::Base
|
6
|
-
desc
|
7
|
-
source_root File.expand_path(
|
8
|
-
class_option :template_engine, desc:
|
6
|
+
desc "Generate DecentExposure scaffold template files"
|
7
|
+
source_root File.expand_path("../templates", __FILE__)
|
8
|
+
class_option :template_engine, desc: "Template engine to be invoked (erb)."
|
9
9
|
|
10
|
-
VIEWS = %i
|
11
|
-
AVAILABLE_ENGINES = %w
|
10
|
+
VIEWS = %i[_form edit index new show]
|
11
|
+
AVAILABLE_ENGINES = %w[erb haml]
|
12
12
|
|
13
13
|
def generate
|
14
14
|
validate_template_engine
|
@@ -20,7 +20,7 @@ module DecentExposure
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def generate_controller
|
23
|
-
copy_template(
|
23
|
+
copy_template("rails/scaffold_controller", "controller.rb")
|
24
24
|
end
|
25
25
|
|
26
26
|
def generate_view(view)
|
@@ -5,7 +5,8 @@ RSpec.describe DecentExposure::Controller do
|
|
5
5
|
class DifferentThing; end
|
6
6
|
|
7
7
|
class BaseController
|
8
|
-
def self.helper_method(*)
|
8
|
+
def self.helper_method(*)
|
9
|
+
end
|
9
10
|
|
10
11
|
def params
|
11
12
|
@params ||= HashWithIndifferentAccess.new
|
@@ -18,18 +19,18 @@ RSpec.describe DecentExposure::Controller do
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
let(:request){ double("Request") }
|
22
|
-
let(:controller){ controller_klass.new }
|
23
|
-
before{ allow(controller).to receive(:request){ request } }
|
22
|
+
let(:request) { double("Request") }
|
23
|
+
let(:controller) { controller_klass.new }
|
24
|
+
before { allow(controller).to receive(:request) { request } }
|
24
25
|
|
25
26
|
%w[expose expose! exposure_config].each do |method_name|
|
26
|
-
define_method method_name do |*args, &block|
|
27
|
-
controller_klass.send method_name, *args, &block
|
27
|
+
define_method method_name do |*args, **options, &block|
|
28
|
+
controller_klass.send method_name, *args, **options, &block
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
32
|
context "getter/setter methods" do
|
32
|
-
before{ expose :thing }
|
33
|
+
before { expose :thing }
|
33
34
|
|
34
35
|
it "defines getter method" do
|
35
36
|
expect(controller).to respond_to(:thing)
|
@@ -70,7 +71,7 @@ RSpec.describe DecentExposure::Controller do
|
|
70
71
|
end
|
71
72
|
|
72
73
|
context "applying" do
|
73
|
-
let(:thing){ double("Thing") }
|
74
|
+
let(:thing) { double("Thing") }
|
74
75
|
|
75
76
|
before do
|
76
77
|
exposure_config :sluggable, find_by: :slug
|
@@ -80,7 +81,7 @@ RSpec.describe DecentExposure::Controller do
|
|
80
81
|
controller.params.merge! check_this_out: "foo", whee: "wut"
|
81
82
|
end
|
82
83
|
|
83
|
-
after{ expect(controller.thing).to eq(thing) }
|
84
|
+
after { expect(controller.thing).to eq(thing) }
|
84
85
|
|
85
86
|
it "can be reused later" do
|
86
87
|
expose :thing, with: :weird_id_name
|
@@ -110,7 +111,7 @@ RSpec.describe DecentExposure::Controller do
|
|
110
111
|
end
|
111
112
|
|
112
113
|
context "with block" do
|
113
|
-
before{ expose(:thing){ compute_thing } }
|
114
|
+
before { expose(:thing) { compute_thing } }
|
114
115
|
|
115
116
|
it "executes block to calculate the value" do
|
116
117
|
allow(controller).to receive(:compute_thing).and_return(42)
|
@@ -119,7 +120,7 @@ RSpec.describe DecentExposure::Controller do
|
|
119
120
|
|
120
121
|
it "executes the block once and memoizes the result" do
|
121
122
|
expect(controller).to receive(:compute_thing).once.and_return(42)
|
122
|
-
10.times{ controller.thing }
|
123
|
+
10.times { controller.thing }
|
123
124
|
end
|
124
125
|
|
125
126
|
it "allows setting value directly" do
|
@@ -129,20 +130,20 @@ RSpec.describe DecentExposure::Controller do
|
|
129
130
|
end
|
130
131
|
|
131
132
|
it "throws and error when providing options with block" do
|
132
|
-
action = ->{ expose(:thing, id: :some_id){ some_code } }
|
133
|
+
action = -> { expose(:thing, id: :some_id) { some_code } }
|
133
134
|
expect(&action).to raise_error(ArgumentError, "Using :fetch option with other options doesn't make sense")
|
134
135
|
end
|
135
136
|
end
|
136
137
|
|
137
138
|
context "passing fetch block as an argument instead of block" do
|
138
139
|
it "is equivalent to passing block" do
|
139
|
-
expose :thing, ->{ compute_thing }
|
140
|
+
expose :thing, -> { compute_thing }
|
140
141
|
expect(controller).to receive(:compute_thing).and_return(42)
|
141
142
|
expect(controller.thing).to eq(42)
|
142
143
|
end
|
143
144
|
|
144
145
|
it "throws an error when passing both block and block-argument" do
|
145
|
-
action = ->{ expose(:thing, ->{}){} }
|
146
|
+
action = -> { expose(:thing, -> {}) {} }
|
146
147
|
expect(&action).to raise_error(ArgumentError, "Fetch block is already defined")
|
147
148
|
end
|
148
149
|
end
|
@@ -157,7 +158,7 @@ RSpec.describe DecentExposure::Controller do
|
|
157
158
|
|
158
159
|
context "redefine fetch" do
|
159
160
|
before do
|
160
|
-
expose :thing, fetch: ->{ compute_thing }
|
161
|
+
expose :thing, fetch: -> { compute_thing }
|
161
162
|
allow(controller).to receive(:compute_thing).and_return(42)
|
162
163
|
end
|
163
164
|
|
@@ -168,9 +169,9 @@ RSpec.describe DecentExposure::Controller do
|
|
168
169
|
|
169
170
|
context "default behaviour" do
|
170
171
|
context "build" do
|
171
|
-
let(:thing){ double("Thing") }
|
172
|
+
let(:thing) { double("Thing") }
|
172
173
|
|
173
|
-
after{ expect(controller.thing).to eq(thing) }
|
174
|
+
after { expect(controller.thing).to eq(thing) }
|
174
175
|
|
175
176
|
context "params method is not available" do
|
176
177
|
it "builds a new instance with empty hash" do
|
@@ -189,20 +190,20 @@ RSpec.describe DecentExposure::Controller do
|
|
189
190
|
|
190
191
|
it "uses params method on non-get request" do
|
191
192
|
expose :thing
|
192
|
-
expect(request).to
|
193
|
+
expect(request).to receive_messages(get?: false, head?: false)
|
193
194
|
expect(Thing).to receive(:new).with(foo: :bar).and_return(thing)
|
194
195
|
expect(controller).to receive(:thing_params).and_return(foo: :bar)
|
195
196
|
end
|
196
197
|
|
197
198
|
it "can use custom params method name" do
|
198
199
|
expose :thing, build_params: :custom_params_method_name
|
199
|
-
expect(request).to
|
200
|
+
expect(request).to receive_messages(get?: false, head?: false)
|
200
201
|
expect(Thing).to receive(:new).with(foo: :bar).and_return(thing)
|
201
202
|
expect(controller).to receive(:custom_params_method_name).and_return(foo: :bar)
|
202
203
|
end
|
203
204
|
|
204
205
|
it "can use custom build params" do
|
205
|
-
expose :thing, build_params: ->{ foobar }
|
206
|
+
expose :thing, build_params: -> { foobar }
|
206
207
|
expect(controller).to receive(:foobar).and_return(42)
|
207
208
|
expect(Thing).to receive(:new).with(42).and_return(thing)
|
208
209
|
end
|
@@ -215,7 +216,7 @@ RSpec.describe DecentExposure::Controller do
|
|
215
216
|
expect(DifferentThing).to receive(:find).with(10)
|
216
217
|
end
|
217
218
|
|
218
|
-
after{ controller.thing }
|
219
|
+
after { controller.thing }
|
219
220
|
|
220
221
|
it "checks params[:different_thing_id] first" do
|
221
222
|
controller.params.merge! different_thing_id: 10, thing_id: 11, id: 12
|
@@ -232,14 +233,14 @@ RSpec.describe DecentExposure::Controller do
|
|
232
233
|
|
233
234
|
context "find_by" do
|
234
235
|
it "throws and error when using with :find" do
|
235
|
-
action = ->{ expose :thing, find: :foo, find_by: :bar }
|
236
|
+
action = -> { expose :thing, find: :foo, find_by: :bar }
|
236
237
|
expect(&action).to raise_error(ArgumentError, "Using :find_by option with :find doesn't make sense")
|
237
238
|
end
|
238
239
|
|
239
240
|
it "allows to specify what attribute to use for find" do
|
240
241
|
expect(Thing).to receive(:find_by!).with(foo: 10).and_return(42)
|
241
242
|
expose :thing, find_by: :foo
|
242
|
-
controller.params
|
243
|
+
controller.params[:id] = 10
|
243
244
|
expect(controller.thing).to eq(42)
|
244
245
|
end
|
245
246
|
end
|
@@ -247,19 +248,19 @@ RSpec.describe DecentExposure::Controller do
|
|
247
248
|
context "parent option" do
|
248
249
|
context "with scope/model options" do
|
249
250
|
it "throws an error when used with scope option" do
|
250
|
-
action = ->{ expose :thing, scope: :foo, parent: :something }
|
251
|
+
action = -> { expose :thing, scope: :foo, parent: :something }
|
251
252
|
expect(&action).to raise_error(ArgumentError, "Using :parent option with :scope doesn't make sense")
|
252
253
|
end
|
253
254
|
|
254
255
|
it "throws an error when used with model option" do
|
255
|
-
action = ->{ expose :thing, model: :foo, parent: :something }
|
256
|
+
action = -> { expose :thing, model: :foo, parent: :something }
|
256
257
|
expect(&action).to raise_error(ArgumentError, "Using :parent option with :model doesn't make sense")
|
257
258
|
end
|
258
259
|
end
|
259
260
|
|
260
261
|
context "build/find" do
|
261
|
-
let(:current_user){ double("User") }
|
262
|
-
let(:scope){ double("Scope") }
|
262
|
+
let(:current_user) { double("User") }
|
263
|
+
let(:scope) { double("Scope") }
|
263
264
|
|
264
265
|
before do
|
265
266
|
expect(controller).to receive(:current_user).and_return(current_user)
|
@@ -267,26 +268,26 @@ RSpec.describe DecentExposure::Controller do
|
|
267
268
|
expose :thing, parent: :current_user
|
268
269
|
end
|
269
270
|
|
270
|
-
after{ expect(controller.thing).to eq(42) }
|
271
|
+
after { expect(controller.thing).to eq(42) }
|
271
272
|
|
272
273
|
it "sets the scope to belong to parent defined by controller method" do
|
273
274
|
expect(scope).to receive(:new).with({}).and_return(42)
|
274
275
|
end
|
275
276
|
|
276
277
|
it "scopes the find to proper scope" do
|
277
|
-
controller.params
|
278
|
+
controller.params[:thing_id] = 10
|
278
279
|
expect(scope).to receive(:find).with(10).and_return(42)
|
279
280
|
end
|
280
281
|
end
|
281
282
|
end
|
282
283
|
|
283
284
|
context "override model" do
|
284
|
-
let(:different_thing){ double("DifferentThing") }
|
285
|
-
before{ expect(DifferentThing).to receive(:new).with({}).and_return(different_thing) }
|
286
|
-
after{ expect(controller.thing).to eq(different_thing) }
|
285
|
+
let(:different_thing) { double("DifferentThing") }
|
286
|
+
before { expect(DifferentThing).to receive(:new).with({}).and_return(different_thing) }
|
287
|
+
after { expect(controller.thing).to eq(different_thing) }
|
287
288
|
|
288
289
|
it "allows overriding model class with proc" do
|
289
|
-
expose :thing, model: ->{ DifferentThing }
|
290
|
+
expose :thing, model: -> { DifferentThing }
|
290
291
|
end
|
291
292
|
|
292
293
|
it "allows overriding model with class" do
|
@@ -305,7 +306,7 @@ RSpec.describe DecentExposure::Controller do
|
|
305
306
|
context "override scope" do
|
306
307
|
it "allows overriding scope with proc" do
|
307
308
|
scope = double("Scope")
|
308
|
-
expose :thing, scope: ->{ scope }
|
309
|
+
expose :thing, scope: -> { scope }
|
309
310
|
expect(scope).to receive(:new).and_return(42)
|
310
311
|
expect(controller.thing).to eq(42)
|
311
312
|
end
|
@@ -326,7 +327,7 @@ RSpec.describe DecentExposure::Controller do
|
|
326
327
|
end
|
327
328
|
|
328
329
|
it "allows overriding id with proc" do
|
329
|
-
expose :thing, id: ->{ get_thing_id_somehow }
|
330
|
+
expose :thing, id: -> { get_thing_id_somehow }
|
330
331
|
expect(controller).to receive(:get_thing_id_somehow).and_return(42)
|
331
332
|
end
|
332
333
|
|
@@ -343,7 +344,7 @@ RSpec.describe DecentExposure::Controller do
|
|
343
344
|
|
344
345
|
context "override decorator" do
|
345
346
|
it "allows specify decorator" do
|
346
|
-
expose :thing, decorate: ->(thing){ decorate(thing) }
|
347
|
+
expose :thing, decorate: ->(thing) { decorate(thing) }
|
347
348
|
thing = double("Thing")
|
348
349
|
expect(Thing).to receive(:new).with({}).and_return(thing)
|
349
350
|
expect(controller).to receive(:decorate).with(thing)
|
@@ -362,7 +363,7 @@ RSpec.describe DecentExposure::Controller do
|
|
362
363
|
end
|
363
364
|
|
364
365
|
it "should throw error when used with other options" do
|
365
|
-
action = ->{ expose :thing, from: :foo, parent: :bar }
|
366
|
+
action = -> { expose :thing, from: :foo, parent: :bar }
|
366
367
|
expect(&action).to raise_error(ArgumentError, "Using :from option with other options doesn't make sense")
|
367
368
|
end
|
368
369
|
|
@@ -372,7 +373,7 @@ RSpec.describe DecentExposure::Controller do
|
|
372
373
|
foo = double("Foo", thing: thing)
|
373
374
|
expect(controller).to receive(:foo).and_return(foo)
|
374
375
|
expect(controller).to receive(:decorate).with(thing).and_return(decorated_thing)
|
375
|
-
expose :thing, from: :foo, decorate: ->(thing){ decorate(thing) }
|
376
|
+
expose :thing, from: :foo, decorate: ->(thing) { decorate(thing) }
|
376
377
|
expect(controller.thing).to eq(decorated_thing)
|
377
378
|
end
|
378
379
|
end
|
@@ -3,11 +3,11 @@ require "support/rails_app"
|
|
3
3
|
require "rspec/rails"
|
4
4
|
|
5
5
|
RSpec.describe Api::BirdsController, type: :controller do
|
6
|
-
let(:bird){ Bird.new }
|
6
|
+
let(:bird) { Bird.new }
|
7
7
|
|
8
|
-
context
|
8
|
+
context "when birds relation is exposed" do
|
9
9
|
class Api::BirdsController
|
10
|
-
expose :birds, ->{ Bird.all }
|
10
|
+
expose :birds, -> { Bird.all }
|
11
11
|
end
|
12
12
|
|
13
13
|
it "fetches all birds" do
|
@@ -17,20 +17,20 @@ RSpec.describe Api::BirdsController, type: :controller do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
context
|
20
|
+
context "when a bird is exposed" do
|
21
21
|
class Api::BirdsController
|
22
22
|
expose :bird
|
23
23
|
end
|
24
24
|
|
25
25
|
it "finds model by id" do
|
26
26
|
expect(Bird).to receive(:find).with("bird-id").and_return(bird)
|
27
|
-
get :show, request_params(id: "bird-id")
|
27
|
+
get :show, **request_params(id: "bird-id")
|
28
28
|
expect(controller.bird).to eq(bird)
|
29
29
|
end
|
30
30
|
|
31
31
|
it "finds model by bird_id" do
|
32
32
|
expect(Bird).to receive(:find).with("bird-id").and_return(bird)
|
33
|
-
get :new, request_params(bird_id: "bird-id")
|
33
|
+
get :new, **request_params(bird_id: "bird-id")
|
34
34
|
expect(controller.bird).to eq(bird)
|
35
35
|
end
|
36
36
|
|
@@ -50,12 +50,12 @@ RSpec.describe Api::BirdsController, type: :controller do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it "bird is build with params set" do
|
53
|
-
post :create, request_params(bird: {
|
53
|
+
post :create, **request_params(bird: {name: "crow"})
|
54
54
|
expect(controller.bird.name).to eq("crow")
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
context
|
58
|
+
context "when a bird? with a question mark is exposed" do
|
59
59
|
class Api::BirdsController
|
60
60
|
expose :bird
|
61
61
|
expose :bird?, -> { bird.present? }
|
@@ -63,7 +63,7 @@ RSpec.describe Api::BirdsController, type: :controller do
|
|
63
63
|
|
64
64
|
it "exposes bird?" do
|
65
65
|
expect(Bird).to receive(:find).with("bird-id").and_return(bird)
|
66
|
-
get :show, request_params(id: "bird-id")
|
66
|
+
get :show, **request_params(id: "bird-id")
|
67
67
|
expect(controller.bird?).to be true
|
68
68
|
end
|
69
69
|
end
|
@@ -3,11 +3,11 @@ require "support/rails_app"
|
|
3
3
|
require "rspec/rails"
|
4
4
|
|
5
5
|
RSpec.describe BirdsController, type: :controller do
|
6
|
-
let(:bird){ Bird.new }
|
6
|
+
let(:bird) { Bird.new }
|
7
7
|
|
8
|
-
context
|
8
|
+
context "when birds relation is exposed" do
|
9
9
|
class BirdsController
|
10
|
-
expose :birds, ->{ Bird.all }
|
10
|
+
expose :birds, -> { Bird.all }
|
11
11
|
end
|
12
12
|
|
13
13
|
it "fetches all birds" do
|
@@ -17,20 +17,20 @@ RSpec.describe BirdsController, type: :controller do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
context
|
20
|
+
context "when a bird is exposed" do
|
21
21
|
class BirdsController
|
22
22
|
expose :bird
|
23
23
|
end
|
24
24
|
|
25
25
|
it "finds model by id" do
|
26
26
|
expect(Bird).to receive(:find).with("bird-id").and_return(bird)
|
27
|
-
get :show, request_params(id: "bird-id")
|
27
|
+
get :show, **request_params(id: "bird-id")
|
28
28
|
expect(controller.bird).to eq(bird)
|
29
29
|
end
|
30
30
|
|
31
31
|
it "finds model by bird_id" do
|
32
32
|
expect(Bird).to receive(:find).with("bird-id").and_return(bird)
|
33
|
-
get :new, request_params(bird_id: "bird-id")
|
33
|
+
get :new, **request_params(bird_id: "bird-id")
|
34
34
|
expect(controller.bird).to eq(bird)
|
35
35
|
end
|
36
36
|
|
@@ -38,6 +38,13 @@ RSpec.describe BirdsController, type: :controller do
|
|
38
38
|
get :new
|
39
39
|
expect(controller.bird).to be_a(Bird)
|
40
40
|
end
|
41
|
+
|
42
|
+
context "when request.method is HEAD" do
|
43
|
+
it "builds bird if id is not provided" do
|
44
|
+
head :new
|
45
|
+
expect(controller.bird).to be_a(Bird)
|
46
|
+
end
|
47
|
+
end
|
41
48
|
end
|
42
49
|
|
43
50
|
context "when bird_params is defined" do
|
@@ -50,12 +57,12 @@ RSpec.describe BirdsController, type: :controller do
|
|
50
57
|
end
|
51
58
|
|
52
59
|
it "bird is build with params set" do
|
53
|
-
post :create, request_params(bird: {
|
60
|
+
post :create, **request_params(bird: {name: "crow"})
|
54
61
|
expect(controller.bird.name).to eq("crow")
|
55
62
|
end
|
56
63
|
end
|
57
64
|
|
58
|
-
context
|
65
|
+
context "when a bird? with a question mark is exposed" do
|
59
66
|
class BirdsController
|
60
67
|
expose :bird
|
61
68
|
expose :bird?, -> { bird.present? }
|
@@ -63,7 +70,7 @@ RSpec.describe BirdsController, type: :controller do
|
|
63
70
|
|
64
71
|
it "exposes bird?" do
|
65
72
|
expect(Bird).to receive(:find).with("bird-id").and_return(bird)
|
66
|
-
get :show, request_params(id: "bird-id")
|
73
|
+
get :show, **request_params(id: "bird-id")
|
67
74
|
expect(controller.bird?).to be true
|
68
75
|
end
|
69
76
|
end
|
@@ -25,7 +25,7 @@ class BirdsMailer
|
|
25
25
|
end
|
26
26
|
|
27
27
|
RSpec.describe BirdsMailer, type: :mailer do
|
28
|
-
let(:bird){ double :bird }
|
28
|
+
let(:bird) { double :bird }
|
29
29
|
let(:birds) { double :birds }
|
30
30
|
|
31
31
|
context "when birds relation is exposed" do
|
@@ -38,16 +38,16 @@ RSpec.describe BirdsMailer, type: :mailer do
|
|
38
38
|
|
39
39
|
context "when bird is exposed" do
|
40
40
|
it "sends the email with exposed bird" do
|
41
|
-
expect(Bird).to receive(:find).with(
|
42
|
-
expect(described_class.hello_bird(id:
|
41
|
+
expect(Bird).to receive(:find).with("some-id").and_return(bird)
|
42
|
+
expect(described_class.hello_bird(id: "some-id").body.to_s)
|
43
43
|
.to include("Hello #{bird}")
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
context "with non hash argument" do
|
48
48
|
it "does not set params" do
|
49
|
-
expect(Bird).to receive(:find).with(
|
50
|
-
expect(described_class.hello_bird_by_id(
|
49
|
+
expect(Bird).to receive(:find).with("some-id").and_return(bird)
|
50
|
+
expect(described_class.hello_bird_by_id("some-id").body.to_s)
|
51
51
|
.to include("Hello #{bird}")
|
52
52
|
end
|
53
53
|
end
|
@@ -1,45 +1,44 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
RSpec.describe DecentExposure::Generators::ScaffoldTemplatesGenerator, type: :generator do
|
4
|
-
|
5
4
|
subject(:generator) { described_class.new }
|
6
5
|
|
7
|
-
context
|
8
|
-
it
|
9
|
-
allow(generator).to receive(:copy_file).with(
|
10
|
-
allow(generator).to receive(:copy_file).with(
|
11
|
-
allow(generator).to receive(:copy_file).with(
|
12
|
-
allow(generator).to receive(:copy_file).with(
|
13
|
-
allow(generator).to receive(:copy_file).with(
|
14
|
-
allow(generator).to receive(:copy_file).with(
|
6
|
+
context "with erb" do
|
7
|
+
it "generates controller and erb views" do
|
8
|
+
allow(generator).to receive(:copy_file).with("controller.rb", "lib/templates/rails/scaffold_controller/controller.rb")
|
9
|
+
allow(generator).to receive(:copy_file).with("_form.html.erb", "lib/templates/erb/scaffold/_form.html.erb")
|
10
|
+
allow(generator).to receive(:copy_file).with("edit.html.erb", "lib/templates/erb/scaffold/edit.html.erb")
|
11
|
+
allow(generator).to receive(:copy_file).with("index.html.erb", "lib/templates/erb/scaffold/index.html.erb")
|
12
|
+
allow(generator).to receive(:copy_file).with("new.html.erb", "lib/templates/erb/scaffold/new.html.erb")
|
13
|
+
allow(generator).to receive(:copy_file).with("show.html.erb", "lib/templates/erb/scaffold/show.html.erb")
|
15
14
|
|
16
15
|
generator.generate
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
|
-
context
|
19
|
+
context "with haml" do
|
21
20
|
before do
|
22
21
|
allow(generator).to receive(:options).and_return(template_engine: :haml)
|
23
22
|
end
|
24
23
|
|
25
|
-
it
|
26
|
-
allow(generator).to receive(:copy_file).with(
|
27
|
-
allow(generator).to receive(:copy_file).with(
|
28
|
-
allow(generator).to receive(:copy_file).with(
|
29
|
-
allow(generator).to receive(:copy_file).with(
|
30
|
-
allow(generator).to receive(:copy_file).with(
|
31
|
-
allow(generator).to receive(:copy_file).with(
|
24
|
+
it "generates controller and haml views" do
|
25
|
+
allow(generator).to receive(:copy_file).with("controller.rb", "lib/templates/rails/scaffold_controller/controller.rb")
|
26
|
+
allow(generator).to receive(:copy_file).with("_form.html.haml", "lib/templates/haml/scaffold/_form.html.haml")
|
27
|
+
allow(generator).to receive(:copy_file).with("edit.html.haml", "lib/templates/haml/scaffold/edit.html.haml")
|
28
|
+
allow(generator).to receive(:copy_file).with("index.html.haml", "lib/templates/haml/scaffold/index.html.haml")
|
29
|
+
allow(generator).to receive(:copy_file).with("new.html.haml", "lib/templates/haml/scaffold/new.html.haml")
|
30
|
+
allow(generator).to receive(:copy_file).with("show.html.haml", "lib/templates/haml/scaffold/show.html.haml")
|
32
31
|
|
33
32
|
generator.generate
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
context
|
36
|
+
context "with invalid template_engine" do
|
38
37
|
before do
|
39
38
|
allow(generator).to receive(:options).and_return(template_engine: :foo_bar)
|
40
39
|
end
|
41
40
|
|
42
|
-
it
|
41
|
+
it "raises an ArgumentError" do
|
43
42
|
expect { generator.generate }. to raise_error(ArgumentError)
|
44
43
|
end
|
45
44
|
end
|
data/spec/support/rails_app.rb
CHANGED
@@ -3,12 +3,14 @@ require "rails"
|
|
3
3
|
|
4
4
|
def request_params(params)
|
5
5
|
return params if Rails::VERSION::MAJOR < 5
|
6
|
-
{
|
6
|
+
{params: params}
|
7
7
|
end
|
8
8
|
|
9
9
|
module Rails
|
10
10
|
class App
|
11
|
-
def env_config
|
11
|
+
def env_config
|
12
|
+
{}
|
13
|
+
end
|
12
14
|
|
13
15
|
def routes
|
14
16
|
@routes ||= ActionDispatch::Routing::RouteSet.new.tap do |routes|
|
@@ -24,7 +26,7 @@ module Rails
|
|
24
26
|
end
|
25
27
|
|
26
28
|
def self.root
|
27
|
-
|
29
|
+
""
|
28
30
|
end
|
29
31
|
|
30
32
|
def self.application
|
@@ -35,7 +37,7 @@ end
|
|
35
37
|
class Bird
|
36
38
|
attr_accessor :name
|
37
39
|
def initialize(options = {})
|
38
|
-
options.each { |k, v|
|
40
|
+
options.each { |k, v| public_send("#{k}=", v) }
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
@@ -49,7 +51,7 @@ def base_api_class
|
|
49
51
|
end
|
50
52
|
|
51
53
|
class BirdsController < ApplicationController
|
52
|
-
%i
|
54
|
+
%i[index show edit new create update].each do |action|
|
53
55
|
define_method action do
|
54
56
|
head :ok
|
55
57
|
end
|
@@ -58,7 +60,7 @@ end
|
|
58
60
|
|
59
61
|
module Api
|
60
62
|
class BirdsController < base_api_class
|
61
|
-
%i
|
63
|
+
%i[index show edit new create update].each do |action|
|
62
64
|
define_method action do
|
63
65
|
head :ok
|
64
66
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: decent_exposure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Pravosud
|
8
8
|
- Stephen Caudill
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-01-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -67,6 +67,20 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '3.0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: standard
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
70
84
|
description: "\n DecentExposure helps you program to an interface, rather than
|
71
85
|
an\n implementation in your Rails controllers. The fact of the matter is that\n
|
72
86
|
\ sharing state via instance variables in controllers promotes close coupling\n
|
@@ -124,13 +138,13 @@ homepage: https://github.com/hashrocket/decent_exposure
|
|
124
138
|
licenses:
|
125
139
|
- MIT
|
126
140
|
metadata: {}
|
127
|
-
post_install_message:
|
141
|
+
post_install_message:
|
128
142
|
rdoc_options: []
|
129
143
|
require_paths:
|
130
144
|
- lib
|
131
145
|
required_ruby_version: !ruby/object:Gem::Requirement
|
132
146
|
requirements:
|
133
|
-
- - "
|
147
|
+
- - ">="
|
134
148
|
- !ruby/object:Gem::Version
|
135
149
|
version: '2.0'
|
136
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -139,9 +153,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
153
|
- !ruby/object:Gem::Version
|
140
154
|
version: '0'
|
141
155
|
requirements: []
|
142
|
-
|
143
|
-
|
144
|
-
signing_key:
|
156
|
+
rubygems_version: 3.2.3
|
157
|
+
signing_key:
|
145
158
|
specification_version: 4
|
146
159
|
summary: A helper for creating declarative interfaces in controllers
|
147
160
|
test_files:
|