granite 0.8.0 → 0.8.1

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: eee58f357db73ca54fa35ec5a68a13081bd450a8
4
- data.tar.gz: 1042435a47b006d54caafc174552863a2024a52d
3
+ metadata.gz: f9bc00868502247ad725644cccc110d93845426e
4
+ data.tar.gz: '09710e9fbf2c004ef8d369869e3479f92377b51f'
5
5
  SHA512:
6
- metadata.gz: 59143c029f08dae76509be73e06b653eedbfb29b98cf8b79ffebcd0eb0183fd63fe9312a0fa51c8d7806097e5a70d7168e87e116c45ce7e16af3211886b03ed4
7
- data.tar.gz: f3d6579fbd80170a55a3fef47e90db59236087a0ecd4b14c1f54f145553b38bc118efd7f24a535b5d6225143511db18b26f82187bcebb3f384063c03bdc997f2
6
+ metadata.gz: 29d0c0a27c84fb772a96af9b1fd110d0ea1453b0d47252c803ba29f32201c6cd50a9665da4137ba8349ec7c0cd01c9dddca7e408d8054daec694adfe8442d931
7
+ data.tar.gz: 6c7d51a1f438c7d1958d261f5f7e51be1aa38adf161877ef96500b3a5d19069907f7d615f0335ca63f898a5b06268afeb40f72f3bf040b610e41abebb683f6ef
@@ -0,0 +1,39 @@
1
+ module Granite
2
+ class Action
3
+ module ExceptionsHandling
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :_exception_handlers, instance_writer: false
8
+ self._exception_handlers = {}
9
+
10
+ protected :_exception_handlers
11
+ end
12
+
13
+ module ClassMethods
14
+ # Register default handler for exceptions thrown inside execute_perform! and after_commit methods.
15
+ # @param klass Exception class, could be parent class too [Class]
16
+ # @param block [Block<Exception>] with default behavior for handling specified
17
+ # type exceptions. First block argument is raised exception instance.
18
+ #
19
+ # @return [Hash<Class, Proc>] Registered handlers
20
+ def handle_exception(klass, &block)
21
+ self._exception_handlers = _exception_handlers.merge(klass => block)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def handled_exceptions
28
+ _exception_handlers.keys
29
+ end
30
+
31
+ def handle_exception(e)
32
+ klass = e.class.ancestors.detect do |ancestor|
33
+ ancestor <= Exception && _exception_handlers[ancestor]
34
+ end
35
+ instance_exec(e, &_exception_handlers[klass]) if klass
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,4 @@
1
+ require 'granite/action/exceptions_handling'
1
2
  require 'granite/action/transaction'
2
3
  require 'granite/action/error'
3
4
 
@@ -17,28 +18,14 @@ module Granite
17
18
  module Performing
18
19
  extend ActiveSupport::Concern
19
20
 
21
+ include ExceptionsHandling
20
22
  include Transaction
21
23
 
22
24
  included do
23
- class_attribute :_exception_handlers, instance_writer: false
24
- self._exception_handlers = {}
25
-
26
- protected :_exception_handlers
27
-
28
25
  define_callbacks :execute_perform
29
26
  end
30
27
 
31
28
  module ClassMethods
32
- # Register default handler for exceptions thrown inside execute_perform! method.
33
- # @param klass Exception class, could be parent class too [Class]
34
- # @param block [Block<Exception>] with default behavior for handling specified
35
- # type exceptions. First block argument is raised exception instance.
36
- #
37
- # @return [Hash<Class, Proc>] Registered handlers
38
- def handle_exception(klass, &block)
39
- self._exception_handlers = _exception_handlers.merge(klass => block)
40
- end
41
-
42
29
  def perform(*)
43
30
  fail 'Perform block declaration was removed! Please declare `private def execute_perform!(*)` method'
44
31
  end
@@ -54,7 +41,7 @@ module Granite
54
41
  # using `:on`)
55
42
  # @return [Object] result of execute_perform! method execution or false in case of errors
56
43
  def perform(context: nil, **options)
57
- transactional do
44
+ transaction do
58
45
  valid?(context) && perform_action(options)
59
46
  end
60
47
  end
@@ -72,7 +59,7 @@ module Granite
72
59
  # @raise [Granite::Action::ValidationError] Action or associated objects are invalid
73
60
  # @raise [NotImplementedError] execute_perform! method was not defined yet
74
61
  def perform!(context: nil, **options)
75
- transactional do
62
+ transaction do
76
63
  validate!(context)
77
64
  perform_action!(**options)
78
65
  end
@@ -88,7 +75,7 @@ module Granite
88
75
  # @raise [NotImplementedError] execute_perform! method was not defined yet
89
76
  def try_perform!(context: nil, **options)
90
77
  return unless satisfy_preconditions?
91
- transactional do
78
+ transaction do
92
79
  validate!(context)
93
80
  perform_action!(**options)
94
81
  end
@@ -108,7 +95,7 @@ module Granite
108
95
  result = run_callbacks(:execute_perform) { execute_perform!(options) }
109
96
  @_action_performed = true
110
97
  result || true
111
- rescue *_exception_handlers.keys => e
98
+ rescue *handled_exceptions => e
112
99
  handle_exception(e)
113
100
  raise_validation_error(e) if raise_errors
114
101
  raise Rollback
@@ -121,13 +108,6 @@ module Granite
121
108
  def execute_perform!(**_options)
122
109
  fail NotImplementedError, "BA perform body MUST be defined for #{self}"
123
110
  end
124
-
125
- def handle_exception(e)
126
- klass = e.class.ancestors.detect do |ancestor|
127
- ancestor <= Exception && _exception_handlers[ancestor]
128
- end
129
- instance_exec(e, &_exception_handlers[klass]) if klass
130
- end
131
111
  end
