granite 0.12.0 → 0.14.0

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
  SHA256:
3
- metadata.gz: 8f01fbcec194a3031c22582899a7ff0210d2b621aa149a5ccf7814a3a70540ea
4
- data.tar.gz: c763544b18d4feb43a5502df2e661dce313c304f47543978be095e4e72afc863
3
+ metadata.gz: d0524a0055b0ea48aeab0691a1063cf332455b87094e2a78dbb6b66cc24b168e
4
+ data.tar.gz: e07a9c6a636eed28916860e213beea548aa92943da442b7d39019b346079e3fc
5
5
  SHA512:
6
- metadata.gz: '099c76956322fe11a1118dc25a1fffbc0553018d1abf660d7c6270256f40505a3d93be01e57df0d7502c767c09d961fcf3361a7281315296e6abb9c512a38a9f'
7
- data.tar.gz: 9b1b66eca75f4ff623319d1828cbec2b987c36050fb70598a8a14ea7edd760da38eb61c89f0a4de3b706875b68a16dccefe22333c3ac8edbe5b80864e04f4aca
6
+ metadata.gz: 217ac1d410c18e838f648af770c610b24ad4a28fc70e37514060509b5ac0a9303907912da5a2e7151162df2d842c78cdf3dd4c03e64ae464427bea9707923410
7
+ data.tar.gz: 2824f499e042ce4df4565d450367ccf3c33b711586c496c752fde675c4a1bd4d2a5810b92c84916603436981ef61c100583d89865e7f5c758c5033fbc3d97e20
@@ -14,11 +14,12 @@ module Granite
14
14
  before_action :authorize_action!
15
15
 
16
16
  def projector
17
- @projector ||= begin
18
- action_projector_class = action_class.public_send(projector_name)
19
- action_projector_class = action_projector_class.as(projector_performer) if respond_to?(:projector_performer, true)
20
- action_projector_class.new(projector_params)
21
- end
17
+ @projector ||=
18
+ begin
19
+ projector_class = action_class.public_send(projector_name)
20
+ projector_class = projector_class.with(projector_context) if respond_to?(:projector_context, true)
21
+ projector_class.new(projector_params)
22
+ end
22
23
  end
23
24
  helper_method :projector
24
25
 
@@ -7,7 +7,7 @@ module Granite
7
7
  class_attribute :_exception_handlers, instance_writer: false
8
8
  self._exception_handlers = {}
9
9
 
10
- protected :_exception_handlers # rubocop:disable Style/AccessModifierDeclarations
10
+ protected :_exception_handlers
11
11
  end
12
12
 
13
13
  module ClassMethods
@@ -0,0 +1,23 @@
1
+ module Granite
2
+ class Action
3
+ module Instrumentation
4
+ def perform!(*, **)
5
+ instrument_perform(:perform!) { super }
6
+ end
7
+
8
+ def perform(*, **)
9
+ instrument_perform(:perform) { super }
10
+ end
11
+
12
+ def try_perform!(*, **)
13
+ instrument_perform(:try_perform!) { super }
14
+ end
15
+
16
+ private
17
+
18
+ def instrument_perform(using, &block)
19
+ ActiveSupport::Notifications.instrument('granite.perform_action', action: self, using: using, &block)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,4 +1,4 @@
1
- require 'granite/performer_proxy'
1
+ require 'granite/context_proxy'
2
2
 
3
3
  module Granite
4
4
  class Action
@@ -8,15 +8,16 @@ module Granite
8
8
  extend ActiveSupport::Concern
9
9
 
10
10
  included do
11
- include PerformerProxy
12
- attr_reader :performer
11
+ include ContextProxy
12
+ attr_reader :ctx
13
13
  end
14
14
 
15
15
  def initialize(*args)
16
- @performer = self.class.proxy_performer
16
+ @ctx = self.class.proxy_context
17
17
  super
18
18
  end
19
19
 
20
+ delegate :performer, to: :ctx, allow_nil: true
20
21
  delegate :id, to: :performer, prefix: true, allow_nil: true
21
22
  end
22
23
  end
@@ -98,8 +98,8 @@ module Granite
98
98
  end
99
99
 
