shamu 0.0.17 → 0.0.18

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: f6f49a347f5a63383390bc51b9cba9616d7b7fec
4
- data.tar.gz: 732419b2df2e8757cc4772f8e03d59411abbbcbe
3
+ metadata.gz: dd0f794321cd3d306d36b16935e133e3ded9270b
4
+ data.tar.gz: 244f8025c48879a691c7faa6f6e76b3b45efe2e0
5
5
  SHA512:
6
- metadata.gz: 7355e1c846de3a9c53dbcaa6cc301433a0f901464f92f557ca2c0a439fa2385320e7faf53248b895b7364ea17c8ae71fdac828d14b779b0d31b57434c67b016e
7
- data.tar.gz: 61c004a0899ae0707d5d6f1a2b21e200cb80622302c9ac0ed77496c79019888d72006e99cd34f5df07d899354066584d04ada782cf8fba1743f0f0c4f1be4500
6
+ metadata.gz: 57d00e95ce2bf7a4d1ddbc224aff0a2790255a6bd1c1ac907f7450b95a30b63c7ca2cc404d0754c7ee363761386fc5c1567f1f50114957488d538be85d2cbda8
7
+ data.tar.gz: e2ab805eb2ba0db7969601cb825f827c8d5346c8ebd34db8e836543a6726b7327c20b68f092681555b56f1832d8dd8512d08d8bc1ddaf3170e6f221d5b3ab1a0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shamu (0.0.17)
4
+ shamu (0.0.18)
5
5
  activemodel (>= 5.0)
6
6
  activesupport (>= 5.0)
7
7
  crc32 (~> 1)
@@ -46,6 +46,7 @@ module Shamu
46
46
  self.class.attributes.each_with_object({}) do |(name, options), attrs|
47
47
  next if ( only && !match_attribute?( only, name ) ) || ( except && match_attribute?( except, name ) )
48
48
  next unless serialize_attribute?( name, options )
49
+
49
50
  attrs[name] = send( name )
50
51
  end
51
52
  end
@@ -12,6 +12,12 @@ module Shamu
12
12
  public :assign_attributes
13
13
  end
14
14
 
15
+ # @param [Symbol] name of the attribute to assign.
16
+ # @param [Object] value to assign.
17
+ def []=( name, value )
18
+ send :"assign_#{ name }", value if attribute?( name )
19
+ end
20
+
15
21
  # @return [Array<Symbol>] the attributes that have been assigned.
16
22
  def assigned_attributes
17
23
  @assigned_attributes.to_a || []
@@ -20,50 +20,52 @@ module Shamu
20
20
  #
21
21
  # @!endgroup Dependencies
22
22
 
23
+ private
24
+
25
+ # Override {Shamu::Services::RequestSupport#with_partial_request} and to yield
26
+ # a {Transaction} as an additional argument to automatically
27
+ # {#audit_request audit the request}.
28
+ def with_partial_request( *args, &block )
29
+ super( *args ) do |request|
30
+ audit_request request do |transaction|
31
+ yield request, transaction
32
+ end
33
+ end
34
+ end
35
+
23
36
  end
24
37
 
25
38
  private
26
39
 
27
- # @!visibility public
28
- #
29
- # Same as {#audit_request} but does not validate the request before
30
- # yielding to the block.
31
- def audit_partial_request( params, request_class, action: :smart, &block )
32
- perform_audit_request( :with_partial_request, params, request_class, action: action, &block )
33
- end
34
40
 
35
41
  # @!visibility public
36
42
  #
37
43
  # Audit the requested changes and report the request to the
38
44
  # {#auditing_service}.
39
45
  #
40
- # See {Shamu::Services::RequestSupport#with_request}
41
- #
42
- # @param (see Shamu::Services::RequestSupport#with_request)
46
+ # @param [Services::Request] request the coerced request params.
43
47
  # @return (see Shamu::Services::RequestSupport#with_request)
44
- # @yield (request, transaction)
45
- # @yieldparam [Services::Request] request coerced from `params`.
48
+ # @yield (transaction)
46
49
  # @yieldparam [Transaction] transaction the audit transaction. Most fields
47
50
  # will be populated automatically from the request but the block
48
51
  # should call {Transaction#append_entity} to include any parent
49
52
  # entities in the entity path.
50
- def audit_request( params, request_class, action: :smart, &block )
51
- perform_audit_request( :with_request, params, request_class, action: action, &block )
52
- end
53
-
54
- def perform_audit_request( method, params, request_class, action: :smart, &block )
53
+ # @yieldreturn [Services::Result]
54
+ def audit_request( request, action: :smart, &block )
55
55
  transaction = Transaction.new \
