gl_command 1.0.1 → 1.1.1

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: 11a5d5ab9dd4a28700cb671153c1a757612f5b735194a28ad22f8be660a09250
4
- data.tar.gz: a3a351134af335563ee6e970d5920d08e52f2b4375cef1c8adc87e555bd1e64f
3
+ metadata.gz: 2c64386ffafec990d01604c12482b0cf2deb8b4caff95c638d9d4e8835c4cb92
4
+ data.tar.gz: 9a58f0b30039b493382f01d22fb8cc2c8d6950af71f16ec3b4e708a776e78af9
5
5
  SHA512:
6
- metadata.gz: 4344a62dca3bccad299425f9d22db05ca7e3062518c0f4a0c3b1be2d3708de8ccb3d310380c5a4eb73b515a21c4866c8b3385f9ee18c23e9389fd49e9afb8803
7
- data.tar.gz: '08c842fe87ac92bc793fad76498e0b12ecc772a8d5385fea2d5c34670115ba40a17545227e572a5ce1bcee9b3bc6c52f2e70f59e45a8755a871b93ebe3d344a2'
6
+ metadata.gz: 126e275c0bd65be3fb7fe1ead77e283231a158359b1c95ab00d691e010287f41b397a97a9202de316ba921313b1df66c59e76b4f5e13d62d4130d762aba6f803
7
+ data.tar.gz: 728454632aa41f5b740b4f3eaf97c85ee8022857ac349ca86bfa0d655687fc6b402b7501629e580c3ed3c2b87b621a56a11333a95f3239d8ec0095901bb0e311
@@ -6,7 +6,7 @@ require 'gl_command/validatable'
6
6
 
7
7
  module GLCommand
8
8
  class Callable
9
- DEFAULT_OPTS = { raise_errors: false, skip_unknown_parameters: true }.freeze
9
+ DEFAULT_OPTS = { raise_errors: false, skip_unknown_parameters: true, in_chain: false }.freeze
10
10
  RESERVED_WORDS = (DEFAULT_OPTS.keys + GLCommand::ChainableContext.reserved_words).sort.freeze
11
11
 
12
12
  class << self
@@ -25,7 +25,8 @@ module GLCommand
25
25
 
26
26
  # DEFAULT_OPTS contains skip_unknown_parameters: true - so it raises on call
27
27
  # (rather than in context initialize) to make errors more legible
28
- opts = DEFAULT_OPTS.merge(raise_errors: args.delete(:raise_errors)).compact
28
+ opts = DEFAULT_OPTS.merge(raise_errors: args.delete(:raise_errors),
29
+ in_chain: args.delete(:in_chain)).compact
29
30
  # args are passed in in perform_call(args) so that invalid args raise in a legible place
30
31
  new(build_context(**args.merge(opts))).perform_call(args)
31
32
  end
@@ -34,9 +35,13 @@ module GLCommand
34
35
  call(*posargs, **args.merge(raise_errors: true))
35
36
  end
36
37
 
