gl_command 1.3.0 → 2.0.0
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/README.md +152 -11
- data/lib/gl_command/callable.rb +21 -2
- data/lib/gl_command/context.rb +6 -3
- data/lib/gl_command/rspec/matchers.rb +113 -0
- data/lib/gl_command/rspec.rb +18 -0
- data/lib/gl_command/validatable.rb +2 -1
- data/lib/gl_command/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5c1d353b0428b6aa32adf96b5962256b415dfacc45116d3e4a21ea8ca345de8e
|
|
4
|
+
data.tar.gz: f8056f5711ef8ffdfafd3678fd25c05fa1879f2893f1d9acecaa9a3880565d7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8229ae95a48c6b5fc83fbeb647d604666be82cc2e35b08d294c6c8c4c7e44ec4c52d40f520ead9005d38edeee0aab9fc03f0db9e637271b2fd1dbd98619efd21
|
|
7
|
+
data.tar.gz: 678f19f03349988f5a033eeb1f5cff6acb846e0c2b5eea744b7493e0419232d7e0e56f2b4684c9857f0d5e78d7119b9147bef86cf0b5ac642056f9b67365cd8d
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# GLCommand
|
|
2
2
|
|
|
3
|
-
`GLCommand` is a way to encapsulate business logic.
|
|
3
|
+
`GLCommand` is a way to encapsulate business logic and standardize error handling.
|
|
4
4
|
|
|
5
5
|
Calling a command returns a `GLCommand::Context` which has these properties:
|
|
6
6
|
|
|
@@ -10,6 +10,22 @@ Calling a command returns a `GLCommand::Context` which has these properties:
|
|
|
10
10
|
- `full_error_message` - which renders a string from the error, or can be set explicitly (used to show a legible error to the user).
|
|
11
11
|
- `success` - `true` if the command executed without an error (false if there is an `error`)
|
|
12
12
|
|
|
13
|
+
# Table of contents
|
|
14
|
+
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Using GLCommand](#using-glcommand)
|
|
17
|
+
- [Success/Failure](#successfailure)
|
|
18
|
+
- [Displaying errors (use `full_error_message`)](#displaying-errors-use-full_error_message)
|
|
19
|
+
- [stop_and_fail!](#stop_and_fail)
|
|
20
|
+
- [Validations](#validations)
|
|
21
|
+
- [Best practices for error handling](#best-practices-for-error-handling)
|
|
22
|
+
- [GLExceptionNotifier](#glexceptionnotifier)
|
|
23
|
+
- [Chainable](#chainable)
|
|
24
|
+
- [Testing `GLCommand`s](#testing-glcommands)
|
|
25
|
+
- [Stubbing with `build_context`](#stubbing-with-build_context)
|
|
26
|
+
- [Rspec matchers](#rspec-matchers)
|
|
27
|
+
- [Publishing the gem to Rubygems](#publishing-the-gem-to-rubygems)
|
|
28
|
+
|
|
13
29
|
|
|
14
30
|
## Installation
|
|
15
31
|
|
|
@@ -50,7 +66,7 @@ class SomeCommand < GLCommand::Callable
|
|
|
50
66
|
end
|
|
51
67
|
```
|
|
52
68
|
|
|
53
|
-
|
|
69
|
+
### Success/Failure
|
|
54
70
|
|
|
55
71
|
GLCommand context's are successful by default (`successful?` aliases `success?`).
|
|
56
72
|
|
|
@@ -70,13 +86,14 @@ Here are the ways of adding an error to a command:
|
|
|
70
86
|
|
|
71
87
|
If you invoke a command with `.call!` all of the above will raise an exception
|
|
72
88
|
|
|
73
|
-
If a command fails, it
|
|
89
|
+
If a command fails, it calls its `rollback` method before returning (even when invoked with `.call!`)
|
|
74
90
|
|
|
75
|
-
|
|
91
|
+
|
|
92
|
+
### Displaying errors (use `full_error_message`)
|
|
76
93
|
|
|
77
94
|
In addition to encapsulating business logic, GLCommand also standardizes error handling.
|
|
78
95
|
|
|
79
|
-
This means that rather than having to rescue errors in controllers,
|
|
96
|
+
This means that rather than having to rescue errors in controllers, just render the command's `full_error_message`
|
|
80
97
|
|
|
81
98
|
```ruby
|
|
82
99
|
result = GLCommand::Callable.call(params)
|
|
@@ -88,7 +105,7 @@ else
|
|
|
88
105
|
end
|
|
89
106
|
```
|
|
90
107
|
|
|
91
|
-
In general, use `context.full_error_message` to render errors.
|
|
108
|
+
In general, use `context.full_error_message` to render errors (rather than `context.error.message` which might not have the full error message text).
|
|
92
109
|
|
|
93
110
|
|
|
94
111
|
### `stop_and_fail!`
|
|
@@ -130,16 +147,45 @@ stop_and_fail!('An error message', no_notify: true) # GLExceptionNotifier is *no
|
|
|
130
147
|
|
|
131
148
|
### Validations
|
|
132
149
|
|
|
133
|
-
You can add validations to `GLCommand::Callable` and `GLCommand::Chainable`.
|
|
150
|
+
You can add validations to `GLCommand::Callable` and `GLCommand::Chainable`. They include `ActiveModel::Validations`, so you can use [Rails active record validations](https://guides.rubyonrails.org/active_record_validations.html).
|
|
151
|
+
|
|
152
|
+
If the validations fail, the command returns `success: false` without executing and if validations fail, `GLExceptionNotifier` is **not** called.
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
class ExampleCommand < GLCommand::Callable
|
|
156
|
+
validates :name, presence: true
|
|
157
|
+
validate :name_must_start_with_cool
|
|
158
|
+
|
|
159
|
+
def name_must_start_with_cool
|
|
160
|
+
return true unless name.start_with?('cool')
|
|
161
|
+
|
|
162
|
+
errors.add(:name, "Doesn't start with 'cool'")
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Best practices for error handling
|
|
134
168
|
|
|
135
|
-
|
|
169
|
+
#### Only add validation errors in validations
|
|
136
170
|
|
|
137
|
-
|
|
171
|
+
i.e. don't use `errors.add` in the `call` method. Use `stop_and_fail!` instead.
|
|
138
172
|
|
|
173
|
+
#### Prefer raising the original error
|
|
174
|
+
|
|
175
|
+
For example, if you want to raise a custom error message, don't rescue and then `stop_and_fail!('Some special error message')`. Do this instead:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
rescue StandardError => e
|
|
179
|
+
context.full_error_message = "Some special error message"
|
|
180
|
+
raise e
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
This will preserve the original error and stack trace, which makes it easier to debug and track down issues.
|
|
139
185
|
|
|
140
186
|
## GLExceptionNotifier
|
|
141
187
|
|
|
142
|
-
[
|
|
188
|
+
[GLExceptionNotifier](https://github.com/givelively/gl_exception_notifier) is Give Lively's wrapper for notify our error monitoring service (currently [Sentry](https://github.com/getsentry/sentry-ruby))
|
|
143
189
|
|
|
144
190
|
When a command fails `GLExceptionNotifier` is called, unless:
|
|
145
191
|
|
|
@@ -147,7 +193,7 @@ When a command fails `GLExceptionNotifier` is called, unless:
|
|
|
147
193
|
- The failure is a validation failure
|
|
148
194
|
- `stop_and_fail!` is called with `no_notify: true` - for example `stop_and_fail!('An error message', no_notify: true)`
|
|
149
195
|
|
|
150
|
-
**NOTE:** commands that invoke other commands with `call!` inherit the no_notify property of called command.
|
|
196
|
+
**NOTE:** commands that invoke other commands with `call!` inherit the `no_notify` property of the called command.
|
|
151
197
|
|
|
152
198
|
```ruby
|
|
153
199
|
class InteriorCommand < GLCommand::Callable
|
|
@@ -211,9 +257,104 @@ class SomeChain < GLCommand::Chainable
|
|
|
211
257
|
chain(:item)
|
|
212
258
|
end
|
|
213
259
|
end
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## RSpec Matchers
|
|
263
|
+
|
|
264
|
+
`GLCommand` comes with a set of RSpec matchers to make testing your command's interface declarative and simple.
|
|
265
|
+
|
|
266
|
+
### Setup
|
|
267
|
+
|
|
268
|
+
To enable the matchers, add the following line to your `spec/spec_helper.rb` or `spec/rails_helper.rb`:
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
require 'gl_command/rspec'
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
This will automatically include the necessary matchers and configure RSpec for specs marked with `type: :command`.
|
|
275
|
+
|
|
276
|
+
### Usage
|
|
277
|
+
|
|
278
|
+
You can now test your command's interface like this:
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
# spec/commands/some_command_spec.rb
|
|
282
|
+
|
|
283
|
+
RSpec.describe SomeCommand, type: :command do
|
|
284
|
+
describe 'interface' do
|
|
285
|
+
it { is_expected.to require(:user).being(User) }
|
|
286
|
+
it { is_expected.to allow(:subject) }
|
|
287
|
+
it { is_expected.to returns(:message) }
|
|
288
|
+
it { is_expected.not_to require(:other_thing) }
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Note:** The `.being(ClassName)` chain is supported for `require` and `allow` but not for `return`, as `GLCommand` does not store type information for return values.
|
|
294
|
+
|
|
295
|
+
## Testing `GLCommand`s
|
|
296
|
+
|
|
297
|
+
Give Lively uses Rspec for testing, so this section assumes you're using RSpec.
|
|
298
|
+
|
|
299
|
+
### Stubbing with `build_context`
|
|
300
|
+
|
|
301
|
+
If you need the response from a command (typically because you are stubbing it), use the `build_context` method to create a context with the desired response. This has the advantage of using the actual Command's `requires`, `allows`, and `returns` methods.
|
|
302
|
+
|
|
303
|
+
```ruby
|
|
304
|
+
class SomeCommand < GLCommand::Callable
|
|
305
|
+
requires user: User
|
|
306
|
+
allows :subject
|
|
307
|
+
returns :message
|
|
308
|
+
|
|
309
|
+
def call
|
|
310
|
+
user.update!(subject:)
|
|
311
|
+
context.message = "Hello - user subject: #{user.subject}"
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
result = SomeCommand.build_context(user: User.new, message: "Hello!")
|
|
316
|
+
result.success? # true
|
|
317
|
+
result.full_error_message # nil
|
|
318
|
+
result_error = SomeCommand.build_context(error: "invalid")
|
|
319
|
+
result_error.success? # false
|
|
320
|
+
result_error.full_error_message # "invalid"
|
|
214
321
|
|
|
322
|
+
SomeCommand.build_context(other_thing: "some other thing")
|
|
323
|
+
# ArgumentError: Unknown argument or return attribute: 'other_thing'
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### RSpec Matchers
|
|
327
|
+
|
|
328
|
+
`GLCommand` comes with a set of RSpec matchers to make testing your command's interface declarative and simple.
|
|
329
|
+
|
|
330
|
+
### Setup
|
|
331
|
+
|
|
332
|
+
To enable the matchers, add the following line to your `spec/spec_helper.rb` or `spec/rails_helper.rb`:
|
|
333
|
+
|
|
334
|
+
```ruby
|
|
335
|
+
require 'gl_command/rspec'
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
This will automatically include the necessary matchers and configure RSpec for specs marked with `type: :command`.
|
|
339
|
+
|
|
340
|
+
### Usage
|
|
341
|
+
|
|
342
|
+
You can now test your command's interface like this:
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
# spec/commands/some_command_spec.rb
|
|
346
|
+
|
|
347
|
+
RSpec.describe SomeCommand, type: :command do
|
|
348
|
+
describe 'interface' do
|
|
349
|
+
it { is_expected.to require(:user).being(User) }
|
|
350
|
+
it { is_expected.to allow(:subject) }
|
|
351
|
+
it { is_expected.to returns(:message) }
|
|
352
|
+
it { is_expected.not_to require(:other_thing) }
|
|
353
|
+
end
|
|
354
|
+
end
|
|
215
355
|
```
|
|
216
356
|
|
|
357
|
+
**Note:** The `.being(ClassName)` chain is supported for `require` and `allow` but not for `return`, as `GLCommand` does not store type information for return values.
|
|
217
358
|
|
|
218
359
|
## Publishing the gem to Rubygems
|
|
219
360
|
|
data/lib/gl_command/callable.rb
CHANGED
|
@@ -214,12 +214,15 @@ module GLCommand
|
|
|
214
214
|
raise ArgumentError, "unknown #{error_keys_str(unknown)}" if unknown.any?
|
|
215
215
|
|
|
216
216
|
# strong_attributes type checking
|
|
217
|
+
# type can be a class (e.g. String), a symbol naming a predicate method
|
|
218
|
+
# the value must answer truthily (e.g. :acts_as_syncable?), or an array of
|
|
219
|
+
# either (e.g. [User, AdminUser]), in which case the value may match any
|
|
217
220
|
self.class.requires.merge(self.class.allows).each do |arg, type|
|
|
218
|
-
next if type.nil? || args[arg]
|
|
221
|
+
next if type.nil? || Array(type).any? { |t| value_matches_type?(args[arg], t) }
|
|
219
222
|
# Validation skipped if allows and nil (but not if blank)
|
|
220
223
|
next if args[arg].nil? && self.class.allows.include?(arg)
|
|
221
224
|
|
|
222
|
-
raise GLCommand::ArgumentTypeError, ":#{arg} is not
|
|
225
|
+
raise GLCommand::ArgumentTypeError, ":#{arg} is not #{type_error_str(type)}"
|
|
223
226
|
end
|
|
224
227
|
end
|
|
225
228
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
@@ -227,5 +230,21 @@ module GLCommand
|
|
|
227
230
|
def error_keys_str(keys)
|
|
228
231
|
"keyword#{keys.count > 1 ? 's' : ''}: #{keys.map { |k| ":#{k}" }.join(', ')}"
|
|
229
232
|
end
|
|
233
|
+
|
|
234
|
+
# A type can be a class (checked with is_a?) or a symbol naming a predicate
|
|
235
|
+
# method the value must respond to and return truthy from
|
|
236
|
+
def value_matches_type?(value, type)
|
|
237
|
+
if type.is_a?(Symbol)
|
|
238
|
+
value.respond_to?(type) && value.public_send(type)
|
|
239
|
+
else
|
|
240
|
+
value.is_a?(type)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def type_error_str(type)
|
|
245
|
+
return "one of #{type.join(', ')}" if type.is_a?(Array)
|
|
246
|
+
|
|
247
|
+
type.is_a?(Symbol) ? type.to_s : "a #{type}"
|
|
248
|
+
end
|
|
230
249
|
end
|
|
231
250
|
end
|
data/lib/gl_command/context.rb
CHANGED
|
@@ -27,7 +27,7 @@ module GLCommand
|
|
|
27
27
|
|
|
28
28
|
# If someone calls #errors, they expect to get the errors! Include the non-validation error, if it exists
|
|
29
29
|
def errors
|
|
30
|
-
current_errors&.add(:base,
|
|
30
|
+
current_errors&.add(:base, full_error_message) if add_command_error?
|
|
31
31
|
current_errors
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -126,7 +126,10 @@ module GLCommand
|
|
|
126
126
|
private
|
|
127
127
|
|
|
128
128
|
def current_errors
|
|
129
|
-
@callable
|
|
129
|
+
return @callable.errors if defined?(@callable)
|
|
130
|
+
|
|
131
|
+
# @standalone_errors only is instantiated when you use build_context
|
|
132
|
+
(@standalone_errors ||= ActiveModel::Errors.new(self))
|
|
130
133
|
end
|
|
131
134
|
|
|
132
135
|
def add_command_error?
|
|
@@ -136,7 +139,7 @@ module GLCommand
|
|
|
136
139
|
|
|
137
140
|
# Add command error unless the existing error is a validation error or there's already a command error
|
|
138
141
|
@error&.class != ActiveRecord::RecordInvalid &&
|
|
139
|
-
current_errors.full_messages.none? { |err| err
|
|
142
|
+
current_errors.full_messages.none? { |err| err == @error.message }
|
|
140
143
|
end
|
|
141
144
|
|
|
142
145
|
def exception?(passed_error)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is intended to be required by lib/gl_command/rspec.rb
|
|
4
|
+
|
|
5
|
+
module GLCommand
|
|
6
|
+
module Matchers
|
|
7
|
+
# Base matcher for `requires` and `allows`, which store a Hash of { attribute: Type }.
|
|
8
|
+
class CommandArgumentMatcher
|
|
9
|
+
def initialize(attribute)
|
|
10
|
+
@attribute = attribute
|
|
11
|
+
@expected_type = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def being(expected_type)
|
|
15
|
+
@expected_type = expected_type
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def matches?(command_class)
|
|
20
|
+
@command_class = command_class.is_a?(Class) ? command_class : command_class.class
|
|
21
|
+
attributes = @command_class.public_send(scope)
|
|
22
|
+
|
|
23
|
+
return false unless attributes.key?(@attribute)
|
|
24
|
+
return true if @expected_type.nil? # Type check not requested
|
|
25
|
+
|
|
26
|
+
attributes[@attribute] == @expected_type
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def description
|
|
30
|
+
"#{action} argument `#{@attribute}`"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def failure_message
|
|
34
|
+
message = "Expected #{@command_class.name} to #{action} `#{@attribute}`"
|
|
35
|
+
message += " of type `#{@expected_type}`" if @expected_type
|
|
36
|
+
message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def failure_message_when_negated
|
|
40
|
+
message = "Expected #{@command_class.name} not to #{action} `#{@attribute}`"
|
|
41
|
+
message += " of type `#{@expected_type}`" if @expected_type
|
|
42
|
+
message
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class RequireArgumentMatcher < CommandArgumentMatcher
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def scope = :requires
|
|
50
|
+
def action = 'require'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class AllowArgumentMatcher < CommandArgumentMatcher
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def scope = :allows
|
|
57
|
+
def action = 'allow'
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Specific matcher for `returns`, which only stores an Array of keys.
|
|
61
|
+
class ReturnAttributeMatcher
|
|
62
|
+
def initialize(attribute)
|
|
63
|
+
@attribute = attribute
|
|
64
|
+
@type_check_attempted = false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def being(_expected_type)
|
|
68
|
+
@type_check_attempted = true
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# rubocop:disable Layout/LineLength
|
|
73
|
+
def matches?(command_class)
|
|
74
|
+
@command_class = command_class.is_a?(Class) ? command_class : command_class.class
|
|
75
|
+
|
|
76
|
+
if @type_check_attempted
|
|
77
|
+
@failure_reason = 'GLCommand::Callable does not store types for `returns`, so `.being()` cannot be used.'
|
|
78
|
+
return false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
@command_class.returns.include?(@attribute)
|
|
82
|
+
end
|
|
83
|
+
# rubocop:enable Layout/LineLength
|
|
84
|
+
|
|
85
|
+
def description
|
|
86
|
+
"return attribute `#{@attribute}`"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def failure_message
|
|
90
|
+
return @failure_reason if @failure_reason
|
|
91
|
+
|
|
92
|
+
"Expected #{@command_class.name} to return `#{@attribute}`"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def failure_message_when_negated
|
|
96
|
+
"Expected #{@command_class.name} not to return `#{@attribute}`"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Helper methods to provide the clean syntax in specs
|
|
101
|
+
def require(attribute)
|
|
102
|
+
RequireArgumentMatcher.new(attribute)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def allow(attribute)
|
|
106
|
+
AllowArgumentMatcher.new(attribute)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def returns(attribute)
|
|
110
|
+
ReturnAttributeMatcher.new(attribute)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'gl_command/rspec/matchers'
|
|
4
|
+
|
|
5
|
+
# A shared context to automatically set the subject of a spec to the
|
|
6
|
+
# described class. This allows `is_expected` to work directly on the
|
|
7
|
+
# command class in specs with `type: :command`.
|
|
8
|
+
RSpec.shared_context 'GLCommand::Command subject' do
|
|
9
|
+
subject { described_class }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
RSpec.configure do |config|
|
|
13
|
+
# Makes the matcher methods (require, allow, returns) available in these specs.
|
|
14
|
+
config.include GLCommand::Matchers, type: :command
|
|
15
|
+
|
|
16
|
+
# Allows `is_expected` to work directly on the command class.
|
|
17
|
+
config.include_context 'GLCommand::Command subject', type: :command
|
|
18
|
+
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'active_support/concern'
|
|
4
4
|
require 'active_model'
|
|
5
|
+
require 'active_record'
|
|
5
6
|
|
|
6
7
|
module GLCommand
|
|
7
8
|
module Validatable
|
|
@@ -12,7 +13,7 @@ module GLCommand
|
|
|
12
13
|
include ActiveModel::Validations
|
|
13
14
|
|
|
14
15
|
class_methods do
|
|
15
|
-
|
|
16
|
+
define_method(:i18n_scope) do
|
|
16
17
|
:activerecord
|
|
17
18
|
end
|
|
18
19
|
end
|
data/lib/gl_command/version.rb
CHANGED
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:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Give Lively
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-07-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -54,6 +54,8 @@ files:
|
|
|
54
54
|
- lib/gl_command/chainable_context.rb
|
|
55
55
|
- lib/gl_command/context.rb
|
|
56
56
|
- lib/gl_command/context_inspect.rb
|
|
57
|
+
- lib/gl_command/rspec.rb
|
|
58
|
+
- lib/gl_command/rspec/matchers.rb
|
|
57
59
|
- lib/gl_command/validatable.rb
|
|
58
60
|
- lib/gl_command/version.rb
|
|
59
61
|
homepage: https://github.com/givelively/gl_command
|
|
@@ -76,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
76
78
|
- !ruby/object:Gem::Version
|
|
77
79
|
version: '0'
|
|
78
80
|
requirements: []
|
|
79
|
-
rubygems_version: 3.
|
|
81
|
+
rubygems_version: 3.5.22
|
|
80
82
|
signing_key:
|
|
81
83
|
specification_version: 4
|
|
82
84
|
summary: Give Lively Commands
|