service_base 1.0.4 → 1.1.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/CHANGELOG.md +87 -0
- data/README.md +133 -50
- data/lib/service_base/rspec/service_support.rb +52 -15
- data/lib/service_base/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f709f1e0e410fab6ddd7be7497a63b157433a8137d29a315039bde500c181d4
|
4
|
+
data.tar.gz: 436d06c1d55ac4c3e4d5b803a370e26976201bc88c2c934de5ac43f89275b52d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2dc449665465e7952604be4700330eedd024681334df857caca45e471a7649bea92a1eaec4a526257d6c1d6d84a6ae30a08009d624f93b98b95085e88b4e266
|
7
|
+
data.tar.gz: fae721976b7ef7e82e2d66c18ca4718e5d25673148e98effcf41498d7bea351c52b7d7cbcb4029a13dac73e804f0f00a6c49786b2c067c080813e0e2d81b9ebd
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [1.1.0] - 2025-09-09
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- Support for parameter-less failure and success handlers in ServiceSupport test helpers
|
14
|
+
- Flexible block parameter handling that works with both `on.failure { |error| ... }` and `on.failure do ... end` patterns
|
15
|
+
- Comprehensive test coverage for parameter-less handler scenarios
|
16
|
+
- New helper methods in ServiceSupport for improved code organization
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
- Refactored ServiceSupport methods to use helper methods for better maintainability
|
20
|
+
- Enhanced ServiceSupport stubbing to automatically detect block parameter requirements
|
21
|
+
- Improved error handling in test stubs with fallback to parameter-less calls
|
22
|
+
|
23
|
+
### Technical Details
|
24
|
+
- ServiceSupport methods now use Ruby's `ArgumentError` rescue mechanism to detect block parameter compatibility
|
25
|
+
- `stub_service_success` and `stub_service_failure` automatically handle both parameterized and parameter-less blocks
|
26
|
+
- Test stubs try calling with parameters first, then fall back to parameter-less calls when blocks don't accept them
|
27
|
+
- This enables cleaner test code without requiring unused `|_|` parameters in failure handlers
|
28
|
+
|
29
|
+
## [1.0.4] - 2025-08-27
|
30
|
+
|
31
|
+
### Added
|
32
|
+
- Comprehensive test coverage achieving 100%
|
33
|
+
- GitHub Actions workflow for running tests
|
34
|
+
- GitHub Actions status badge to README
|
35
|
+
|
36
|
+
### Changed
|
37
|
+
- Improved README formatting and clarity
|
38
|
+
|
39
|
+
### Fixed
|
40
|
+
- GitHub Actions workflow compatibility with Rails 8.0+
|
41
|
+
|
42
|
+
## [1.0.3] - 2025-04-30
|
43
|
+
|
44
|
+
### Fixed
|
45
|
+
- ServiceSupport now properly yields success block values in stubbed services
|
46
|
+
|
47
|
+
## [1.0.2] - 2025-04-24
|
48
|
+
|
49
|
+
### Changed
|
50
|
+
- Improved constant namespacing to avoid need for global search with `::`
|
51
|
+
- Fixed generator issues for proper file creation
|
52
|
+
|
53
|
+
### Fixed
|
54
|
+
- Type generator now works correctly
|
55
|
+
- Generator template improvements
|
56
|
+
|
57
|
+
## [1.0.1] - 2025-04-02
|
58
|
+
|
59
|
+
### Changed
|
60
|
+
- Removed types and locale support to simplify the gem
|
61
|
+
- Improved namespacing - everything now properly namespaced to `ServiceBase::`
|
62
|
+
- Enhanced test coverage
|
63
|
+
|
64
|
+
### Removed
|
65
|
+
- Active Support dependency for lighter footprint
|
66
|
+
- Locale support functionality
|
67
|
+
- Custom types functionality
|
68
|
+
|
69
|
+
## [1.0.0] - 2025-04-01
|
70
|
+
|
71
|
+
### Added
|
72
|
+
- Initial release of ServiceBase gem
|
73
|
+
- Service Object pattern implementation with dry-rb integration
|
74
|
+
- Railway-oriented programming using dry-monads
|
75
|
+
- Type validation using dry-struct and dry-types
|
76
|
+
- ArgumentTypeAnnotations DSL for service arguments
|
77
|
+
- Service generators for Rails integration
|
78
|
+
- RSpec test helpers with ServiceSupport
|
79
|
+
- Comprehensive documentation and examples
|
80
|
+
|
81
|
+
### Features
|
82
|
+
- Base Service class with automatic type validation
|
83
|
+
- Result monad integration (Success/Failure)
|
84
|
+
- Service description and pretty-printing support
|
85
|
+
- Rails generators for ApplicationService and Type modules
|
86
|
+
- Test stubbing utilities for service success/failure scenarios
|
87
|
+
- Argument validation with descriptive error messages
|
data/README.md
CHANGED
@@ -1,10 +1,57 @@
|
|
1
1
|
# Service Base
|
2
2
|
|
3
|
-
|
3
|
+
[](https://github.com/kleinjm/service_base/actions/workflows/test.yml)
|
4
|
+
[](https://badge.fury.io/rb/service_base)
|
4
5
|
|
5
|
-
|
6
|
+
A powerful base service class for Ruby applications that implements the Service Object pattern with type-safe arguments and railway-oriented programming using dry-rb gems.
|
6
7
|
|
7
|
-
|
8
|
+
## ✨ Features
|
9
|
+
|
10
|
+
- 🚂 **Railway-oriented programming** with automatic error handling
|
11
|
+
- 🔒 **Type-safe arguments** with validation and coercion
|
12
|
+
- 📝 **Self-documenting** services with descriptions
|
13
|
+
- 🧪 **Test helpers** for easy mocking and stubbing
|
14
|
+
- ⚡ **Zero dependencies** - works standalone or with Rails
|
15
|
+
- 🛠️ **Rails generators** for quick setup
|
16
|
+
|
17
|
+
## Table of Contents
|
18
|
+
|
19
|
+
- [Quick Start](#quick-start)
|
20
|
+
- [Installation](#installation)
|
21
|
+
- [Service Pattern Overview](#service-pattern-overview)
|
22
|
+
- [Usage](#usage)
|
23
|
+
- [Arguments](#arguments)
|
24
|
+
- [Types](#types)
|
25
|
+
- [Transactions](#working-with-transactions)
|
26
|
+
- [Testing](#test-support)
|
27
|
+
- [Development](#development)
|
28
|
+
|
29
|
+
## Quick Start
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# Define a service
|
33
|
+
class User::CreateService < ApplicationService
|
34
|
+
description "Creates a new user with validation"
|
35
|
+
|
36
|
+
argument :name, Type::String, description: "User's full name"
|
37
|
+
argument :email, Type::String, description: "User's email address"
|
38
|
+
argument :age, Type::Integer, optional: true, description: "User's age"
|
39
|
+
|
40
|
+
def call
|
41
|
+
user = User.new(arguments)
|
42
|
+
return Failure("Invalid user data") unless user.valid?
|
43
|
+
|
44
|
+
user.save!
|
45
|
+
Success(user)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Use the service
|
50
|
+
User::CreateService.call(name: "John Doe", email: "john@example.com") do |on|
|
51
|
+
on.success { |user| redirect_to user_path(user) }
|
52
|
+
on.failure { |error| render json: { error: error }, status: 422 }
|
53
|
+
end
|
54
|
+
```
|
8
55
|
|
9
56
|
## Installation
|
10
57
|
|
@@ -36,14 +83,11 @@ class ApplicationService < ServiceBase::Service
|
|
36
83
|
end
|
37
84
|
```
|
38
85
|
|
39
|
-
|
86
|
+
## Service Pattern Overview
|
40
87
|
|
41
|
-
The
|
42
|
-
sequential steps. The service encapsulates those steps into a single class with a single action to trigger the steps.
|
88
|
+
The Service Object pattern is useful when you need to execute a set of sequential steps. The service encapsulates those steps into a single class with a single action to trigger the steps.
|
43
89
|
|
44
|
-
|
45
|
-
Pattern](https://fsharpforfunandprofit.com/posts/recipe-part2/) set up and enforced by the `Service` class,
|
46
|
-
which every service inherits from.
|
90
|
+
This gem implements a modified [Railway Pattern](https://fsharpforfunandprofit.com/posts/recipe-part2/) that's set up and enforced by the `ServiceBase::Service` class, which every service inherits from.
|
47
91
|
|
48
92
|
## Recommended resources
|
49
93
|
|
@@ -79,14 +123,48 @@ responsible for handling that logic.
|
|
79
123
|
|
80
124
|
One of the best ways to use the service pattern is for CRUD services - Ie. `ActiveRecordModel` + `::CreateService`, `::UpdateService`, `::DeleteService`. This avoids the use of callbacks, mystery guests, and unexpected side effects because all the steps to do a CRUD action are in one place and in order of execution.
|
81
125
|
|
82
|
-
##
|
126
|
+
## Usage
|
127
|
+
|
128
|
+
### Defining a Service
|
129
|
+
|
130
|
+
Every service must:
|
131
|
+
1. Inherit from `ApplicationService` (or `ServiceBase::Service` directly)
|
132
|
+
2. Define a `#call` method that returns `Success(value)` or `Failure(error)`
|
133
|
+
3. Use the `argument` DSL to define typed arguments
|
134
|
+
4. Optionally include a `description` for documentation
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
class User::UpdateService < ApplicationService
|
138
|
+
description "Updates user attributes with validation"
|
139
|
+
|
140
|
+
argument :user, Type::User, description: "User to update"
|
141
|
+
argument :attributes, Type::Hash, description: "Attributes to update"
|
142
|
+
argument :notify, Type::Boolean, default: true, description: "Send notification email"
|
143
|
+
|
144
|
+
def call
|
145
|
+
return Failure("User is archived") if user.archived?
|
146
|
+
|
147
|
+
user.assign_attributes(attributes)
|
148
|
+
return Failure(user.errors.full_messages) unless user.valid?
|
149
|
+
|
150
|
+
user.save!
|
151
|
+
send_notification if notify
|
152
|
+
Success(user)
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def send_notification
|
158
|
+
UserMailer.updated(user).deliver_now
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
83
162
|
|
84
|
-
|
85
|
-
the [dry-monads gem](https://dry-rb.org/gems/dry-monads/1.3/). Both `Result` types may take any value as input, ie. `Success(user)`, `Failure(:not_found)`
|
163
|
+
### Calling a Service
|
86
164
|
|
87
|
-
`
|
165
|
+
Services return `Result` monads from the [dry-monads gem](https://dry-rb.org/gems/dry-monads/1.3/). Both `Success` and `Failure` can contain any value, like `Success(user)` or `Failure(:not_found)`.
|
88
166
|
|
89
|
-
The caller
|
167
|
+
The caller can unwrap the `Success` or `Failure`:
|
90
168
|
|
91
169
|
```ruby
|
92
170
|
MyService.call(name: user.name) do |on|
|
@@ -146,36 +224,36 @@ end
|
|
146
224
|
|
147
225
|
## Arguments
|
148
226
|
|
149
|
-
Arguments to a service are defined via the `argument` DSL.
|
150
|
-
|
151
|
-
|
227
|
+
Arguments to a service are defined via the `argument` DSL. The positional name and type arguments are required, with additional options available:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
argument(:name, Type::String, optional: true, description: "The User's name")
|
231
|
+
```
|
152
232
|
|
153
233
|
If an argument is optional and has a default value, simply set `default: your_value` but do not also specify `optional: true`.
|
154
234
|
Doing so will raise an `ArgumentError`.
|
155
235
|
|
156
|
-
Additionally, be sure to `.freeze` any mutable default values,
|
157
|
-
Failure to do so will raise an `ArgumentError`.
|
236
|
+
Additionally, be sure to `.freeze` any mutable default values, e.g., `default: {}.freeze`. Failure to do so will raise an `ArgumentError`.
|
158
237
|
|
159
|
-
To allow multiple types as arguments, use
|
238
|
+
To allow multiple types as arguments, use `|`:
|
160
239
|
|
161
|
-
```
|
240
|
+
```ruby
|
162
241
|
argument(:value, Type::String | Type::Integer)
|
163
242
|
```
|
164
243
|
|
165
|
-
A service should also define a `description`. This is recommended for self-documentation
|
244
|
+
A service should also define a `description`. This is recommended for self-documentation:
|
166
245
|
|
167
246
|
```ruby
|
168
247
|
class MyService < ApplicationService
|
169
|
-
description
|
248
|
+
description "Does a lot of cool things"
|
170
249
|
end
|
171
250
|
```
|
172
251
|
|
173
|
-
To get the full hash of
|
174
|
-
call `arguments`. This is a very useful technique for services that update an object. For example
|
252
|
+
To get the full hash of arguments passed into a service, call `arguments`. This is a very useful technique for services that update an object:
|
175
253
|
|
176
254
|
```ruby
|
177
255
|
class User::UpdateService < ApplicationService
|
178
|
-
argument
|
256
|
+
argument :name, Type::String
|
179
257
|
|
180
258
|
def call
|
181
259
|
user.update(arguments)
|
@@ -183,12 +261,15 @@ class User::UpdateService < ApplicationService
|
|
183
261
|
end
|
184
262
|
```
|
185
263
|
|
186
|
-
### Nil
|
264
|
+
### Nil Values
|
187
265
|
|
188
|
-
Empty strings attempted to coerce into integers will throw an error.
|
189
|
-
|
190
|
-
To instead accept `nil`,
|
191
|
-
|
266
|
+
Empty strings attempted to coerce into integers will throw an error. See [this GitHub issue for an explanation](https://github.com/dry-rb/dry-types/issues/344#issuecomment-518743661).
|
267
|
+
|
268
|
+
To instead accept `nil`, use the following:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
argument :some_integer, Type::Params::Nil | Type::Params::Integer
|
272
|
+
```
|
192
273
|
|
193
274
|
|
194
275
|
## Types
|
@@ -198,7 +279,7 @@ You may also add custom types as outlined in [Dry.rb Custom Types](https://dry-r
|
|
198
279
|
|
199
280
|
The Rails generators will create a Type module, which includes `ServiceBase::Types`, which includes `Dry.Types`. Therefore, all types defined in Dry.rb's Types are available to you.
|
200
281
|
|
201
|
-
```
|
282
|
+
```ruby
|
202
283
|
# app/models/type.rb
|
203
284
|
module Type
|
204
285
|
include ServiceBase::Types
|
@@ -211,7 +292,7 @@ module Type
|
|
211
292
|
# Controller params are an ActionController::Parameters instance or a hash (easier for testing)
|
212
293
|
ControllerParams = Dry.Types.Instance(ActionController::Parameters) | Dry.Types.Instance(Hash)
|
213
294
|
|
214
|
-
#
|
295
|
+
# Custom param hashes
|
215
296
|
AddressParams = Dry::Types['hash'].schema(
|
216
297
|
address: Dry::Types['string'],
|
217
298
|
address2: Dry::Types['string'],
|
@@ -223,40 +304,38 @@ end
|
|
223
304
|
|
224
305
|
# app/services/example_service.rb
|
225
306
|
class ExampleService < ApplicationService
|
226
|
-
argument
|
227
|
-
argument
|
228
|
-
argument
|
229
|
-
argument
|
230
|
-
argument
|
307
|
+
argument :any_model, Type::ApplicationRecord, description: "The model to update"
|
308
|
+
argument :params, Type::ControllerParams, description: "The attributes to update"
|
309
|
+
argument :user, Type::User, description: "A cool user that relates to the model"
|
310
|
+
argument :project, Type::Project, description: "A project that the user is working on"
|
311
|
+
argument :address, Type::AddressParams, description: "The user's address"
|
231
312
|
end
|
232
313
|
```
|
233
314
|
|
234
|
-
Dry.rb's `Coercible` and `Params` Types are very powerful and recommended for automatic parsing of inputs,
|
315
|
+
Dry.rb's `Coercible` and `Params` Types are very powerful and recommended for automatic parsing of inputs, e.g., controller parameters.
|
235
316
|
|
236
|
-
For example `argument
|
317
|
+
For example, `argument :number, Type::Params::Integer` will convert `"12"` ⇒ `12`.
|
237
318
|
|
238
319
|
Entire hash structures may also be validated and automatically parsed, for example:
|
239
320
|
|
240
321
|
```ruby
|
241
|
-
argument
|
242
|
-
:line_items,
|
322
|
+
argument :line_items,
|
243
323
|
Type::Array(
|
244
324
|
Type::Hash.schema(
|
245
325
|
vintage_year: Type::Params::Integer,
|
246
326
|
number_of_credits: Type::Params::Integer,
|
247
327
|
price_dollars_usd: Type::Params::Float,
|
248
|
-
)
|
249
|
-
)
|
328
|
+
)
|
329
|
+
)
|
250
330
|
```
|
251
331
|
|
252
|
-
## Working with
|
332
|
+
## Working with Transactions
|
253
333
|
|
254
334
|
⚠️ If your service makes more than one write call to the DB, you
|
255
335
|
should wrap all operations in a single transaction with
|
256
|
-
|
336
|
+
`ApplicationRecord.transaction`.
|
257
337
|
|
258
|
-
According to the [Dry
|
259
|
-
RB docs](https://dry-rb.org/gems/dry-monads/1.3/do-notation/#transaction-safety):
|
338
|
+
According to the [Dry-RB documentation](https://dry-rb.org/gems/dry-monads/1.3/do-notation/#transaction-safety):
|
260
339
|
|
261
340
|
> Under the hood, Do uses exceptions to halt unsuccessful
|
262
341
|
operations…Since yield internally uses exceptions to
|
@@ -303,7 +382,7 @@ blocks or other sub-modules. See [https://github.com/dry-rb/dry-monads/issues/68
|
|
303
382
|
|
304
383
|
## Misc
|
305
384
|
|
306
|
-
- To get a pretty printed description of a service and
|
385
|
+
- To get a pretty printed description of a service and its args, run `ServiceClass.pp`
|
307
386
|
|
308
387
|
## Test Support
|
309
388
|
|
@@ -320,13 +399,17 @@ stub_service_success(User::CreateService, success: create(:user)) # yields the s
|
|
320
399
|
stub_service_success(User::CreateService, success_nil: true) # yields the success block of the service call, returning `nil` as the Success's value
|
321
400
|
|
322
401
|
stub_service_failure(User::CreateService, failure: "error")
|
323
|
-
stub_service_failure(User::CreateService failure: :invalid_email, matched: true)
|
402
|
+
stub_service_failure(User::CreateService, failure: :invalid_email, matched: true)
|
324
403
|
```
|
325
404
|
|
326
405
|
## Development
|
327
406
|
|
328
407
|
After checking out the repo, run `bundle install` to install dependencies. Then, run `rspec` to run the tests.
|
329
408
|
|
409
|
+
### Test Coverage
|
410
|
+
|
411
|
+
The gem maintains **100%** test coverage across all core components.
|
412
|
+
|
330
413
|
## Contributing
|
331
414
|
|
332
415
|
Bug reports and pull requests are welcome on GitHub.
|
@@ -6,13 +6,9 @@ module ServiceSupport
|
|
6
6
|
def stub_service_success(service_class, success: nil, success_nil: false)
|
7
7
|
block = double(:on)
|
8
8
|
allow(block).to receive(:failure)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
allow(block).to receive(:success).and_yield(nil)
|
13
|
-
else
|
14
|
-
allow(block).to receive(:success).and_yield
|
15
|
-
end
|
9
|
+
|
10
|
+
yield_value = determine_success_yield_value(success, success_nil)
|
11
|
+
allow(block).to receive(:success) { |&block_proc| call_with_flexible_params(block_proc, yield_value) }
|
16
12
|
allow(service_class).to receive(:call).and_yield(block)
|
17
13
|
end
|
18
14
|
|
@@ -23,16 +19,57 @@ module ServiceSupport
|
|
23
19
|
def stub_service_failure(service_class, failure:, matched: false)
|
24
20
|
block = double(:on)
|
25
21
|
allow(block).to receive(:success)
|
26
|
-
|
27
|
-
|
28
|
-
allow(block).to receive(:failure).with(failure).and_yield(failure)
|
29
|
-
else # on.failure
|
30
|
-
# ignore matched on.failure(:some_error)
|
31
|
-
allow(block).to receive(:failure).with(anything)
|
32
|
-
allow(block).to receive(:failure).with(no_args).and_yield(failure)
|
33
|
-
end
|
22
|
+
|
23
|
+
setup_failure_stub(block, failure, matched)
|
34
24
|
allow(service_class).to receive(:call).and_yield(block)
|
35
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def determine_success_yield_value(success, success_nil)
|
30
|
+
return success unless success.nil?
|
31
|
+
return nil if success_nil
|
32
|
+
|
33
|
+
:no_yield
|
34
|
+
end
|
35
|
+
|
36
|
+
def call_with_flexible_params(block_proc, yield_value)
|
37
|
+
if yield_value == :no_yield
|
38
|
+
block_proc.call
|
39
|
+
else
|
40
|
+
call_block_with_fallback(block_proc, yield_value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def call_block_with_fallback(block_proc, value)
|
45
|
+
block_proc.call(value)
|
46
|
+
rescue ArgumentError
|
47
|
+
# Block doesn't accept parameters, call without arguments
|
48
|
+
block_proc.call
|
49
|
+
end
|
50
|
+
|
51
|
+
def setup_failure_stub(block, failure, matched)
|
52
|
+
if matched
|
53
|
+
setup_matched_failure_stub(block, failure)
|
54
|
+
else
|
55
|
+
setup_unmatched_failure_stub(block, failure)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def setup_matched_failure_stub(block, failure)
|
60
|
+
allow(block).to receive(:failure) # ignore unmatched on.failure
|
61
|
+
allow(block).to receive(:failure).with(failure) do |&failure_block|
|
62
|
+
call_block_with_fallback(failure_block, failure)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup_unmatched_failure_stub(block, failure)
|
67
|
+
# ignore matched on.failure(:some_error)
|
68
|
+
allow(block).to receive(:failure).with(anything)
|
69
|
+
allow(block).to receive(:failure).with(no_args) do |&failure_block|
|
70
|
+
call_block_with_fallback(failure_block, failure)
|
71
|
+
end
|
72
|
+
end
|
36
73
|
end
|
37
74
|
|
38
75
|
RSpec.configure do |config|
|
data/lib/service_base/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: service_base
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Klein
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-09-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: dry-matcher
|
@@ -87,6 +87,7 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
+
- CHANGELOG.md
|
90
91
|
- LICENSE.txt
|
91
92
|
- README.md
|
92
93
|
- lib/generators/application_service_generator.rb
|
@@ -105,7 +106,7 @@ licenses:
|
|
105
106
|
metadata:
|
106
107
|
homepage_uri: https://github.com/kleinjm/service_base
|
107
108
|
source_code_uri: https://github.com/kleinjm/service_base
|
108
|
-
changelog_uri: https://github.com/kleinjm/service_base/blob/main/
|
109
|
+
changelog_uri: https://github.com/kleinjm/service_base/blob/main/CHANGELOG.md
|
109
110
|
rdoc_options: []
|
110
111
|
require_paths:
|
111
112
|
- lib
|