56
- user_id_chain: auditing_security_principal.user_id_chain
56
+ user_id_chain: auditing_security_principal.user_id_chain,
57
+ changes: request.to_attributes( only: request.assigned_attributes ),
58
+ action: audit_request_action( request, action )
57
59
 
58
- result = send method, params, request_class do |request|
59
- transaction.action = audit_request_action( request, action )
60
- transaction.changes = request.to_attributes
61
-
62
- yield request, transaction
63
- end
60
+ result = yield transaction if block_given?
61
+ result = Services::Result.coerce( result, request: request )
64
62
 
65
63
  if result.valid?
66
- transaction.append_entity result.entity if result.entity
64
+ if result.entity
65
+ transaction.append_entity result.entity
66
+ elsif request.respond_to?( :id ) && defined? entity_class
67
+ transaction.append_entity [ entity_class, request.id ]
68
+ end
67
69
  auditing_service.commit( transaction )
68
70
  end
69
71
 
@@ -70,12 +70,13 @@ module Shamu
70
70
  def entity_path_name( entity )
71
71
  case entity
72
72
  when String then entity.sub( /Entity$/, "" )
73
- when Class then Class.model_name.name
73
+ when Class then entity.model_name.name
74
74
  else fail "Don't know how to compose #{ entity }"
75
75
  end
76
76
  end
77
77
 
78
78
  def build_composed_entity_path( name, id )
79
+ id = id.to_model_id if id.respond_to?( :to_model_id )
79
80
  "#{ name }[#{ id }]"
80
81
  end
81
82
 
@@ -21,20 +21,37 @@ module Shamu
21
21
 
22
22
  end
23
23
 
24
+ # (see Support.event_channel)
25
+ def event_channel
26
+ self.class.event_channel
27
+ end
28
+
24
29
  private
25
30
 
26
31
  # @!visibility public
27
32
  #
28
33
  # Publish the given `message` to the {#events_service}.
29
34
  #
30
- # @param [Events::Message] message the custom event specific message to
35
+ # @param [Events::Message, Symbol] message the custom event specific message to
31
36
  # publish.
32
37
  # @param [String] channel to publish to.
38
+ # @param [Hash] message_attrs arguments to use when creating an
39
+ # instance of `message`.
40
+ #
41
+ # If `message` is a symbol, looks for a {Message} class in
42
+ # {ServiceNamespace}::{OptionalServiceDomain}Events::{name.caemlize}.
33
43
  # @return [void]
34
- def event!( message, channel: event_channel )
44
+ def event!( message, channel: event_channel, **message_attrs )
45
+ if message.is_a?( Symbol )
46
+ message = self.class
47
+ .event_message_namespace
48
+ .const_get( message.to_s.camelize )
49
+ .new( message_attrs )
50
+ end
35
51
  events_service.publish channel, message
36
52
  end
37
53
 
54
+ class_methods do
38
55
  # @!visibility public
39
56
  #
40
57
  # The channel to {#publish_event publish events} to. Defaults to the
@@ -47,7 +64,7 @@ module Shamu
47
64
  # @return [String] the name of the channel.
48
65
  def event_channel
49
66
  @event_channel ||= begin
50
- base_name = self.class.name || "Events"
67
+ base_name = name || "Events"
51
68
  parts = base_name.split( "::" )
52
69
  parts[-1].sub!( /Service$/, "" )
53
70
  parts.pop if parts[-1] == parts[-2] || ( parts.length > 1 && parts[-1].blank? )
@@ -55,6 +72,28 @@ module Shamu
55
72
  end
56
73
  end
57
74
 
75
+ # The module that holds the per-message event classes for the service.
76
+ # @return [Module]
77
+ def event_message_namespace
78
+ @event_message_namespace ||=
79
+ begin
80
+ namespace = name.deconstantize
81
+ return unless namespace.present?
82
+
83
+ namespace = namespace.constantize
84
+ domain = name.demodulize.sub( /Service/, "" ).singularize
85
+
86
+ # Must use exceptions instead of const_defined? so that rails has
87
+ # a change to autoload the constant.
88
+ begin
89
+ namespace.const_get( "#{ domain }Events" )
90
+ rescue NameError
91
+ namespace.const_get( "Events" )
92
+ end
93
+ end
94
+ end
95
+ end
96
+
58
97
  end
59
98
  end
60
- end
99
+ end
@@ -14,22 +14,22 @@ module Shamu
14
14
  #