37
- def build_context(raise_errors: false, skip_unknown_parameters: false,
38
+ # error can be passed to build context, useful for stubbing in tests
39
+ def build_context(raise_errors: false, skip_unknown_parameters: false, error: nil,
38
40
  **arguments_and_returns)
39
- context_class.new(self, raise_errors:, skip_unknown_parameters:, **arguments_and_returns)
41
+ new_context = context_class.new(self, raise_errors:, skip_unknown_parameters:,
42
+ **arguments_and_returns)
43
+ new_context.error = error if error.present?
44
+ new_context
40
45
  end
41
46
 
42
47
  def requires(*attributes, **strong_attributes)
@@ -70,7 +75,7 @@ module GLCommand
70
75
  (arguments + returns).uniq
71
76
  end
72
77
 
73
- # Used internally by GLCommand (probably don't reference them in your own GLCommands)
78
+ # Used internally by GLCommand (probably don't reference in your own GLCommands)
74
79
  # is true in GLCommand::Chainable
75
80
  def chain?
76
81
  false
@@ -106,7 +111,9 @@ module GLCommand
106
111
 
107
112
  def perform_call(args)
108
113
  raise_for_invalid_args!(**args)
114
+ instrument_command(:before_call)
109
115
  call_with_callbacks
116
+ instrument_command(:after_call)
110
117
  raise_unless_chained_or_skipped if self.class.chain? # defined in GLCommand::Chainable
111
118
  context.failure? ? handle_failure : context
112
119
  rescue StandardError => e
@@ -133,6 +140,11 @@ module GLCommand
133
140
 
134
141
  private
135
142
 
143
+ # trigger: [:before_call, :after_call, :before_rollback]
144
+ def instrument_command(trigger)
145
+ # Override where gem is used if you want to instrument commands
146
+ end
147
+
136
148
  # rubocop:disable Metrics/AbcSize
137
149
  def handle_failure(e = nil)
138
150
  context.error ||= e
@@ -159,9 +171,7 @@ module GLCommand
159
171
  rescue GLCommand::CommandNoNotifyError
160
172
  raise context.error # makes CommandNoNotifyError the cause
161
173
  end
162
- # rubocop:enable Metrics/AbcSize
163
174
 
164
- # rubocop:disable Metrics/AbcSize
165
175
  def call_with_callbacks
166
176
  GLExceptionNotifier.breadcrumbs(data: { context: context.inspect }, message: self.class.to_s)
167
177
  validate_validatable! # defined in GLCommand::Validatable
@@ -186,6 +196,8 @@ module GLCommand
186
196
  def call_rollbacks
187
197
  return if defined?(@rolled_back) # Not sure this is required
188
198
 
199
+ instrument_command(:before_rollback)
200
+
189
201
  @rolled_back = true
190
202
 
191
203
  chain_rollback if self.class.chain? # defined in GLCommand::Chainable
@@ -41,7 +41,7 @@ module GLCommand
41
41
 
42
42
  commands.map do |command|
43
43
  cargs = context.chain_arguments_and_returns.slice(*command.arguments)
44
- .merge(context.opts_hash)
44
+ .merge(context.opts_hash).merge(in_chain: true)
45
45
 
46
46
  result = command.call(**cargs)
47
47
  context.assign_parameters(skip_unknown_parameters: true, **result.returns)
@@ -7,9 +7,10 @@ require 'active_support/core_ext/module'
7
7
  module GLCommand
8
8
  class Context
9
9
  def initialize(klass, raise_errors: false, skip_unknown_parameters: false,
10
- **arguments_and_returns)
10
+ in_chain: false, **arguments_and_returns)
11
11
  @klass = klass
12
12
  @raise_errors = raise_errors.nil? ? false : raise_errors
13
+ @in_chain = in_chain
13
14
  @klass.arguments_and_returns.each { |key| singleton_class.class_eval { attr_accessor key } }
14
15
  initialize_chain_context(**arguments_and_returns) if chain?
15
16
  assign_parameters(skip_unknown_parameters:, **arguments_and_returns)
@@ -24,12 +25,21 @@ module GLCommand
24
25
  attr_reader :klass, :error
25
26
  attr_writer :full_error_message
26
27
 
27
- delegate :errors, to: :@callable, allow_nil: true
28
+ # If someone calls errors on a context, they expect to get the errors!
29
+ # Make that work, but also try to make it clear that they probably shouldn't be using that for presentation
30
+ def errors
31
+ current_errors&.add(:base, "full_error_message: #{full_error_message}") if @failure && current_errors.blank?
32
+ current_errors
33
+ end
28
34
 
29
35
  def chain?
30
36
  false
31
37
  end
32
38
 
39
+ def in_chain?
40
+ @in_chain
41
+ end
42
+
33
43
  def returns
34
44
  @klass.returns.index_with { |rattr| send(rattr) }
35
45
  end
@@ -43,7 +53,7 @@ module GLCommand
43
53
  end
44
54
 
45
55
  def failure?
46
- @failure || errors.present? || @full_error_message.present? || false
56
+ @failure || current_errors.present? || @full_error_message.present? || false
47
57
  end
48
58
 
49
59
  def success?
@@ -98,7 +108,7 @@ module GLCommand
98
108
  passed_error.is_a?(ActiveRecord::RecordInvalid) && defined?(passed_error.record.errors)
99
109
  # Return a new error if it's an error (rather than the class)
100
110
  passed_error.is_a?(Class) ? passed_error.new(@full_error_message) : passed_error
101
- elsif errors.present? # check for validation errors
111
+ elsif current_errors.present? # check for validation errors
102
112
  # Assign ActiveRecord::RecordInvalid if validatable error
103
113
  ActiveRecord::RecordInvalid.new(@callable)
104
114
  else
@@ -118,6 +128,10 @@ module GLCommand
118
128
 
119
129
  private
120
130
 
131
+ def current_errors
132
+ @callable&.errors
133
+ end
134
+
121
135
  def exception?(passed_error)
122
136
  passed_error.is_a?(Exception) ||
123
137
  (passed_error.respond_to?(:ancestors) && passed_error.ancestors.include?(Exception))
@@ -1,3 +1,3 @@
1
1
  module GLCommand
2
- VERSION = '1.0.1'.freeze
2
+ VERSION = '1.1.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gl_command
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Give Lively
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-19 00:00:00.000000000 Z
11
+ date: 2024-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord