granite 0.17.1 → 0.17.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 +4 -4
- data/app/controllers/granite/controller/translations.rb +1 -1
- data/app/controllers/granite/controller.rb +1 -1
- data/lib/generators/granite/install_controller_generator.rb +1 -1
- data/lib/generators/granite_generator.rb +5 -2
- data/lib/granite/action/error.rb +1 -1
- data/lib/granite/action/exceptions_handling.rb +5 -5
- data/lib/granite/action/instrumentation.rb +1 -1
- data/lib/granite/action/performing.rb +7 -4
- data/lib/granite/action/policies.rb +3 -3
- data/lib/granite/action/precondition.rb +2 -2
- data/lib/granite/action/preconditions/base_precondition.rb +1 -1
- data/lib/granite/action/preconditions/object_precondition.rb +1 -1
- data/lib/granite/action/preconditions.rb +3 -3
- data/lib/granite/action/projectors.rb +4 -6
- data/lib/granite/action/subject.rb +5 -5
- data/lib/granite/action/transaction.rb +1 -1
- data/lib/granite/action/transaction_manager/transactions_stack.rb +2 -3
- data/lib/granite/action/transaction_manager.rb +5 -4
- data/lib/granite/action/translations.rb +2 -2
- data/lib/granite/action.rb +7 -4
- data/lib/granite/assign_data.rb +2 -2
- data/lib/granite/config.rb +1 -1
- data/lib/granite/context.rb +1 -1
- data/lib/granite/context_proxy.rb +1 -1
- data/lib/granite/dispatcher.rb +49 -46
- data/lib/granite/projector/controller_actions.rb +3 -3
- data/lib/granite/projector/error.rb +1 -1
- data/lib/granite/projector/helpers.rb +4 -4
- data/lib/granite/projector/translations.rb +1 -1
- data/lib/granite/projector.rb +1 -1
- data/lib/granite/routing/cache.rb +1 -1
- data/lib/granite/routing/caching.rb +1 -1
- data/lib/granite/routing/declarer.rb +1 -1
- data/lib/granite/routing/mapper.rb +1 -1
- data/lib/granite/routing/mapping.rb +1 -1
- data/lib/granite/routing/route.rb +1 -1
- data/lib/granite/rspec/action_helpers.rb +8 -4
- data/lib/granite/rspec/perform_action.rb +1 -1
- data/lib/granite/rspec/projector_helpers.rb +43 -38
- data/lib/granite/rspec/raise_validation_error.rb +2 -6
- data/lib/granite/rspec/satisfy_preconditions.rb +6 -6
- data/lib/granite/translations.rb +1 -1
- data/lib/granite/version.rb +1 -1
- data/lib/granite.rb +5 -1
- data/lib/rubocop/granite/inject.rb +1 -3
- data/lib/rubocop/granite.rb +1 -1
- data/lib/rubocop-granite.rb +0 -2
- metadata +30 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3e1ba1452b79b7af5130326fb9fd4b11399bf8c23d2bdcbb3cf7a3d54a81c6f
|
4
|
+
data.tar.gz: dbc6e24fa6d5e22710bed7a24f0ff9bde67d91bc6672bb0af89477601ec1b199
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfff687bb585d2ddff0fc504e08a849e3f148c13cfb9bb6d48a016dca0a83a57008cdce581753ccacb18005a5c9cac46ad49ebcacc3e615f14c9a7af4fc7aa90
|
7
|
+
data.tar.gz: 77fa6fd1b0c27b045cca42ec681ae51e3042fa89c45c602bdd509f78126920da694d85582089805cf753ce9792aef21177ee9cfe745e268bd36e6be62b0094b5
|
@@ -2,7 +2,7 @@ require 'rails/generators/base'
|
|
2
2
|
|
3
3
|
module Granite
|
4
4
|
module Generators
|
5
|
-
class InstallControllerGenerator < Rails::Generators::Base
|
5
|
+
class InstallControllerGenerator < Rails::Generators::Base # :nodoc:
|
6
6
|
source_root File.expand_path('../../..', __dir__)
|
7
7
|
|
8
8
|
desc 'Creates a Granite::Controller for further customization'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class GraniteGenerator < Rails::Generators::NamedBase
|
1
|
+
class GraniteGenerator < Rails::Generators::NamedBase # :nodoc:
|
2
2
|
source_root File.expand_path('templates', __dir__)
|
3
3
|
|
4
4
|
argument :projector, type: :string, required: false
|
@@ -6,7 +6,10 @@ class GraniteGenerator < Rails::Generators::NamedBase
|
|
6
6
|
|
7
7
|
def create_action
|
8
8
|
template 'granite_action.rb.erb', "apq/actions/#{file_path}.rb"
|
9
|
-
|
9
|
+
unless options.collection?
|
10
|
+
template 'granite_business_action.rb.erb',
|
11
|
+
"apq/actions/#{class_path.join('/')}/business_action.rb"
|
12
|
+
end
|
10
13
|
template 'granite_base_action.rb.erb', 'apq/actions/base_action.rb', skip: true
|
11
14
|
template 'granite_action_spec.rb.erb', "spec/apq/actions/#{file_path}_spec.rb"
|
12
15
|
empty_directory "apq/actions/#{file_path}/#{projector}" if projector
|
data/lib/granite/action/error.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Granite
|
2
2
|
class Action
|
3
|
-
module ExceptionsHandling
|
3
|
+
module ExceptionsHandling # :nodoc:
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
@@ -10,7 +10,7 @@ module Granite
|
|
10
10
|
protected :_exception_handlers
|
11
11
|
end
|
12
12
|
|
13
|
-
module ClassMethods
|
13
|
+
module ClassMethods # :nodoc:
|
14
14
|
# Register default handler for exceptions thrown inside execute_perform! and after_commit methods.
|
15
15
|
# @param klass Exception class, could be parent class too [Class]
|
16
16
|
# @param block [Block<Exception>] with default behavior for handling specified
|
@@ -28,11 +28,11 @@ module Granite
|
|
28
28
|
_exception_handlers.keys
|
29
29
|
end
|
30
30
|
|
31
|
-
def handle_exception(
|
32
|
-
klass =
|
31
|
+
def handle_exception(exception)
|
32
|
+
klass = exception.class.ancestors.detect do |ancestor|
|
33
33
|
ancestor <= Exception && _exception_handlers[ancestor]
|
34
34
|
end
|
35
|
-
instance_exec(
|
35
|
+
instance_exec(exception, &_exception_handlers[klass]) if klass
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -25,9 +25,9 @@ module Granite
|
|
25
25
|
define_callbacks :execute_perform
|
26
26
|
end
|
27
27
|
|
28
|
-
module ClassMethods
|
28
|
+
module ClassMethods # :nodoc:
|
29
29
|
def perform(*)
|
30
|
-
|
30
|
+
raise 'Perform block declaration was removed! Please declare `private def execute_perform!(*)` method'
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -36,13 +36,16 @@ module Granite
|
|
36
36
|
# database transaction. Returns the result of execute_perform! method execution
|
37
37
|
# or true if method execution returned false or nil
|
38
38
|
#
|
39
|
+
# @deprecated Use {#perform!} or {#try_perform!} instead
|
39
40
|
# @param context [Symbol] can be optionally provided to define which
|
40
41
|
# validations to test against (the context is defined on validations
|
41
42
|
# using `:on`)
|
42
43
|
# @return [Object] result of execute_perform! method execution or false in case of errors
|
43
44
|
def perform(context: nil, **options)
|
45
|
+
Granite.deprecator.warn('Granite::Action#perform is deprecated, use #perform! or #try_perform! instead')
|
46
|
+
|
44
47
|
transaction do
|
45
|
-
|
48
|
+
raise Rollback unless valid?(context)
|
46
49
|
|
47
50
|
perform_action(**options)
|
48
51
|
end
|
@@ -110,7 +113,7 @@ module Granite
|
|
110
113
|
end
|
111
114
|
|
112
115
|
def execute_perform!(**_options)
|
113
|
-
|
116
|
+
raise NotImplementedError, "BA perform body MUST be defined for #{self}"
|
114
117
|
end
|
115
118
|
end
|
116
119
|
end
|
@@ -5,7 +5,7 @@ require 'granite/action/policies/required_performer_strategy'
|
|
5
5
|
|
6
6
|
module Granite
|
7
7
|
class Action
|
8
|
-
class NotAllowedError < Error
|
8
|
+
class NotAllowedError < Error # :nodoc:
|
9
9
|
def initialize(action)
|
10
10
|
performer_id = "##{action.performer.id}" if action.performer.respond_to?(:id) && action.performer.id.present?
|
11
11
|
|
@@ -30,7 +30,7 @@ module Granite
|
|
30
30
|
self._policies_strategy = AnyStrategy
|
31
31
|
end
|
32
32
|
|
33
|
-
module ClassMethods
|
33
|
+
module ClassMethods # :nodoc:
|
34
34
|
# The simplies policy. Takes block and executes it returning
|
35
35
|
# boolean result. Multiple policies are reduced with ||
|
36
36
|
#
|
@@ -80,7 +80,7 @@ module Granite
|
|
80
80
|
# Raises Granite::Action::NotAllowedError if action is not allowed
|
81
81
|
#
|
82
82
|
def authorize!
|
83
|
-
|
83
|
+
raise Granite::Action::NotAllowedError, self unless allowed?
|
84
84
|
|
85
85
|
self
|
86
86
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Granite
|
2
2
|
class Action
|
3
|
-
class Precondition < BasicObject
|
3
|
+
class Precondition < BasicObject # :nodoc:
|
4
4
|
UNDEFINED = ::Object.new.freeze
|
5
5
|
|
6
6
|
def self.description(text = UNDEFINED)
|
@@ -17,7 +17,7 @@ module Granite
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def call(*)
|
20
|
-
|
20
|
+
raise NotImplementedError, "#call method must be implemented for #{self.class}"
|
21
21
|
end
|
22
22
|
|
23
23
|
def method_missing(method_name, *args, &blk)
|
@@ -13,7 +13,7 @@ module Granite
|
|
13
13
|
module Preconditions
|
14
14
|
extend ActiveSupport::Concern
|
15
15
|
|
16
|
-
class PreconditionsCollection
|
16
|
+
class PreconditionsCollection # :nodoc:
|
17
17
|
include Enumerable
|
18
18
|
|
19
19
|
delegate :each, to: :@preconditions
|
@@ -36,7 +36,7 @@ module Granite
|
|
36
36
|
self._preconditions = PreconditionsCollection.new
|
37
37
|
end
|
38
38
|
|
39
|
-
module ClassMethods
|
39
|
+
module ClassMethods # :nodoc:
|
40
40
|
# Define preconditions for current action.
|
41
41
|
#
|
42
42
|
# @param options [Hash] hash with
|
@@ -61,7 +61,7 @@ module Granite
|
|
61
61
|
key = key.to_s.camelize
|
62
62
|
Granite.precondition_namespaces.reduce(nil) do |memo, ns|
|
63
63
|
memo || "#{ns.to_s.camelize}::#{key}Precondition".safe_constantize
|
64
|
-
end ||
|
64
|
+
end || raise(NameError, "No precondition class for #{key}Precondition")
|
65
65
|
end
|
66
66
|
|
67
67
|
def add_preconditions_hash(*args, **options)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Granite
|
2
2
|
class Action
|
3
|
-
module Projectors
|
3
|
+
module Projectors # :nodoc:
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
class ProjectorsCollection
|
6
|
+
class ProjectorsCollection # :nodoc:
|
7
7
|
def initialize(action_class)
|
8
8
|
@action_class = action_class
|
9
9
|
@storage = {}
|
@@ -40,9 +40,7 @@ module Granite
|
|
40
40
|
redefine_const(projector_name, projector)
|
41
41
|
redefine_const(controller_name, projector.controller_class)
|
42
42
|
|
43
|
-
blocks.each
|
44
|
-
projector.class_eval(&block)
|
45
|
-
end
|
43
|
+
blocks.each { |block| projector.class_eval(&block) }
|
46
44
|
|
47
45
|
projector
|
48
46
|
end
|
@@ -72,7 +70,7 @@ module Granite
|
|
72
70
|
end
|
73
71
|
end
|
74
72
|
|
75
|
-
module ClassMethods
|
73
|
+
module ClassMethods # :nodoc:
|
76
74
|
def _projectors
|
77
75
|
@_projectors ||= ProjectorsCollection.new(self)
|
78
76
|
end
|
@@ -1,25 +1,25 @@
|
|
1
1
|
module Granite
|
2
2
|
class Action
|
3
|
-
class SubjectNotFoundError < ArgumentError
|
3
|
+
class SubjectNotFoundError < ArgumentError # :nodoc:
|
4
4
|
def initialize(action_class)
|
5
5
|
super("Unable to initialize #{action_class} without subject provided")
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
class SubjectTypeMismatchError < ArgumentError
|
9
|
+
class SubjectTypeMismatchError < ArgumentError # :nodoc:
|
10
10
|
def initialize(action_class, candidate, expected)
|
11
11
|
super("Unable to initialize #{action_class} with #{candidate} as subject, expecting instance of #{expected}")
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
module Subject
|
15
|
+
module Subject # :nodoc:
|
16
16
|
extend ActiveSupport::Concern
|
17
17
|
|
18
18
|
included do
|
19
19
|
class_attribute :_subject
|
20
20
|
end
|
21
21
|
|
22
|
-
module ClassMethods
|
22
|
+
module ClassMethods # :nodoc:
|
23
23
|
def subject(name, *args, &block)
|
24
24
|
reflection = reflect_on_association(name)
|
25
25
|
reflection ||= references_one name, *args, &block
|
@@ -65,7 +65,7 @@ module Granite
|
|
65
65
|
assign_attributes(attributes)
|
66
66
|
|
67
67
|
self.subject = args.first unless args.empty?
|
68
|
-
|
68
|
+
raise SubjectNotFoundError, self.class unless subject
|
69
69
|
rescue Granite::Form::AssociationTypeMismatch
|
70
70
|
raise SubjectTypeMismatchError.new(self.class, args.first.class.name, reflection.klass)
|
71
71
|
end
|
@@ -21,7 +21,7 @@ module Granite
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def add_callback(callback)
|
24
|
-
|
24
|
+
raise 'Start a transaction before you add callbacks on it' if depth.zero?
|
25
25
|
|
26
26
|
@callbacks.last << callback
|
27
27
|
end
|
@@ -46,7 +46,7 @@ module Granite
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def finish_current(result)
|
49
|
-
|
49
|
+
raise ArgumentError, 'No current transaction' if @depth.zero?
|
50
50
|
|
51
51
|
@depth -= 1
|
52
52
|
|
@@ -58,7 +58,6 @@ module Granite
|
|
58
58
|
@callbacks.pop
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
@@ -5,7 +5,7 @@ module Granite
|
|
5
5
|
class Rollback < defined?(ActiveRecord) ? ActiveRecord::Rollback : StandardError
|
6
6
|
end
|
7
7
|
|
8
|
-
module TransactionManager
|
8
|
+
module TransactionManager # :nodoc:
|
9
9
|
class << self
|
10
10
|
# Runs a block in a transaction
|
11
11
|
# It will open a new transaction or append a block to the current one if it exists
|
@@ -23,7 +23,7 @@ module Granite
|
|
23
23
|
def after_commit(listener = nil, &block)
|
24
24
|
callback = listener || block
|
25
25
|
|
26
|
-
|
26
|
+
raise 'Block or object is required to register after_commit hook!' unless callback
|
27
27
|
|
28
28
|
transactions_stack.add_callback callback
|
29
29
|
end
|
@@ -70,12 +70,13 @@ module Granite
|
|
70
70
|
return unless collected_errors.any?
|
71
71
|
|
72
72
|
log_errors(collected_errors[1..])
|
73
|
-
|
73
|
+
raise collected_errors.first
|
74
74
|
end
|
75
75
|
|
76
76
|
def log_errors(errors)
|
77
77
|
errors.each do |error|
|
78
|
-
|
78
|
+
message = "Unhandled error in after_commit callback: #{error.inspect}\n#{error.backtrace.join("\n")}"
|
79
|
+
Granite::Form.config.logger.error message
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
data/lib/granite/action.rb
CHANGED
@@ -15,13 +15,16 @@ require 'granite/action/subject'
|
|
15
15
|
require 'granite/action/translations'
|
16
16
|
|
17
17
|
module Granite
|
18
|
-
class Action
|
19
|
-
class ValidationError < Error
|
18
|
+
class Action # :nodoc:
|
19
|
+
class ValidationError < Error # :nodoc:
|
20
20
|
delegate :errors, to: :action
|
21
21
|
|
22
22
|
def initialize(action)
|
23
23
|
errors = action.errors.full_messages.join(', ')
|
24
|
-
super(I18n.t(:"#{action.class.i18n_scope}.errors.messages.action_invalid",
|
24
|
+
super(I18n.t(:"#{action.class.i18n_scope}.errors.messages.action_invalid",
|
25
|
+
action: action.class,
|
26
|
+
errors: errors,
|
27
|
+
default: :'errors.messages.action_invalid'), action)
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -102,7 +105,7 @@ module Granite
|
|
102
105
|
protected
|
103
106
|
|
104
107
|
def raise_validation_error(original_error = nil)
|
105
|
-
|
108
|
+
raise ValidationError, self, original_error&.backtrace
|
106
109
|
end
|
107
110
|
end
|
108
111
|
end
|
data/lib/granite/assign_data.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Granite
|
2
|
-
module AssignData
|
2
|
+
module AssignData # :nodoc:
|
3
3
|
DataAssignment = Struct.new(:method, :options) # rubocop:disable Lint/StructNewOverride
|
4
4
|
|
5
5
|
extend ActiveSupport::Concern
|
@@ -14,7 +14,7 @@ module Granite
|
|
14
14
|
assign_data :sync_attributes
|
15
15
|
end
|
16
16
|
|
17
|
-
module ClassMethods
|
17
|
+
module ClassMethods # :nodoc:
|
18
18
|
# Defines a callback to call when assigning data from business action to model.
|
19
19
|
# @param methods [Array<Symbol>] list of methods to call
|
20
20
|
# @param block [Proc] a block to call
|
data/lib/granite/config.rb
CHANGED
data/lib/granite/context.rb
CHANGED
data/lib/granite/dispatcher.rb
CHANGED
@@ -1,64 +1,67 @@
|
|
1
1
|
require 'memoist'
|
2
2
|
require 'action_controller/metal/exceptions'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
module Granite
|
5
|
+
class Dispatcher # :nodoc:
|
6
|
+
extend Memoist
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# Make dispatcher object pristine, clean memoist cache.
|
9
|
+
def reset!
|
10
|
+
unmemoize_all
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
def call(*)
|
14
|
+
# Pretend to be a Rack app, however we are still dispatcher, so this method should never be called
|
15
|
+
# see lib/granite/routing/mapping.rb for more info.
|
16
|
+
raise 'Dispatcher can\'t be used as a Rack app.'
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def serve(req)
|
20
|
+
controller, action = detect_controller_class_and_action_name(req)
|
21
|
+
controller.action(action).call(req.env)
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
def constraints
|
25
|
+
[->(req) { detect_controller_class_and_action_name(req).all?(&:present?) }]
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def controller(params, *_args)
|
29
|
+
projector(*params.values_at(:granite_action, :granite_projector))&.controller_class
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
def prepare_params!(params, *_args)
|
33
|
+
params
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
+
private
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
def detect_controller_class_and_action_name(req)
|
39
|
+
[
|
40
|
+
controller(req.params),
|
41
|
+
action_name(
|
42
|
+
req.request_method_symbol,
|
43
|
+
*req.params.values_at(:granite_action, :granite_projector, :projector_action)
|
44
|
+
)
|
45
|
+
]
|
46
|
+
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
memoize def action_name(request_method_symbol, granite_action, granite_projector, projector_action)
|
49
|
+
projector = projector(granite_action, granite_projector)
|
50
|
+
return unless projector
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
projector.action_for(request_method_symbol, projector_action.to_s)
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
55
|
+
memoize def projector(granite_action, granite_projector)
|
56
|
+
action = business_action(granite_action)
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
action.public_send(granite_projector) if action.respond_to?(granite_projector)
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
memoize def business_action(granite_action)
|
62
|
+
granite_action.camelize.safe_constantize ||
|
63
|
+
raise(ActionController::RoutingError,
|
64
|
+
"Granite action '#{granite_action}' is mounted but class '#{granite_action.camelize}' can't be found")
|
65
|
+
end
|
63
66
|
end
|
64
67
|
end
|
@@ -2,7 +2,7 @@ require 'action_dispatch/routing'
|
|
2
2
|
|
3
3
|
module Granite
|
4
4
|
class Projector
|
5
|
-
module ControllerActions
|
5
|
+
module ControllerActions # :nodoc:
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
@@ -16,8 +16,8 @@ module Granite
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
module ClassMethods
|
20
|
-
def action(name, options = {}, &block)
|
19
|
+
module ClassMethods # :nodoc:
|
20
|
+
def action(name, options = {}, &block) # rubocop:disable Metrics/MethodLength
|
21
21
|
if block
|
22
22
|
self.controller_actions = controller_actions.merge(name.to_sym => options)
|
23
23
|
controller_class.__send__(:define_method, name, &block)
|
@@ -2,14 +2,14 @@ require 'granite/projector/error'
|
|
2
2
|
|
3
3
|
module Granite
|
4
4
|
class Projector
|
5
|
-
class ActionNotMountedError < Error
|
5
|
+
class ActionNotMountedError < Error # :nodoc:
|
6
6
|
def initialize(projector)
|
7
7
|
super("Seems like #{projector.class} was not mounted. \
|
8
8
|
Do you have #{projector.action_name}##{projector.projector_name} declared in routes?", projector)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
module Helpers
|
12
|
+
module Helpers # :nodoc:
|
13
13
|
extend ActiveSupport::Concern
|
14
14
|
|
15
15
|
def view_context
|
@@ -35,7 +35,7 @@ Do you have #{projector.action_name}##{projector.projector_name} declared in rou
|
|
35
35
|
|
36
36
|
def required_params
|
37
37
|
corresponding_route.required_parts
|
38
|
-
|
38
|
+
.to_h { |name| [name, action.public_send(name)] }
|
39
39
|
end
|
40
40
|
|
41
41
|
def corresponding_route
|
@@ -51,7 +51,7 @@ Do you have #{projector.action_name}##{projector.projector_name} declared in rou
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def fetch_corresponding_route
|
54
|
-
Rails.application.routes.routes.granite_cache[*route_id] ||
|
54
|
+
Rails.application.routes.routes.granite_cache[*route_id] || raise(ActionNotMountedError, self)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
data/lib/granite/projector.rb
CHANGED
@@ -3,7 +3,7 @@ require 'granite/routing/route'
|
|
3
3
|
|
4
4
|
module Granite
|
5
5
|
module Routing
|
6
|
-
module Mapper
|
6
|
+
module Mapper # :nodoc:
|
7
7
|
def granite(projector_path, **options)
|
8
8
|
route = Route.new(projector_path, **options.extract!(:path, :as, :projector_prefix))
|
9
9
|
Declarer.declare(self, route, **options)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Granite
|
2
2
|
module Routing
|
3
|
-
module Mapping
|
3
|
+
module Mapping # :nodoc:
|
4
4
|
# Override the `ActionDispatch::Routing::Mapper::Mapping#app` method to
|
5
5
|
# be able to mount custom Dispatcher objects. Otherwise, the only way to
|
6
6
|
# point a dispatcher to business actions is to mount it as a Rack app
|
@@ -1,8 +1,12 @@
|
|
1
|
-
module Granite
|
2
|
-
|
1
|
+
module Granite
|
2
|
+
module ActionHelpers # :nodoc:
|
3
|
+
extend ActiveSupport::Concern
|
3
4
|
|
4
|
-
|
5
|
+
delegate :perform!, to: :subject
|
6
|
+
end
|
5
7
|
end
|
6
8
|
|
7
|
-
RSpec.configuration.define_derived_metadata(file_path: %r{spec/apq/actions/})
|
9
|
+
RSpec.configuration.define_derived_metadata(file_path: %r{spec/apq/actions/}) do |metadata|
|
10
|
+
metadata[:type] ||= :granite_action
|
11
|
+
end
|
8
12
|
RSpec.configuration.include Granite::ActionHelpers, type: :granite_action
|
@@ -1,54 +1,59 @@
|
|
1
|
-
module Granite
|
2
|
-
|
3
|
-
|
1
|
+
module Granite
|
2
|
+
module ProjectorHelpers # :nodoc:
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include RSpec::Rails::ControllerExampleGroup
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
included do
|
7
|
+
before { Granite::Routing::Declarer.dispatcher.unmemoize_all }
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
module ClassMethods # :nodoc:
|
11
|
+
def draw_routes(&block)
|
12
|
+
before(:all) do
|
13
|
+
routes = Rails.application.routes
|
14
|
+
routes.disable_clear_and_finalize = true
|
15
|
+
routes.draw(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
after(:all) do
|
19
|
+
Rails.application.routes.disable_clear_and_finalize = false
|
20
|
+
Rails.application.reload_routes!
|
21
|
+
Rails.application.routes.routes.clear_cache!
|
22
|
+
end
|
15
23
|
end
|
16
24
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
25
|
+
def projector(&block)
|
26
|
+
setup_controller
|
27
|
+
setup_view_context
|
28
|
+
let(:projector_class, &block)
|
29
|
+
let(:projector) { controller.projector }
|
21
30
|
end
|
22
|
-
end
|
23
31
|
|
24
|
-
|
25
|
-
setup_controller
|
26
|
-
setup_view_context
|
27
|
-
let(:projector_class, &block)
|
28
|
-
let(:projector) { controller.projector }
|
29
|
-
end
|
32
|
+
private
|
30
33
|
|
31
|
-
|
34
|
+
def setup_controller
|
35
|
+
define_method :setup_controller_request_and_response do
|
36
|
+
@controller ||= projector_class.controller_class.new
|
37
|
+
super()
|
38
|
+
end
|
39
|
+
end
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
super()
|
41
|
+
def setup_view_context
|
42
|
+
before { Granite.view_context = controller.view_context }
|
43
|
+
after { Granite.view_context = nil }
|
37
44
|
end
|
38
45
|
end
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
# Overrides ActionController::TestCase::Behavior#process to include granite_action and granite_projector
|
48
|
+
def process(action, **options)
|
49
|
+
projector_params = { granite_action: projector_class.action_name,
|
50
|
+
granite_projector: projector_class.projector_name }
|
51
|
+
super(action, **options, params: projector_params.reverse_merge(options[:params] || {}))
|
43
52
|
end
|
44
53
|
end
|
45
|
-
|
46
|
-
# Overrides ActionController::TestCase::Behavior#process to include granite_action and granite_projector
|
47
|
-
def process(action, **options)
|
48
|
-
projector_params = {granite_action: projector_class.action_name, granite_projector: projector_class.projector_name}
|
49
|
-
super(action, **options, params: projector_params.reverse_merge(options[:params] || {}))
|
50
|
-
end
|
51
54
|
end
|
52
55
|
|
53
|
-
RSpec.configuration.define_derived_metadata(file_path: %r{spec/apq/projectors/})
|
56
|
+
RSpec.configuration.define_derived_metadata(file_path: %r{spec/apq/projectors/}) do |metadata|
|
57
|
+
metadata[:type] ||= :granite_projector
|
58
|
+
end
|
54
59
|
RSpec.configuration.include Granite::ProjectorHelpers, type: :granite_projector
|
@@ -38,13 +38,9 @@ RSpec::Matchers.define :raise_validation_error do
|
|
38
38
|
expected
|
39
39
|
end
|
40
40
|
|
41
|
-
failure_message
|
42
|
-
"expected to #{description}"
|
43
|
-
end
|
41
|
+
failure_message { "expected to #{description}" }
|
44
42
|
|
45
|
-
failure_message_when_negated
|
46
|
-
"expected not to #{description}"
|
47
|
-
end
|
43
|
+
failure_message_when_negated { "expected not to #{description}" }
|
48
44
|
|
49
45
|
supports_block_expectations
|
50
46
|
end
|
@@ -16,13 +16,13 @@
|
|
16
16
|
# ```ruby
|
17
17
|
# # assuming subject is business action
|
18
18
|
# it { is_expected.to satisfy_preconditions }
|
19
|
-
# it { is_expected.not_to satisfy_preconditions.with_message('
|
20
|
-
# it { is_expected.not_to satisfy_preconditions.with_messages(/^
|
21
|
-
# it { is_expected.not_to satisfy_preconditions.with_message_of_kind(:
|
22
|
-
# it { is_expected.not_to satisfy_preconditions.with_messages_of_kinds(:
|
19
|
+
# it { is_expected.not_to satisfy_preconditions.with_message('Form has not been signed') }
|
20
|
+
# it { is_expected.not_to satisfy_preconditions.with_messages(/^Form has not been signed by/', 'Signature required') }
|
21
|
+
# it { is_expected.not_to satisfy_preconditions.with_message_of_kind(:portfolio_needed) }
|
22
|
+
# it { is_expected.not_to satisfy_preconditions.with_messages_of_kinds(:portfolio_needed, :relevant_education_needed) }
|
23
23
|
# ```
|
24
24
|
#
|
25
|
-
RSpec::Matchers.define :satisfy_preconditions do
|
25
|
+
RSpec::Matchers.define :satisfy_preconditions do # rubocop:disable Metrics/BlockLength
|
26
26
|
chain(:with_message) do |message|
|
27
27
|
@expected_messages = [message]
|
28
28
|
end
|
@@ -44,7 +44,7 @@ RSpec::Matchers.define :satisfy_preconditions do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
match do |object|
|
47
|
-
|
47
|
+
raise '"with_messages" method chain is not supported for positive matcher' if @expected_messages
|
48
48
|
|
49
49
|
object.satisfy_preconditions?
|
50
50
|
end
|
data/lib/granite/translations.rb
CHANGED
data/lib/granite/version.rb
CHANGED
data/lib/granite.rb
CHANGED
@@ -6,7 +6,7 @@ require 'granite/version'
|
|
6
6
|
require 'granite/config'
|
7
7
|
require 'granite/context'
|
8
8
|
|
9
|
-
module Granite
|
9
|
+
module Granite # :nodoc:
|
10
10
|
def self.config
|
11
11
|
Granite::Config.instance
|
12
12
|
end
|
@@ -15,6 +15,10 @@ module Granite
|
|
15
15
|
Granite::Context.instance
|
16
16
|
end
|
17
17
|
|
18
|
+
def self.deprecator
|
19
|
+
@deprecator ||= ActiveSupport::Deprecation.new('1.0.0', 'Granite')
|
20
|
+
end
|
21
|
+
|
18
22
|
singleton_class.delegate(*Granite::Config.delegated, to: :config)
|
19
23
|
singleton_class.delegate(*Granite::Context.delegated, to: :context)
|
20
24
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
# The original code is from https://github.com/rubocop-hq/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
|
4
2
|
# See https://github.com/rubocop-hq/rubocop-rspec/blob/master/MIT-LICENSE.md
|
5
3
|
module RuboCop
|
@@ -11,7 +9,7 @@ module RuboCop
|
|
11
9
|
path = CONFIG_DEFAULT.to_s
|
12
10
|
hash = ConfigLoader.load_file(path)
|
13
11
|
config = Config.new(hash, path).tap(&:make_excludes_absolute)
|
14
|
-
|
12
|
+
Rails.logger.debug { "configuration from #{path}" } if ConfigLoader.debug?
|
15
13
|
config = ConfigLoader.merge_with_default(config, path)
|
16
14
|
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
17
15
|
end
|
data/lib/rubocop/granite.rb
CHANGED
data/lib/rubocop-granite.rb
CHANGED
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.17.
|
4
|
+
version: 0.17.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Toptal Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -31,39 +31,39 @@ dependencies:
|
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '7.2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: activesupport
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: '6.0'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '7.2'
|
40
43
|
type: :runtime
|
41
44
|
prerelease: false
|
42
45
|
version_requirements: !ruby/object:Gem::Requirement
|
43
46
|
requirements:
|
44
47
|
- - ">="
|
45
48
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
49
|
+
version: '6.0'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '7.2'
|
47
53
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
54
|
+
name: granite-form
|
49
55
|
requirement: !ruby/object:Gem::Requirement
|
50
56
|
requirements:
|
51
57
|
- - ">="
|
52
58
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
54
|
-
- - "<"
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version: '7.2'
|
59
|
+
version: 0.3.0
|
57
60
|
type: :runtime
|
58
61
|
prerelease: false
|
59
62
|
version_requirements: !ruby/object:Gem::Requirement
|
60
63
|
requirements:
|
61
64
|
- - ">="
|
62
65
|
- !ruby/object:Gem::Version
|
63
|
-
version:
|
64
|
-
- - "<"
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '7.2'
|
66
|
+
version: 0.3.0
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: memoist
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,75 +233,75 @@ dependencies:
|
|
233
233
|
- !ruby/object:Gem::Version
|
234
234
|
version: '1.2'
|
235
235
|
- !ruby/object:Gem::Dependency
|
236
|
-
name:
|
236
|
+
name: rspec_junit_formatter
|
237
237
|
requirement: !ruby/object:Gem::Requirement
|
238
238
|
requirements:
|
239
239
|
- - "~>"
|
240
240
|
- !ruby/object:Gem::Version
|
241
|
-
version: '
|
241
|
+
version: '0.2'
|
242
242
|
type: :development
|
243
243
|
prerelease: false
|
244
244
|
version_requirements: !ruby/object:Gem::Requirement
|
245
245
|
requirements:
|
246
246
|
- - "~>"
|
247
247
|
- !ruby/object:Gem::Version
|
248
|
-
version: '
|
248
|
+
version: '0.2'
|
249
249
|
- !ruby/object:Gem::Dependency
|
250
|
-
name:
|
250
|
+
name: rspec-rails
|
251
251
|
requirement: !ruby/object:Gem::Requirement
|
252
252
|
requirements:
|
253
253
|
- - "~>"
|
254
254
|
- !ruby/object:Gem::Version
|
255
|
-
version: '0
|
255
|
+
version: '6.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
|
262
|
+
version: '6.0'
|
263
263
|
- !ruby/object:Gem::Dependency
|
264
264
|
name: rubocop
|
265
265
|
requirement: !ruby/object:Gem::Requirement
|
266
266
|
requirements:
|
267
267
|
- - "~>"
|
268
268
|
- !ruby/object:Gem::Version
|
269
|
-
version:
|
269
|
+
version: 1.63.5
|
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:
|
276
|
+
version: 1.63.5
|
277
277
|
- !ruby/object:Gem::Dependency
|
278
278
|
name: rubocop-rails
|
279
279
|
requirement: !ruby/object:Gem::Requirement
|
280
280
|
requirements:
|
281
281
|
- - "~>"
|
282
282
|
- !ruby/object:Gem::Version
|
283
|
-
version:
|
283
|
+
version: 2.25.0
|
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:
|
290
|
+
version: 2.25.0
|
291
291
|
- !ruby/object:Gem::Dependency
|
292
292
|
name: rubocop-rspec
|
293
293
|
requirement: !ruby/object:Gem::Requirement
|
294
294
|
requirements:
|
295
295
|
- - "~>"
|
296
296
|
- !ruby/object:Gem::Version
|
297
|
-
version:
|
297
|
+
version: 2.29.2
|
298
298
|
type: :development
|
299
299
|
prerelease: false
|
300
300
|
version_requirements: !ruby/object:Gem::Requirement
|
301
301
|
requirements:
|
302
302
|
- - "~>"
|
303
303
|
- !ruby/object:Gem::Version
|
304
|
-
version:
|
304
|
+
version: 2.29.2
|
305
305
|
- !ruby/object:Gem::Dependency
|
306
306
|
name: simplecov
|
307
307
|
requirement: !ruby/object:Gem::Requirement
|
@@ -392,7 +392,8 @@ files:
|
|
392
392
|
homepage: https://github.com/toptal/granite
|
393
393
|
licenses:
|
394
394
|
- MIT
|
395
|
-
metadata:
|
395
|
+
metadata:
|
396
|
+
rubygems_mfa_required: 'true'
|
396
397
|
post_install_message:
|
397
398
|
rdoc_options: []
|
398
399
|
require_paths:
|
@@ -401,14 +402,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
401
402
|
requirements:
|
402
403
|
- - ">="
|
403
404
|
- !ruby/object:Gem::Version
|
404
|
-
version: '2.
|
405
|
+
version: '2.6'
|
405
406
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
406
407
|
requirements:
|
407
408
|
- - ">="
|
408
409
|
- !ruby/object:Gem::Version
|
409
410
|
version: '0'
|
410
411
|
requirements: []
|
411
|
-
rubygems_version: 3.
|
412
|
+
rubygems_version: 3.5.10
|
412
413
|
signing_key:
|
413
414
|
specification_version: 4
|
414
415
|
summary: Another business actions architecture for Rails apps
|