15
15
  # # Define finder methods #find, #list and #lookup using the given
16
16
  # # default scope.
17
- # finders Models::User.active
17
+ # define_finders Models::User.active
18
18
  #
19
19
  # # Define change methods
20
- # create
21
- # update
20
+ # define_create
21
+ # define_update
22
22
  #
23
23
  # # Common update/change behavior for #create and #update
24
- # change do |request, model|
24
+ # define_change do |request, model|
25
25
  # model.last_updated_at = Time.now
26
26
  # end
27
27
  #
28
28
  # # Standard destroy method
29
- # destroy
29
+ # define_destroy
30
30
  #
31
31
  # # Build the entity class from the given record.
32
- # build_entities do |records|
32
+ # define_build_entities do |records|
33
33
  # records.map do |record|
34
34
  # parent = lookup_association( record.parent_id, self ) do
35
35
  # records.pluck( :parent_id )
@@ -123,7 +123,7 @@ module Shamu
123
123
  send method
124
124
  end
125
125
 
126
- build_entities( &block )
126
+ define_build_entities( &block )
127
127
  end
128
128
 
129
129
  # @return [Class] the {Entities::Entity} class that the service will
@@ -138,49 +138,60 @@ module Shamu
138
138
  resource_not_configured
139
139
  end
140
140
 
141
+ # Define all basic CRUD methods without any customization.
142
+ def define_crud
143
+ define_create
144
+ define_update
145
+ define_destroy
146
+ define_finders
147
+ end
148
+
141
149
  # Define a `#create` method on the service that takes a single {Request}
142
150
  # parameter.
143
151
  #
144
- # See {.apply_changes} for details.
145
- # @yield (see .apply_changes)
146
- # @yieldparam (see .apply_changes)
152
+ # @yield ( request, record, *args )
153
+ # @yieldparam [Services::Request] request object.
154
+ # @yieldparam [ActiveRecord::Base] record.
155
+ # @yieldparam [Array] args any additional arguments injected by an
156
+ # overridden {#with_request} method.
147
157
  # @return [void]
148
- def create( &block )
158
+ def define_create( &block )
149
159
  define_method :create do |params = nil|
150
- with_request params, request_class( :create ) do |request|
151
- authorize! :create, entity_class, request
152
-
160
+ with_request params, request_class( :create ) do |request, *args|
153
161
  record = request.apply_to( model_class.new )
154
- if block
155
- yield( request, record )
156
- elsif respond_to? :apply_changes
157
- apply_changes( request, record )
162
+
163
+ if block_given?
164
+ result = instance_exec record, request, *args, &block
165
+ next result if result.is_a?( Services::Result )
158
166
  end
159
167
 
168
+ authorize! :create, build_entity( record ), request
169
+
160
170
  next record unless record.save
161
171
  build_entity record
162
172
  end
163
173
  end
164
174
  end
165
175
 
166
- # rubocop:disable Metrics/MethodLength
167
-
168
176
  # Define an change `method` on the service that takes the id of the
169
177
  # resource to modify and a corresponding {Request} parameter.
170
178
  #
171
- # See {.apply_changes} for details.
172
- # @yield (see .apply_changes)
173
- # @yieldparam (see .apply_changes)
179
+ # @yield ( request, record, *args )
180
+ # @yieldparam [Services::Request] request object.
181
+ # @yieldparam [ActiveRecord::Base] record.
182
+ # @yieldparam [Array] args any additional arguments injected by an
183
+ # overridden {#with_request} method.
174
184
  # @return [Result] the result of the request.
175
185
  # @return [void]
176
- def change( method = :update, &block ) # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
186
+ def define_change( method, default_scope = model_class, &block ) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/LineLength
177
187
  define_method method do |id, params = nil|
178
188
  klass = request_class( method )
179
189
 
180
190
  params, id = id, id[ :id ] if !params && !id.respond_to?( :to_model_id )
191
+ params[ :id ] ||= id if params
181
192
 
182
- with_partial_request params, klass do |request|
183
- record = model_class.find( id.to_model_id || request.id )
193
+ with_partial_request params, klass do |request, *args|
194
+ record = default_scope.find( id.to_model_id || request.id )
184
195
  entity = build_entity( record )
185
196
 
186
197
  backfill_attributes = entity.to_attributes( only: request.unassigned_attributes )
@@ -190,11 +201,9 @@ module Shamu
190
201
  authorize! method, entity, request
191
202
 
192
203
  request.apply_to( record )
