granite 0.8.1 → 0.8.2

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: f9bc00868502247ad725644cccc110d93845426e
4
- data.tar.gz: '09710e9fbf2c004ef8d369869e3479f92377b51f'
3
+ metadata.gz: 3792e5a0bab26cb24becc52bb82e89198a74e84f
4
+ data.tar.gz: 1c085cd86ae0ca9379cfd8d6708a24dea36a6454
5
5
  SHA512:
6
- metadata.gz: 29d0c0a27c84fb772a96af9b1fd110d0ea1453b0d47252c803ba29f32201c6cd50a9665da4137ba8349ec7c0cd01c9dddca7e408d8054daec694adfe8442d931
7
- data.tar.gz: 6c7d51a1f438c7d1958d261f5f7e51be1aa38adf161877ef96500b3a5d19069907f7d615f0335ca63f898a5b06268afeb40f72f3bf040b610e41abebb683f6ef
6
+ metadata.gz: b1afd8ebb16b30ac0a5142369cb7bcb5ac62ab9c1d11a2c5ec84b0a525a70b43b0181e51aed50003384baa4303c0eb466440216acf345d66a7cde594e594e6de
7
+ data.tar.gz: 8bd7ef7aff11fa0f9aaa444993c637cffe2ff7f2c8dfc1b39ec1680d5766a32f5d0bd40a3bfc6fe17f9020a08df40d1777ffff942ea6507e3ed68d40e6edbb26
@@ -23,6 +23,7 @@ require 'granite/dispatcher'
23
23
  require 'granite/action'
24
24
  require 'granite/projector'
25
25
  require 'granite/routing'
26
+ require 'granite/typecasters'
26
27
  require 'granite/rails' if defined?(::Rails)
27
28
 
28
29
  ActiveData.base_concern = Granite::Base
@@ -1,4 +1,3 @@
1
- require 'granite/action/exceptions_handling'
2
1
  require 'granite/action/transaction'
3
2
  require 'granite/action/error'
4
3
 
@@ -18,14 +17,28 @@ module Granite
18
17
  module Performing
19
18
  extend ActiveSupport::Concern
20
19
 
21
- include ExceptionsHandling
22
20
  include Transaction
23
21
 
24
22
  included do
23
+ class_attribute :_exception_handlers, instance_writer: false
24
+ self._exception_handlers = {}
25
+
26
+ protected :_exception_handlers
27
+
25
28
  define_callbacks :execute_perform
26
29
  end
27
30
 
28
31
  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
+
29
42
  def perform(*)
30
43
  fail 'Perform block declaration was removed! Please declare `private def execute_perform!(*)` method'
31
44
  end
@@ -41,7 +54,7 @@ module Granite
41
54
  # using `:on`)
42
55
  # @return [Object] result of execute_perform! method execution or false in case of errors
43
56
  def perform(context: nil, **options)
44
- transaction do
57
+ transactional do
45
58
  valid?(context) && perform_action(options)
46
59
  end
47
60
  end
@@ -59,7 +72,7 @@ module Granite
59
72
  # @raise [Granite::Action::ValidationError] Action or associated objects are invalid
60
73
  # @raise [NotImplementedError] execute_perform! method was not defined yet
61
74
  def perform!(context: nil, **options)
62
- transaction do
75
+ transactional do
63
76
  validate!(context)
64
77
  perform_action!(**options)
65
78
  end
@@ -75,7 +88,7 @@ module Granite
75
88
  # @raise [NotImplementedError] execute_perform! method was not defined yet
76
89
  def try_perform!(context: nil, **options)
77
90
  return unless satisfy_preconditions?
78
- transaction do
91
+ transactional do
79
92
  validate!(context)
80
93
  perform_action!(**options)
81
94
  end
@@ -95,7 +108,7 @@ module Granite
95
108
  result = run_callbacks(:execute_perform) { execute_perform!(options) }
96
109
  @_action_performed = true
97
110
  result || true
98
- rescue *handled_exceptions => e
111
+ rescue *_exception_handlers.keys => e
99
112
  handle_exception(e)
100
113
  raise_validation_error(e) if raise_errors
101
114
  raise Rollback
@@ -108,6 +121,13 @@ module Granite
108
121
  def execute_perform!(**_options)