132
112
  end
133
113
  end
@@ -1,40 +1,44 @@
1
+ require 'granite/action/transaction_manager'
2
+
1
3
  module Granite
2
4
  class Action
3
- class Rollback < defined?(ActiveRecord) ? ActiveRecord::Rollback : StandardError
4
- end
5
-
6
5
  module Transaction
7
6
  extend ActiveSupport::Concern
8
7
 
9
- private
10
-
11
- def transactional(&block)
12
- if transactional?
13
- yield
14
- else
15
- @_transactional = true
16
- result = transaction(&block) || false
17
- @_transactional = nil
18
- result
19
- end
8
+ included do
9
+ define_callbacks :commit
20
10
  end
21
11
 
22
- def transactional?
23
- # Fuck the police!
24
- !(!@_transactional)
12
+ module ClassMethods
13
+ delegate :transaction, to: :'Granite::Action::TransactionManager'
14
+
15
+ private
16
+
17
+ # Defines a callback which will be triggered right after transaction committed
18
+ # Uses the same arguments as `ActiveSupport::Callbacks.set_callback` except for the first two
19
+ #
20
+ def after_commit(*args, &block)
21
+ set_callback :commit, :after, *args, &block
22
+ end
25
23
  end
26
24
 
27
- def transaction(&block)
28
- if defined?(ActiveRecord::Base)
29
- ActiveRecord::Base.transaction(&block)
30
- else
25
+ def run_callbacks(event)
26
+ if event.to_s == 'commit'
31
27
  begin
32
- yield
33
- rescue Granite::Action::Rollback
34
- false
28
+ super event
29
+ rescue *handled_exceptions => e
30
+ handle_exception(e)
35
31
  end
32
+ else
33
+ super event
36
34
  end
37
35
  end
36
+
37
+ private
38
+
39
+ def transaction(&block)
40
+ self.class.transaction(trigger_callbacks_for: self, &block)
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -0,0 +1,86 @@
1
+ module Granite
2
+ class Action
3
+ class Rollback < defined?(ActiveRecord) ? ActiveRecord::Rollback : StandardError
4
+ end
5
+
6
+ module TransactionManager
7
+ class << self
8
+ # Runs a block in a transaction
9
+ # It will open a new transaction or append a block to the current one if it exists
10
+ #
11
+ # @param [Object] trigger_callbacks_for - object which will receive `run_callbacks(:commit)` after transaction commited
12
+ # @return [Object] result of a block
13
+ def transaction(trigger_callbacks_for: nil, &block)
14
+ (callback_listeners << trigger_callbacks_for) if trigger_callbacks_for
15
+
16
+ if in_a_transaction?
17
+ yield
18
+ else
19
+ wrap_in_transaction_with_callbacks(&block)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ IN_A_TRANSACTION_KEY = :granite_transaction_manager_in_a_transaction
26
+ CALLBACK_LISTENERS_KEY = :granite_transaction_manager_callback_listeners
27
+
28
+ def callback_listeners
29
+ Thread.current[CALLBACK_LISTENERS_KEY] ||= []
30
+ end
31
+
32
+ def in_a_transaction?
33
+ !!(Thread.current[IN_A_TRANSACTION_KEY])
34
+ end
35
+
36
+ def in_a_transaction=(value)
37
+ Thread.current[IN_A_TRANSACTION_KEY] = value
38
+ end
39
+
40
+ def wrap_in_transaction_with_callbacks(&block)
41
+ self.in_a_transaction = true
42
+
43
+ result = wrap_in_transaction(&block) || false
44
+
45
+ trigger_callbacks if result
46
+
47
+ result
48
+ ensure
49
+ callback_listeners.clear
50
+ self.in_a_transaction = nil
51
+ end
52
+
53
+ def wrap_in_transaction(&block)
54
+ if defined?(ActiveRecord::Base)
55
+ ActiveRecord::Base.transaction(&block)
56
+ else
57
+ begin
58
+ yield
59
+ rescue Granite::Action::Rollback
60
+ false
61
+ end
62
+ end
63
+ end
64
+
65
+ def trigger_callbacks
66
+ collected_errors = []
67
+
68
+ callback_listeners.reverse.each do |listener|
69
+ begin
70
+ listener.run_callbacks :commit
71
+ rescue StandardError => e
72
+ collected_errors << e
73
+ end
74
+ end
75
+
76
+ if collected_errors.any?
77
+ collected_errors[1..-1].each do |error|
78
+ ActiveData.config.logger.error "Unhandled error in callback: #{error.inspect}\n#{error.backtrace.join("\n")}"
79
+ end
80
+ fail collected_errors.first
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,3 +1,3 @@
1
1
  module Granite
2
- VERSION = '0.8.0'.freeze
2
+ VERSION = '0.8.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: granite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkadiy Zabazhanov & friends
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-15 00:00:00.000000000 Z
11
+ date: 2018-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -280,6 +280,7 @@ files:
280
280
  - lib/granite.rb
281
281
  - lib/granite/action.rb
282
282
  - lib/granite/action/error.rb
283
+ - lib/granite/action/exceptions_handling.rb
283
284
  - lib/granite/action/performer.rb
284
285
  - lib/granite/action/performing.rb
285
286
  - lib/granite/action/policies.rb
@@ -292,6 +293,7 @@ files:
292
293
  - lib/granite/action/projectors.rb
293
294
  - lib/granite/action/subject.rb
294
295
  - lib/granite/action/transaction.rb
296
+ - lib/granite/action/transaction_manager.rb
295
297
  - lib/granite/action/types.rb
296
298
  - lib/granite/action/types/collection.rb
297
299
  - lib/granite/base.rb