193
-
194
- if block
195
- yield( request, record )
196
- elsif respond_to? :apply_changes
197
- apply_changes( request, record )
204
+ if block_given?
205
+ result = instance_exec record, request, *args, &block
206
+ next result if result.is_a?( Services::Result )
198
207
  end
199
208
 
200
209
  next record unless record.save
@@ -203,69 +212,49 @@ module Shamu
203
212
  end
204
213
  end
205
214
 
206
- # rubocop:enabled Metrics/MethodLength
207
-
208
-
209
- # Define an `update` method on the service that takes the id of the
210
- # resource to update and a {Request} parameter. After applying the
211
- # changes the record is persisted and the updated entity result is
212
- # returned.
213
- #
214
- # See {.apply_changes} for details.
215
- # @yield (see .apply_changes)
216
- # @yieldparam (see .apply_changes)
217
- # @return [void]
218
- def update( &block )
219
- change :update, &block
215
+ # Defines an #update method. See {#define_change} for details.
216
+ def define_update( default_scope = model_class, &block )
217
+ define_change :update, default_scope, &block
220
218
  end
221
219
 
222
220
  # Define a `destroy( id )` method that takes an {Entities::Entity} {Entities::Entity#id}
223
221
  # and destroys the resource.
224
222
  #
223
+ # @yield ( request, record, *args )
224
+ # @yieldparam [Services::Request] request object.
225
+ # @yieldparam [ActiveRecord::Base] record.
226
+ # @yieldparam [Array] args any additional arguments injected by an
227
+ # overridden {#with_request} method.
225
228
  # @param [ActiveRecord::Relation] default_scope to use when finding
226
229
  # records.
227
230
  # @return [void]
228
- def destroy( default_scope = model_class.all )
231
+ def define_destroy( default_scope = model_class, &block )
229
232
  define_method :destroy do |params|
230
233
  klass = request_class( :destroy )
231
234
 
232
235
  params = { id: params } if params.respond_to?( :to_model_id )
233
236
 
234
- with_request params, klass do |request|
237
+ with_request params, klass do |request, *args|
235
238
  record = default_scope.find( request.id )
236
239
  authorize! :destroy, build_entity( record )
240
+
241
+ instance_exec record, request, *args, &block if block_given?
237
242
  next record unless record.destroy
238
243
  end
239
244
  end
240
245
  end
241
246
 
242
- # Define a private method `apply_changes` on the service used by the
243
- # {.create} and {.change} defined methods to apply changes in a
244
- # {Request} to the model.
245
- #
246
- # @yield ( request, record ) a block that applies changes in the
247
- # `request` to the `record`.
248
- # @yieldparam [Request] request the {Request} containing all the changes
249
- # that should be applied to the `record`.
250
- # @yieldparam [ActiveRecord::Base] record the record to be updated.
251
- # @yieldreturn [void]
252
- # @return [void]
253
- def apply_changes( &block )
254
- define_method :apply_changes, &block
255
- private :apply_changes
256
- end
257
-
258
247
  # Define the standard finder methods {.find}, {.lookup} and {.list}.
259
248
  #
260
249
  # @param [ActiveRecord::Relation] default_scope to use when finding
261
250
  # records.
262
251
  # @return [void]
263
- def finders( default_scope = model_class.all, only: nil, except: nil )
252
+ def define_finders( default_scope = model_class.all, only: nil, except: nil )
264
253
  methods = Array( only || [ :find, :lookup, :list ] )
265
254
  methods -= Array( except ) if except
266
255
 
267
256
  methods.each do |method|
268
- send method, default_scope
257
+ send :"define_#{ method }", default_scope
269
258
  end
270
259
  end
271
260
 
@@ -278,7 +267,7 @@ module Shamu
278
267
  # @yield (id)
279
268
  # @yieldreturn (ActiveRecord::Base) the found record.
280
269
  # @return [void]
281
- def find( default_scope = model_class.all, &block )
270
+ def define_find( default_scope = model_class.all, &block )
282
271
  if block_given?
283
272
  define_method :find do |id|
284
273
  wrap_not_found do
@@ -305,7 +294,7 @@ module Shamu
305
294
  # @yieldreturn [ActiveRecord::Relation] records for ids found in the
306
295
  # underlying resource.
307
296
  # @return [void]
308
- def lookup( default_scope = model_class.all, &block )
297
+ def define_lookup( default_scope = model_class.all, &block )
309
298
  define_method :lookup do |*ids|
310
299
  cached_lookup( ids ) do |uncached_ids|
311
300
  records = block_given? ? yield( uncached_ids ) : default_scope.where( id: uncached_ids )