100
100
  # Adds passed error message and options to `errors` object
101
- def decline_with(*args)
102
- errors.add(:base, *args)
101
+ def decline_with(*args, **kwargs)
102
+ errors.add(:base, *args, **kwargs)
103
103
  failed_preconditions << args.first
104
104
  end
105
105
 
@@ -85,13 +85,13 @@ module Granite
85
85
  _projectors.store(name, options, &block)
86
86
 
87
87
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
88
- def self.#{name}
89
- _projectors.fetch(:#{name})
90
- end
91
-
92
- def #{name}
93
- @#{name} ||= self.class._projectors.fetch(:#{name}).new(self)
94
- end
88
+ def self.#{name} # def self.foo
89
+ _projectors.fetch(:#{name}) # _projectors.fetch(:foo)
90
+ end # end
91
+ #
92
+ def #{name} # def foo
93
+ @#{name} ||= self.class._projectors.fetch(:#{name}).new(self) # @foo ||= self.class._projectors.fetch(:foo).new(self)
94
+ end # end
95
95
  METHOD
96
96
  end
97
97
  end
@@ -62,16 +62,14 @@ module Granite
62
62
  collected_errors = []
63
63
 
64
64
  callbacks.reverse_each do |callback|
65
- begin
66
- callback.respond_to?(:run_callbacks) ? callback.run_callbacks(:commit) : callback.call
67
- rescue StandardError => e
68
- collected_errors << e
69
- end
65
+ callback.respond_to?(:run_callbacks) ? callback.run_callbacks(:commit) : callback.call
66
+ rescue StandardError => e
67
+ collected_errors << e
70
68
  end
71
69
 
72
70
  return unless collected_errors.any?
73
71
 
74
- log_errors(collected_errors[1..-1])
72
+ log_errors(collected_errors[1..])
75
73
  fail collected_errors.first
76
74
  end
77
75
 
@@ -17,7 +17,7 @@ module Granite
17
17
 
18
18
  def translate(*args, **options)
19
19
  key, options = Granite::Translations.scope_translation_args(self.class.i18n_scopes, *args, **options)
20
- I18n.translate(key, **options)
20
+ I18n.t(key, **options)
21
21
  end
22
22
  alias t translate
23
23
  end
@@ -5,6 +5,7 @@ require 'active_support/callbacks'
5
5
 
6
6
  require 'granite/action/types'
7
7
  require 'granite/action/error'
8
+ require 'granite/action/instrumentation'
8
9
  require 'granite/action/performing'
9
10
  require 'granite/action/performer'
10
11
  require 'granite/action/precondition'
@@ -48,6 +49,7 @@ module Granite
48
49
  include Policies
49
50
  include Projectors
50
51
  prepend AssignAttributes
52
+ prepend Instrumentation
51
53
 
52
54
  handle_exception ActiveRecord::RecordInvalid do |e|
53
55
  merge_errors(e.record.errors)
@@ -1,6 +1,6 @@
1
1
  module Granite
2
2
  module AssignData
3
- DataAssignment = Struct.new(:method, :options)
3
+ DataAssignment = Struct.new(:method, :options) # rubocop:disable Lint/StructNewOverride
4
4
 
5
5
  extend ActiveSupport::Concern
6
6
 
@@ -9,7 +9,7 @@ module Granite
9
9
  self.data_assignments = []
10
10
 
11
11
  alias_method :only_run_validations!, :run_validations!
12
- protected :only_run_validations! # rubocop:disable Style/AccessModifierDeclarations
12
+ protected :only_run_validations!
13
13
  end
14
14
 
15
15
  module ClassMethods
@@ -0,0 +1,20 @@
1
+ module Granite
2
+ module ContextProxy
3
+ # Contains all the arbitrary data that is passed to BA with `with`
4
+ class Data
5
+ attr_reader :performer
6
+
7
+ def self.wrap(data)
8
+ if data.is_a?(self)
9
+ data
10
+ else
11
+ new(**data || {})
12
+ end
13
+ end
14
+
15
+ def initialize(performer: nil)
16
+ @performer = performer
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,21 +1,22 @@
1
1
  module Granite
2
- module PerformerProxy
3
- # Proxy helps to wrap the following method call with
4
- # performer-enabled context.
2
+ module ContextProxy
3
+ # Proxy which wraps the following method calls with BA context.
5
4
  #
6
5
  class Proxy
7
- def initialize(klass, performer)
6
+ extend Granite::Ruby3Compatibility
7
+
8
+ def initialize(klass, context)
8
9
  @klass = klass
9
- @performer = performer
10
+ @context = context
10
11
  end
11
12
 
12
13
  def inspect
13
- "<#{@klass}PerformerProxy #{@performer}>"
14
+ "<#{@klass}ContextProxy #{@context}>"
14
15
  end
15
16
 
16
- def method_missing(method, *args, &block)
17
+ ruby2_keywords def method_missing(method, *args, &block)
17
18
  if @klass.respond_to?(method)
18
- @klass.with_proxy_performer(@performer) do
19
+ @klass.with_context(@context) do
19
20
  @klass.public_send(method, *args, &block)
20
21
  end
21
22
  else
@@ -0,0 +1,34 @@
1
+ require 'granite/context_proxy/data'
2
+ require 'granite/context_proxy/proxy'
3
+
4
+ module Granite
5
+ # This concern contains class methods used for actions and projectors
6
+ #
7
+ module ContextProxy
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ PROXY_CONTEXT_KEY = :granite_proxy_context
12
+
13
+ def with(data)
14
+ Proxy.new(self, Data.wrap(data))
15
+ end
16
+
17
+ def as(performer)
18
+ with(performer: performer)
19
+ end
20
+
21
+ def with_context(context)
22
+ old_context = proxy_context
23
+ Thread.current[PROXY_CONTEXT_KEY] = context
24
+ yield
25
+ ensure
26
+ Thread.current[PROXY_CONTEXT_KEY] = old_context
27
+ end
28
+
29
+ def proxy_context
30
+ Thread.current[PROXY_CONTEXT_KEY]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -22,13 +22,13 @@ module Granite
22
22
  self.controller_actions = controller_actions.merge(name.to_sym => options)
23
23
  controller_class.__send__(:define_method, name, &block)
24
24
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
25
- def #{name}_url(options = {})
26
- action_url(:#{name}, **options.symbolize_keys)
27
- end
28
-
29
- def #{name}_path(options = {})
30
- action_path(:#{name}, **options.symbolize_keys)
31
- end
25
+ def #{name}_url(options = {}) # def foo_url(options = {}
26
+ action_url(:#{name}, **options.symbolize_keys) # action_url(:foo, **options.symbolize_keys)
27
+ end # end
28
+ #
29
+ def #{name}_path(options = {}) # def foo_path(options = {})
30
+ action_path(:#{name}, **options.symbolize_keys) # action_path(:foo, **options.symbolize_keys)
31
+ end # end
32
32
  METHOD
33
33
  else
34
34
  controller_actions[name.to_sym]
@@ -35,8 +35,7 @@ Do you have #{projector.action_class.name.underscore}##{projector.projector_name
35
35
 
36
36
  def required_params
37
37
  corresponding_route.required_parts
38
- .map { |name| [name, action.public_send(name)] }
39
- .to_h
38
+ .to_h { |name| [name, action.public_send(name)] }
40
39
  end
41
40
 
42
41
  def corresponding_route
@@ -2,11 +2,11 @@ require 'granite/projector/controller_actions'
2
2
  require 'granite/projector/error'
3
3
  require 'granite/projector/helpers'
4
4
  require 'granite/projector/translations'
5
- require 'granite/performer_proxy'
5
+ require 'granite/context_proxy'
6
6
 
7
7
  module Granite
8
8
  class Projector
9
- include PerformerProxy
9
+ include ContextProxy
10
10
  include ControllerActions
11
11
  include Helpers
12
12
  include Translations
@@ -42,7 +42,7 @@ module Granite
42
42
  private
43
43
 
44
44
  def build_action(*args)
45
- action_class.as(self.class.proxy_performer).new(*args)
45
+ action_class.with(self.class.proxy_context).new(*args)
46
46
  end
47
47
  end
48
48
  end
@@ -15,7 +15,7 @@ module Granite
15
15
  end
16
16
 
17
17
  def typecast(value)
18
- return value if value.class == type
18
+ return value if value.class == type # rubocop:disable Style/ClassEqualityComparison
19
19
 
20
20
  typecaster.call(value, self) unless value.nil?
21
21
  end
@@ -28,9 +28,9 @@ module Granite
28
28
 
29
29
  def typecaster
30
30
  @typecaster ||= begin
31
- type_class = type.instance_of?(Class) ? type : type.class
32
- @typecaster = ActiveData.typecaster(type_class.ancestors.grep(Class))
33
- end
31
+ type_class = type.instance_of?(Class) ? type : type.class
32
+ @typecaster = ActiveData.typecaster(type_class.ancestors.grep(Class))
33
+ end
34
34
  end
35
35
 
36
36
  def changed?
@@ -0,0 +1,89 @@
1
+ RSpec::Matchers.define :perform_action do |klass|
2
+ chain :using do |using|
3
+ @using = using
4
+ end
5
+
6
+ chain :as do |performer|
7
+ @performer = performer
8
+ end
9
+
10
+ chain :with do |attributes|
11
+ @attributes = attributes
12
+ end
13
+
14
+ match do |block|
15
+ @klass = klass
16
+ @using ||= :perform!
17
+
18
+ @payloads = []
19
+ subscriber = ActiveSupport::Notifications.subscribe('granite.perform_action') do |_, _, _, _, payload|
20
+ @payloads << payload
21
+ end
22
+
23
+ block.call
24
+
25
+ ActiveSupport::Notifications.unsubscribe(subscriber)
26
+
27
+ @payloads.detect { |payload| action_matches?(payload[:action]) && payload[:using] == @using }
28
+ end
29
+
30
+ failure_message do
31
+ output = "expected to call #{performed_entity}"
32
+ add_performer_message(output, @performer) if defined?(@performer)
33
+ add_attributes_message(output, @attributes) if defined?(@attributes)
34
+
35
+ similar_payloads = @payloads.select { |payload| class_matches?(payload[:action]) && payload[:using] == @using }
36
+ if similar_payloads.present?
37
+ output << "\nreceived calls to #{performed_entity}:"
38
+ similar_payloads.each { |payload| add_message_from_payload(output, payload) }
39
+ end
40
+
41
+ output
42
+ end
43
+
44
+ failure_message_when_negated do
45
+ "expected not to call #{performed_entity}"
46
+ end
47
+
48
+ supports_block_expectations
49
+
50
+ private
51
+
52
+ def add_message_from_payload(output, payload)
53
+ action = payload[:action]
54
+ add_performer_message(output, action.performer) if defined?(@performer)
55
+ add_attributes_message(output, actual_attributes(action)) if defined?(@attributes)
56
+ end
57
+
58
+ def add_performer_message(output, performer)
59
+ output << "\n AS #{performer.inspect}"
60
+ end
61
+
62
+ def add_attributes_message(output, attributes)
63
+ output << "\n WITH #{attributes.inspect}"
64
+ end
65
+
66
+ def performed_entity
67
+ "#{@klass}##{@using}"
68
+ end
69
+
70
+ def actual_attributes(action)
71
+ @attributes.keys.to_h { |attr| [attr, action.public_send(attr)] }
72
+ end
73
+
74
+ def action_matches?(action)
75
+ class_matches?(action) && performer_matches?(action) && attributes_match?(action)
76
+ end
77
+
78
+ def class_matches?(action)
79
+ action.is_a?(@klass)
80
+ end
81
+
82
+ def performer_matches?(action)
83
+ !defined?(@performer) || action.performer == @performer
84
+ end
85
+
86
+ def attributes_match?(action)
87
+ !defined?(@attributes) || match(@attributes).matches?(actual_attributes(action))
88
+ end
89
+ end
@@ -30,16 +30,10 @@ module Granite::ProjectorHelpers
30
30
 
31
31
  private
32
32
 
33
- def setup_controller
34
- singleton_class.class_eval do
35
- def controller_class
36
- end
37
- end
38
-
39
- before do
40
- @controller = yield.controller_class.new
41
- @controller.class.instance_variable_set(:@controller_path, yield.projector_path)
42
- @controller.request = @request
33
+ def setup_controller(&block)
34
+ define_method :setup_controller_request_and_response do
35
+ @controller ||= instance_eval(&block).controller_class.new
36
+ super()
43
37
  end
44
38
  end
45
39
 
@@ -23,14 +23,12 @@ RSpec::Matchers.define :raise_validation_error do
23
23
  end
24
24
 
25
25
  match do |block|
26
- begin
27
- block.call
28
- false
29
- rescue Granite::Action::ValidationError => e
30
- @details = e.errors.details
31
- @details_being_checked = @details[@attribute || :base]
32
- @result = @details_being_checked&.any? { |x| x[:error] == @error_type }
33
- end
26
+ block.call
27
+ false
28
+ rescue Granite::Action::ValidationError => e
29
+ @details = e.errors.details
30
+ @details_being_checked = @details[@attribute || :base]
31
+ @result = @details_being_checked&.any? { |x| x[:error] == @error_type }
34
32
  end
35
33
 
36
34
  description do
data/lib/granite/rspec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'granite/rspec/action_helpers'
2
2
  require 'granite/rspec/have_projector'
3
+ require 'granite/rspec/perform_action'
3
4
  require 'granite/rspec/projector_helpers'
4
5
  require 'granite/rspec/raise_validation_error'
5
6
  require 'granite/rspec/satisfy_preconditions'
@@ -0,0 +1,15 @@
1
+ module Granite
2
+ module Ruby3Compatibility
3
+ # Method definition aimed to provide compatibility between Ruby 2.6 and 3.0
4
+ # It's being recommended in this article
5
+ # https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
6
+ #
7
+ # Example:
8
+ #
9
+ # ruby2_keywords def a_method(argument, *args, &block)
10
+ # delegating_to_method(argument, *args, &block)
11
+ # end
12
+ def ruby2_keywords(*)
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Granite
2
- VERSION = '0.12.0'.freeze
2
+ VERSION = '0.14.0'.freeze
3
3
  end
data/lib/granite.rb CHANGED
@@ -5,6 +5,7 @@ require 'granite/version'
5
5
  require 'granite/config'
6
6
  require 'granite/context'
7
7
  require 'granite/util'
8
+ require 'granite/ruby3_compatibility'
8
9
 
9
10
  module Granite
10
11
  def self.config
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.12.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toptal Engineering
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-23 00:00:00.000000000 Z
11
+ date: 2022-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -252,42 +252,42 @@ dependencies:
252
252
  requirements:
253
253
  - - "~>"
254
254
  - !ruby/object:Gem::Version
255
- version: 0.78.0
255
+ version: '1.0'
256
256
  type: :development
257
257
  prerelease: false
258
258
  version_requirements: !ruby/object:Gem::Requirement
259
259
  requirements:
260
260
  - - "~>"
261
261
  - !ruby/object:Gem::Version
262
- version: 0.78.0
262
+ version: '1.0'
263
263
  - !ruby/object:Gem::Dependency
264
264
  name: rubocop-rails
265
265
  requirement: !ruby/object:Gem::Requirement
266
266
  requirements:
267
267
  - - "~>"
268
268
  - !ruby/object:Gem::Version
269
- version: 2.4.1
269
+ version: '2.13'
270
270
  type: :development
271
271
  prerelease: false
272
272
  version_requirements: !ruby/object:Gem::Requirement
273
273
  requirements:
274
274
  - - "~>"
275
275
  - !ruby/object:Gem::Version
276
- version: 2.4.1
276
+ version: '2.13'
277
277
  - !ruby/object:Gem::Dependency
278
278
  name: rubocop-rspec
279
279
  requirement: !ruby/object:Gem::Requirement
280
280
  requirements:
281
281
  - - "~>"
282
282
  - !ruby/object:Gem::Version
283
- version: 1.37.0
283
+ version: '2.8'
284
284
  type: :development
285
285
  prerelease: false
286
286
  version_requirements: !ruby/object:Gem::Requirement
287
287
  requirements:
288
288
  - - "~>"
289
289
  - !ruby/object:Gem::Version
290
- version: 1.37.0
290
+ version: '2.8'
291
291
  - !ruby/object:Gem::Dependency
292
292
  name: simplecov
293
293
  requirement: !ruby/object:Gem::Requirement
@@ -302,8 +302,8 @@ dependencies:
302
302
  - - "~>"
303
303
  - !ruby/object:Gem::Version
304
304
  version: '0.15'
305
- description:
306
- email:
305
+ description:
306
+ email:
307
307
  executables: []
308
308
  extensions: []
309
309
  extra_rdoc_files: []
@@ -323,6 +323,7 @@ files:
323
323
  - lib/granite/action.rb
324
324
  - lib/granite/action/error.rb
325
325
  - lib/granite/action/exceptions_handling.rb
326
+ - lib/granite/action/instrumentation.rb
326
327
  - lib/granite/action/performer.rb
327
328
  - lib/granite/action/performing.rb
328
329
  - lib/granite/action/policies.rb
@@ -346,10 +347,11 @@ files:
346
347
  - lib/granite/base.rb
347
348
  - lib/granite/config.rb
348
349
  - lib/granite/context.rb
350
+ - lib/granite/context_proxy.rb
351
+ - lib/granite/context_proxy/data.rb
352
+ - lib/granite/context_proxy/proxy.rb
349
353
  - lib/granite/dispatcher.rb
350
354
  - lib/granite/error.rb
351
- - lib/granite/performer_proxy.rb
352
- - lib/granite/performer_proxy/proxy.rb
353
355
  - lib/granite/projector.rb
354
356
  - lib/granite/projector/controller_actions.rb
355
357
  - lib/granite/projector/error.rb
@@ -369,9 +371,11 @@ files:
369
371
  - lib/granite/rspec.rb
370
372
  - lib/granite/rspec/action_helpers.rb
371
373
  - lib/granite/rspec/have_projector.rb
374
+ - lib/granite/rspec/perform_action.rb
372
375
  - lib/granite/rspec/projector_helpers.rb
373
376
  - lib/granite/rspec/raise_validation_error.rb
374
377
  - lib/granite/rspec/satisfy_preconditions.rb
378
+ - lib/granite/ruby3_compatibility.rb
375
379
  - lib/granite/translations.rb
376
380
  - lib/granite/typecasters.rb
377
381
  - lib/granite/util.rb
@@ -383,7 +387,7 @@ homepage: https://github.com/toptal/granite
383
387
  licenses:
384
388
  - MIT
385
389
  metadata: {}
386
- post_install_message:
390
+ post_install_message:
387
391
  rdoc_options: []
388
392
  require_paths:
389
393
  - lib
@@ -391,15 +395,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
391
395
  requirements:
392
396
  - - ">="
393
397
  - !ruby/object:Gem::Version
394
- version: '0'
398
+ version: '2.5'
395
399
  required_rubygems_version: !ruby/object:Gem::Requirement
396
400
  requirements:
397
401
  - - ">="
398
402
  - !ruby/object:Gem::Version
399
403
  version: '0'
400
404
  requirements: []
401
- rubygems_version: 3.2.29
402
- signing_key:
405
+ rubygems_version: 3.3.9
406
+ signing_key:
403
407
  specification_version: 4
404
408
  summary: Another business actions architecture for Rails apps
405
409
  test_files: []
@@ -1,34 +0,0 @@
1
- require 'granite/performer_proxy/proxy'
2
-
3
- module Granite
4
- # This concern contains class methods used for actions and projectors
5
- #
6
- module PerformerProxy
7
- extend ActiveSupport::Concern
8
-
9
- module ClassMethods
10
- def as(performer)
11
- Proxy.new(self, performer)
12
- end
13
-
14
- def with_proxy_performer(performer)
15
- key = proxy_performer_key
16
- old_performer = Thread.current[key]
17
- Thread.current[key] = performer
18
- yield
19
- ensure
20
- Thread.current[key] = old_performer
21
- end
22
-
23
- def proxy_performer
24
- Thread.current[proxy_performer_key]
25
- end
26
-
27
- private
28
-
29
- def proxy_performer_key
30
- :"granite_proxy_performer_#{hash}"
31
- end
32
- end
33
- end
34
- end