109
122
  fail NotImplementedError, "BA perform body MUST be defined for #{self}"
110
123
  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
111
131
  end
112
132
  end
113
133
  end
@@ -1,43 +1,39 @@
1
- require 'granite/action/transaction_manager'
2
-
3
1
  module Granite
4
2
  class Action
3
+ class Rollback < defined?(ActiveRecord) ? ActiveRecord::Rollback : StandardError
4
+ end
5
+
5
6
  module Transaction
6
7
  extend ActiveSupport::Concern
7
8
 
8
- included do
9
- define_callbacks :commit
10
- end
11
-
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
23
- end
9
+ private
24
10
 
25
- def run_callbacks(event)
26
- if event.to_s == 'commit'
27
- begin
28
- super event
29
- rescue *handled_exceptions => e
30
- handle_exception(e)
31
- end
11
+ def transactional(&block)
12
+ if transactional?
13
+ yield
32
14
  else
33
- super event
15
+ @_transactional = true
16
+ result = transaction(&block) || false
17
+ @_transactional = nil
18
+ result
34
19
  end
35
20
  end
36
21
 
37
- private
22
+ def transactional?
23
+ # Fuck the police!
24
+ !(!@_transactional)
25
+ end
38
26
 
39
27
  def transaction(&block)
40
- self.class.transaction(trigger_callbacks_for: self, &block)
28
+ if defined?(ActiveRecord::Base)
29
+ ActiveRecord::Base.transaction(&block)
30
+ else
31
+ begin
32
+ yield
33
+ rescue Granite::Action::Rollback
34
+ false
35
+ end
36
+ end
41
37
  end
42
38
  end
43
39
  end
@@ -43,7 +43,7 @@ module Granite
43
43
  return unless reference.respond_to?(reader)
44
44
 
45
45
  variable_cache(:value) do
46
- normalize(enumerize(reference.public_send(reader)))
46
+ normalize(enumerize(typecast(defaultize(reference.public_send(reader)))))
47
47
  end
48
48
  end
49
49
 
@@ -60,6 +60,8 @@ module Granite
60
60
 
61
61
  reference_attribute = reference.attribute(name)
62
62
 
63
+ return nil if reference_attribute.nil?
64
+
63
65
  return Granite::Action::Types::Collection.new(reference_attribute.type) if [
64
66
  ActiveData::Model::Attributes::ReferenceMany,
65
67
  ActiveData::Model::Attributes::Collection,
@@ -0,0 +1,10 @@
1
+ require 'active_data'
2
+
3
+ ActiveData.typecaster('Granite::Action::Types::Collection') do |value, attribute|
4
+ typecaster = ActiveData.typecaster(attribute.type.subtype)
5
+ if value.respond_to? :transform_values
6
+ value.transform_values { |v| typecaster.call(v, attribute) }
7
+ elsif value.respond_to?(:map)
8
+ value.map { |v| typecaster.call(v, attribute) }
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Granite
2
- VERSION = '0.8.1'.freeze
2
+ VERSION = '0.8.2'.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.1
4
+ version: 0.8.2
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-08-15 00:00:00.000000000 Z
11
+ date: 2018-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: active_data
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.2
33
+ version: 1.1.3
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.2
40
+ version: 1.1.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: activesupport
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -280,7 +280,6 @@ 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
284
283
  - lib/granite/action/performer.rb
285
284
  - lib/granite/action/performing.rb
286
285
  - lib/granite/action/policies.rb
@@ -293,7 +292,6 @@ files:
293
292
  - lib/granite/action/projectors.rb
294
293
  - lib/granite/action/subject.rb
295
294
  - lib/granite/action/transaction.rb
296
- - lib/granite/action/transaction_manager.rb
297
295
  - lib/granite/action/types.rb
298
296
  - lib/granite/action/types/collection.rb
299
297
  - lib/granite/base.rb
@@ -328,6 +326,7 @@ files:
328
326
  - lib/granite/rspec/raise_validation_error.rb
329
327
  - lib/granite/rspec/satisfy_preconditions.rb
330
328
  - lib/granite/translations.rb
329
+ - lib/granite/typecasters.rb
331
330
  - lib/granite/version.rb
332
331
  homepage: https://github.com/toptal/granite
333
332
  licenses:
@@ -1,39 +0,0 @@
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,86 +0,0 @@
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