@@ -325,7 +314,7 @@ module Shamu
325
314
  # @yieldparam [ListScope] scope to apply.
326
315
  # @yieldreturn [ActiveRecord::Relation] records matching the given scope.
327
316
  # @return [void]
328
- def list( default_scope = model_class.all, &block )
317
+ def define_list( default_scope = model_class.all, &block )
329
318
  define_method :list do |params = nil|
330
319
  list_scope = Entities::ListScope.for( entity_class ).coerce( params )
331
320
  authorize! :list, entity_class, list_scope
@@ -351,7 +340,7 @@ module Shamu
351
340
  # entities.
352
341
  # @yieldreturn [Array<Entities::Entity>] the projected entities.
353
342
  # @return [void]
354
- def build_entities( &block )
343
+ def define_build_entities( &block )
355
344
  if block_given?
356
345
  define_method :build_entities, &block
357
346
  else
@@ -374,7 +363,7 @@ module Shamu
374
363
 
375
364
  def inferred_resource_name
376
365
  inferred = name || "Resource"
377
- inferred.split( "::" ).last.sub( /Service/, "" )
366
+ inferred.split( "::" ).last.sub( /Service/, "" ).singularize
378
367
  end
379
368
 
380
369
  def inferred_namespace
@@ -25,7 +25,6 @@ module Shamu
25
25
  class Request
26
26
  include Shamu::Attributes
27
27
  include Shamu::Attributes::Assignment
28
- include Shamu::Attributes::FluidAssignment
29
28
  include Shamu::Attributes::Validation
30
29
 
31
30
  # Applies the attributes of the request to the given model. Only handles
@@ -53,6 +52,37 @@ module Shamu
53
52
  end
54
53
  end
55
54
 
55
+ # Execute block if the request is satisfied by the service successfully.
56
+ def on_success( &block )
57
+ @on_success_callbacks ||= []
58
+ @on_success_callbacks << block
59
+ end
60
+
61
+ # Execute block if the request is not satisfied by the service.
62
+ def on_fail( &block )
63
+ @on_fail_callbacks ||= []
64
+ @on_fail_callbacks << block
65
+ end
66
+
67
+ # Execute block when the service is done processing the request.
68
+ def on_complete( &block )
69
+ @on_complete_callbacks ||= []
70
+ @on_complete_callbacks << block
71
+ end
72
+
73
+ # Run any {#on_success} or #{on_fail} callbacks.
74
+ # @param [Boolean] success true if the request was completed
75
+ # successfully.
76
+ def run_callbacks( success )
77
+ if success
78
+ @on_success_callbacks && @on_success_callbacks.each( &:call )
79
+ else
80
+ @on_fail_callbacks && @on_fail_callbacks.each( &:call )
81
+ end
82
+
83
+ @on_fail_callbacks && @on_fail_callbacks.each( &:call )
84
+ end
85
+
56
86
  class << self
57
87
  # Coerces a hash or params object to a proper {Request} object.
58
88
  # @param [Object] params to be coerced.
@@ -70,10 +70,10 @@ module Shamu
70
70
  # end
71
71
  # end
72
72
  def with_request( params, request_class, &block )
73
- with_partial_request params, request_class do |request|
73
+ with_partial_request params, request_class do |request, *args|
74
74
  next unless request.valid?
75
75
 
76
- yield request
76
+ yield request, *args
77
77
  end
78
78
  end
79
79
 
@@ -90,15 +90,10 @@ module Shamu
90
90
  request = request_class.coerce( params )
91
91
  sources = yield( request )
92
92
 
93
- # Make sure the request captures errors even if the block doesn't
94
- # check
95
- request.valid?
93
+ result = Result.coerce( sources, request: request )
94
+ request.run_callbacks( result.valid? )
96
95
 
97
- if sources.is_a?( Result )
98
- sources
99
- else
100
- result( *Array.wrap( sources ), request: request )
101
- end
96
+ result
102
97
  end
103
98
 
104
99
  # Static methods added to {RequestSupport}
@@ -48,7 +48,7 @@ module Shamu
48
48
  # the first {Request} object found in the `values`.
49
49
  # @param [Entities::Entity] entity submitted to the service. If :not_set,
50
50
  # uses the first {Entity} object found in the `values`.
51
- def initialize( *values, request: :not_set, entity: :not_set )
51
+ def initialize( *values, request: :not_set, entity: :not_set ) # rubocop:disable Metrics/LineLength, Metrics/MethodLength, Metrics/PerceivedComplexity
52
52
  @values = values
53
53
  @value = values.first
54
54
 
@@ -60,6 +60,10 @@ module Shamu
60
60
  end
61
61
 
62
62
  unless request == :not_set
63
+ # Make sure the request captures errors even if the block doesn't
64
+ # check
65
+ request && request.valid?
66
+
63
67
  @request = request
64
68
  append_error_source request
65
69
  end
@@ -93,8 +97,16 @@ module Shamu
93
97
  self
94
98
  end
95
99
 
96
- private
100
+ # @return [Result] the value coerced to a {Result}.
101
+ def self.coerce( value, **args )
102
+ if value.is_a?( Result )
103
+ value
104
+ else
105
+ Result.new( *Array.wrap( value ), **args )
106
+ end
107
+ end
97
108
 
109
+ private
98
110
 
99
111
  def append_error_source( source )
100
112
  return unless source.respond_to?( :errors )
@@ -103,6 +115,7 @@ module Shamu
103
115
  errors.add attr, message unless errors[attr].include? message
104
116
  end
105
117
  end
118
+
106
119
  end
107
120
  end
108
121
  end
@@ -340,15 +340,6 @@ module Shamu
340
340
  end
341
341
  end
342
342
 
343
- # @!visibility public
344
- #
345
- # @overload result( *values, request: nil, entity: nil )
346
- # @param (see Result#initialize)
347
- # @return [Result]
348
- def result( *args )
349
- Result.new( *args )
350
- end
351
-
352
343
  # @!visibility public
353
344
  #
354
345
  # Return an error {#result} from a service request.
data/lib/shamu/version.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Shamu
4
4
  # The primary version number
5
- VERSION_NUMBER = "0.0.17"
5
+ VERSION_NUMBER = "0.0.18"
6
6
 
7
7
  # Version suffix such as 'beta' or 'alpha'
8
8
  VERSION_SUFFIX = ""
@@ -5,6 +5,7 @@ module AuditingSupportSpec
5
5
  include Shamu::Auditing::Support
6
6
 
7
7
  public :audit_request
8
+ public :with_request
8
9
  end
9
10
 
10
11
  class Change < Shamu::Services::Request
@@ -14,19 +15,22 @@ end
14
15
 
15
16
  describe Shamu::Auditing::Support do
16
17
  hunt( :service, Shamu::Auditing::AuditingService )
18
+
17
19
  let( :example_service ) { scorpion.new AuditingSupportSpec::ExampleService }
20
+ let( :request ) { AuditingSupportSpec::Change.new name: "Penguin" }
18
21
 
19
22
  it "audits the request on success" do
20
23
  expect( service ).to receive( :commit )
21
24
 
22
- example_service.audit_request( { name: "Penguin" }, AuditingSupportSpec::Change ) do |request, transaction|
25
+ example_service.audit_request( request ) do |transaction|
23
26
  end
24
27
  end
25
28
 
26
29
  it "skips the request on failure" do
27
30
  expect( service ).not_to receive( :commit )
31
+ request.name = nil
28
32
 
29
- example_service.audit_request( {}, AuditingSupportSpec::Change ) do |request, transaction|
33
+ example_service.audit_request( request ) do |transaction|
30
34
  end
31
35
  end
32
36
 
@@ -35,7 +39,16 @@ describe Shamu::Auditing::Support do
35
39
  expect( transaction.action ).to eq "change"
36
40
  end
37
41
 
38
- example_service.audit_request( { name: "Penguin" }, AuditingSupportSpec::Change ) do |request, transaction|
42
+ example_service.audit_request( request ) do |request|
39
43
  end
40
44
  end
41
- end
45
+
46
+ it "wraps with_request" do
47
+ expect( service ).to receive( :commit )
48
+
49
+ example_service.with_request( { name: "Example" }, AuditingSupportSpec::Change ) do |request, transaction|
50
+ expect( request ).to be_a AuditingSupportSpec::Change
51
+ expect( transaction ).to be_a Shamu::Auditing::Transaction
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,19 @@
1
1
  require "spec_helper"
2
2
 
3
+ module EventsSupportSpec
4
+ class Service < Shamu::Services::Service
5
+ include Shamu::Events::Support
6
+
7
+ public :event!
8
+ end
9
+
10
+ module Events
11
+ class Boom < Shamu::Events::Message
12
+ attribute :name
13
+ end
14
+ end
15
+ end
16
+
3
17
  describe Shamu::Events::Support do
4
18
  describe "#event_channel" do
5
19
  {
@@ -27,18 +41,16 @@ describe Shamu::Events::Support do
27
41
  describe "event!" do
28
42
  hunt( :events_service, Shamu::Events::EventsService )
29
43
 
30
- let( :klass ) do
31
- Class.new( Shamu::Services::Service ) do
32
- include Shamu::Events::Support
33
-
34
- public :event!
35
- end
36
- end
37
- let( :service ) { scorpion.new klass }
44
+ let( :service ) { scorpion.new EventsSupportSpec::Service }
38
45
 
39
46
  it "publishes message to events_service" do
40
47
  expect( events_service ).to receive( :publish )
41
48
  service.event! Shamu::Events::Message.new
42
49
  end
50
+
51
+ it "creates message from attributes" do
52
+ expect( events_service ).to receive( :publish )
53
+ service.event! :boom, name: "Me"
54
+ end
43
55
  end
44
- end
56
+ end
@@ -33,10 +33,8 @@ module ActiveRecordCrudSpec
33
33
  include Shamu::Services::ActiveRecordCrud
34
34
 
35
35
  resource FavoriteEntity, ActiveRecordSpec::Favorite
36
- create
37
- change
38
- finders
39
- destroy
36
+ define_crud
37
+
40
38
  end
41
39
 
42
40
  class FavoriteListScope < Shamu::Entities::ListScope
@@ -46,6 +44,7 @@ end
46
44
 
47
45
  describe Shamu::Services::ActiveRecordCrud do
48
46
  use_active_record
47
+
49
48
  before( :all ) { Shamu::ToModelIdExtension.extend! }
50
49
 
51
50
  let( :klass ) { ActiveRecordCrudSpec::Service }
@@ -125,15 +124,6 @@ describe Shamu::Services::ActiveRecordCrud do
125
124
  service.create request
126
125
  end
127
126
 
128
- it "calls apply_changes if present" do
129
- expect( service ).to receive( :apply_changes )
130
- .with(
131
- request,
132
- kind_of( ActiveRecord::Base )
133
- )
134
- service.create( request )
135
- end
136
-
137
127
  it "returns a Result" do
138
128
  expect( service.create( request ) ).to be_a Shamu::Services::Result
139
129
  end
@@ -148,24 +138,27 @@ describe Shamu::Services::ActiveRecordCrud do
148
138
  it "yields if block given" do
149
139
  expect do |b|
150
140
  yield_klass = Class.new( klass ) do
151
- create( &b )
141
+ define_create( &b )
152
142
  end
153
143
 
154
144
  scorpion.new( yield_klass ).create( request )
155
145
  end.to yield_with_args(
156
- request,
157
- kind_of( ActiveRecord::Base )
146
+ kind_of( ActiveRecord::Base ),
147
+ request
158
148
  )
159
149
  end
160
150
 
161
- it "does not call apply_changes if block given" do
151
+ it "short-circuits if block yields a Services::Result" do
162
152
  yield_klass = Class.new( klass ) do
163
- create { |_, _| }
153
+ define_create do
154
+ Shamu::Services::Result.new
155
+ end
164
156
  end
165
157
 
166
158
  service = scorpion.new( yield_klass )
167
- expect( service ).not_to receive :apply_changes
168
- service.create
159
+
160
+ expect( service ).not_to receive( :build_entity )
161
+ service.create request
169
162
  end
170
163
 
171
164
  it "calls #authorize!" do
@@ -198,37 +191,34 @@ describe Shamu::Services::ActiveRecordCrud do
198
191
  service.update entity, request
199
192
  end
200
193
 
201
- it "calls apply_changes if present" do
202
- expect( service ).to receive( :apply_changes )
203
- .with(
204
- kind_of( Shamu::Services::Request ),
205
- kind_of( ::ActiveRecord::Base )
206
- )
207
- service.create( request )
208
- end
209
-
210
194
  it "yields if block given" do
211
195
  entity = service.create.entity
212
196
 
213
197
  expect do |b|
214
198
  yield_klass = Class.new( klass ) do
215
- change( :update, &b )
199
+ define_change( :update, &b )
216
200
  end
217
201
 
218
202
  scorpion.new( yield_klass ).update entity.id, request
219
- end.to yield_with_args( request, kind_of( ::ActiveRecord::Base ) )
203
+ end.to yield_with_args( kind_of( ::ActiveRecord::Base ), request )
220
204
  end
221
205
 
222
- it "does not call apply_changes if block given" do
223
- entity = service.create.entity
206
+ it "short-circuits if block yields a Services::Result" do
207
+ entity
208
+ record = service.class.model_class.all.first
209
+ records = [ record ]
210
+
211
+ expect( records ).to receive( :find ).and_return record
212
+ expect( record ).not_to receive( :save )
224
213
 
225
214
  yield_klass = Class.new( klass ) do
226
- change( :update ) { |_, _| }
215
+ define_update records do
216
+ Shamu::Services::Result.new
217
+ end
227
218
  end
228
219
 
229
220
  service = scorpion.new( yield_klass )
230
- expect( service ).not_to receive :apply_changes
231
- service.update entity.id
221
+ service.update entity.id, request
232
222
  end
233
223
 
234
224
  it "calls #authorize!" do
@@ -244,19 +234,6 @@ describe Shamu::Services::ActiveRecordCrud do
244
234
  end
245
235
  end
246
236
 
247
- describe ".apply_changes" do
248
- it "defines an apply_changes method from the block" do
249
- klass = Class.new( Shamu::Services::Service ) do
250
- include Shamu::Services::ActiveRecordCrud
251
-
252
- apply_changes do |record, request|
253
- end
254
- end
255
-
256
- expect( klass.new.respond_to?( :apply_changes, true ) ).to be_truthy
257
- end
258
- end
259
-
260
237
  describe ".finders" do
261
238
  it "builds #lookup" do
262
239
  expect( service ).to respond_to :lookup
@@ -279,7 +256,7 @@ describe Shamu::Services::ActiveRecordCrud do
279
256
  end
280
257
 
281
258
  it "excludes unwanted methods" do
282
- klass.finders except: :list
259
+ klass.define_finders except: :list
283
260
 
284
261
  expect( klass.new ).to respond_to :find
285
262
  expect( klass.new ).to respond_to :lookup
@@ -287,7 +264,7 @@ describe Shamu::Services::ActiveRecordCrud do
287
264
  end
288
265
 
289
266
  it "includes only specific methods" do
290
- klass.finders only: :list
267
+ klass.define_finders only: :list
291
268
 
292
269
  expect( klass.new ).not_to respond_to :find
293
270
  expect( klass.new ).not_to respond_to :lookup
@@ -307,7 +284,7 @@ describe Shamu::Services::ActiveRecordCrud do
307
284
  it "yields to block if block given" do
308
285
  find_klass = Class.new( klass )
309
286
  expect do |b|
310
- find_klass.find do |_|
287
+ find_klass.define_find do |_|
311
288
  b.to_proc.call
312
289
  ActiveRecordSpec::Favorite.all.first
313
290
  end
@@ -353,7 +330,7 @@ describe Shamu::Services::ActiveRecordCrud do
353
330
  it "yields to block if given?" do
354
331
  expect do |b|
355
332
  yield_klass = Class.new( klass ) do
356
- lookup( &b )
333
+ define_lookup( &b )
357
334
  end
358
335
 
359
336
  scorpion.new( yield_klass ).lookup entity.id
@@ -392,7 +369,7 @@ describe Shamu::Services::ActiveRecordCrud do
392
369
  it "yields if block given" do
393
370
  expect do |b|
394
371
  yield_klass = Class.new( klass ) do
395
- list( &b )
372
+ define_list( &b )
396
373
  end
397
374
 
398
375
  scorpion.new( yield_klass ).list
@@ -438,6 +415,22 @@ describe Shamu::Services::ActiveRecordCrud do
438
415
  end.to change( ActiveRecordSpec::Favorite, :count ).by( -1 )
439
416
  end
440
417
 
418
+ it "short-circuits if block yields a Services::Result" do
419
+ record = klass.model_class.all.first
420
+ records = [ record ]
421
+
422
+ expect( records ).to receive( :find ).and_return record
423
+
424
+ yield_klass = Class.new( klass ) do
425
+ define_destroy records do
426
+ Shamu::Services::Result.new
427
+ end
428
+ end
429
+
430
+ service = scorpion.new( yield_klass )
431
+ service.destroy entity
432
+ end
433
+
441
434
  it "calls #authorize!" do
442
435
  expect( service ).to receive( :authorize! ).with(
443
436
  :destroy,
@@ -458,7 +451,7 @@ describe Shamu::Services::ActiveRecordCrud do
458
451
  let( :klass ) do
459
452
  ec = entity_class
460
453
  Class.new( super() ) do
461
- build_entities do |records|
454
+ define_build_entities do |records|
462
455
  records.map do |record|
463
456
  scorpion.fetch ec, { record: record }, {}
464
457
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shamu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Alexander
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-05 00:00:00.000000000 Z
11
+ date: 2017-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel