solid-process 0.0.0 → 0.2.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 +3 -1
- data/README.md +39 -13
- data/Rakefile +17 -5
- data/examples/business_processes/.rubocop.yml +3 -0
- data/examples/business_processes/.ruby-version +1 -0
- data/examples/business_processes/.standard.yml +1 -0
- data/examples/business_processes/Gemfile +12 -0
- data/examples/business_processes/Rakefile +100 -0
- data/examples/business_processes/app/models/account/member.rb +10 -0
- data/examples/business_processes/app/models/account/owner_creation.rb +53 -0
- data/examples/business_processes/app/models/account.rb +11 -0
- data/examples/business_processes/app/models/user/creation.rb +62 -0
- data/examples/business_processes/app/models/user/token/creation.rb +39 -0
- data/examples/business_processes/app/models/user/token.rb +7 -0
- data/examples/business_processes/app/models/user.rb +15 -0
- data/examples/business_processes/config.rb +14 -0
- data/examples/business_processes/db/setup.rb +49 -0
- data/lib/solid/input.rb +7 -0
- data/lib/solid/model/access.rb +26 -0
- data/lib/solid/model.rb +30 -0
- data/lib/solid/process/active_record.rb +26 -0
- data/lib/solid/process/callbacks.rb +35 -0
- data/lib/solid/process/caller.rb +35 -0
- data/lib/solid/process/class_methods.rb +42 -0
- data/lib/solid/process/config.rb +35 -0
- data/lib/solid/process/error.rb +5 -0
- data/lib/solid/process/version.rb +2 -2
- data/lib/solid/process.rb +134 -4
- data/lib/solid/result.rb +17 -0
- data/lib/solid/validators/all.rb +12 -0
- data/lib/solid/validators/bool_validator.rb +9 -0
- data/lib/solid/validators/email_validator.rb +9 -0
- data/lib/solid/validators/instance_of_validator.rb +13 -0
- data/lib/solid/validators/is_a_validator.rb +6 -0
- data/lib/solid/validators/kind_of_validator.rb +13 -0
- data/lib/solid/validators/persisted_validator.rb +9 -0
- data/lib/solid/validators/respond_to_validator.rb +13 -0
- data/lib/solid/validators/singleton_validator.rb +21 -0
- data/lib/solid/validators/uuid_validator.rb +21 -0
- metadata +88 -8
- data/.rubocop.yml +0 -13
- data/sig/solid/process.rbs +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4b6ab233b8f225123d7a74114c281011f94f7a186faeaee54b3d25e9ba51c2e
|
4
|
+
data.tar.gz: 57a1de84e07d74971640ce4c03b1e12812d1da7765eb83b6ebb460e92972d1bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 378aff92aaacc388198e4c72a5ce0fb72df788b1dd7763d2b0f11024629c8988d95e4e52015393dddd4cfbd1116539f1c6f5e1a541422e296117a27e7a7e778b
|
7
|
+
data.tar.gz: 0040c63c885ff1177dd11c864d208a64c2b46dec1bee9bf71ea2e7df5ac2340668ac8e524c848c30b736457c3a64051e0084e01c3d401cf3bbaf1293959e6764
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,20 +1,46 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
<p align="center">
|
2
|
+
<h1 align="center" id="-solidprocess">🚄 Solid::Process</h1>
|
3
|
+
<p align="center"><i>Ruby on Rails + Business Processes</i></p>
|
4
|
+
<p align="center">
|
5
|
+
<a href="https://codeclimate.com/github/serradura/solid-process/maintainability"><img src="https://api.codeclimate.com/v1/badges/643a53e99bb591321c9f/maintainability" /></a>
|
6
|
+
<a href="https://codeclimate.com/github/serradura/solid-process/test_coverage"><img src="https://api.codeclimate.com/v1/badges/643a53e99bb591321c9f/test_coverage" /></a>
|
7
|
+
<img src="https://img.shields.io/badge/Ruby%20%3E%3D%202.7%2C%20%3C%3D%20Head-ruby.svg?colorA=444&colorB=333" alt="Ruby">
|
8
|
+
<img src="https://img.shields.io/badge/Rails%20%3E%3D%206.0%2C%20%3C%3D%20Edge-rails.svg?colorA=444&colorB=333" alt="Rails">
|
9
|
+
</p>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
## Supported Ruby and Rails
|
13
|
+
|
14
|
+
This library is tested against:
|
15
|
+
|
16
|
+
| Ruby / Rails | 6.0 | 6.1 | 7.0 | 7.1 | Edge |
|
17
|
+
|--------------|-----|-----|-----|-----|------|
|
18
|
+
| 2.7 | ✅ | ✅ | ✅ | ✅ | |
|
19
|
+
| 3.0 | ✅ | ✅ | ✅ | ✅ | |
|
20
|
+
| 3.1 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
21
|
+
| 3.2 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
22
|
+
| 3.3 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
23
|
+
| Head | | | | ✅ | ✅ |
|
6
24
|
|
7
25
|
## Installation
|
8
26
|
|
9
|
-
|
27
|
+
Add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
gem 'solid-process'
|
31
|
+
```
|
10
32
|
|
11
|
-
|
33
|
+
And then execute:
|
12
34
|
|
13
|
-
|
35
|
+
```bash
|
36
|
+
$ bundle install
|
37
|
+
```
|
14
38
|
|
15
|
-
|
39
|
+
Or install it yourself as:
|
16
40
|
|
17
|
-
|
41
|
+
```bash
|
42
|
+
$ gem install solid-process
|
43
|
+
```
|
18
44
|
|
19
45
|
## Usage
|
20
46
|
|
@@ -22,13 +48,13 @@ TODO: Write usage instructions here
|
|
22
48
|
|
23
49
|
## Development
|
24
50
|
|
25
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake
|
51
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake dev` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
26
52
|
|
27
53
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
28
54
|
|
29
55
|
## Contributing
|
30
56
|
|
31
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
57
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/serradura/solid-process. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/serradura/solid-process/blob/master/CODE_OF_CONDUCT.md).
|
32
58
|
|
33
59
|
## License
|
34
60
|
|
@@ -36,4 +62,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
36
62
|
|
37
63
|
## Code of Conduct
|
38
64
|
|
39
|
-
Everyone interacting in the Solid::Process project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
65
|
+
Everyone interacting in the Solid::Process project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/serradura/solid-process/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
|
-
require "
|
4
|
+
require "rake/testtask"
|
5
5
|
|
6
|
-
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs += %w[lib test]
|
7
8
|
|
8
|
-
|
9
|
+
t.test_files = FileList.new("test/**/*_test.rb")
|
10
|
+
end
|
9
11
|
|
10
|
-
|
12
|
+
require "appraisal/task"
|
11
13
|
|
12
|
-
|
14
|
+
Appraisal::Task.new
|
15
|
+
|
16
|
+
require "standard/rake"
|
17
|
+
|
18
|
+
task :dev do
|
19
|
+
exec "bundle exec appraisal rails-7-1 rake test"
|
20
|
+
|
21
|
+
Rake::Task[:standard].invoke
|
22
|
+
end
|
23
|
+
|
24
|
+
task default: %i[test]
|
@@ -0,0 +1 @@
|
|
1
|
+
3.2.2
|
@@ -0,0 +1 @@
|
|
1
|
+
ruby_version: 3.1
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "sqlite3", "~> 1.7"
|
6
|
+
gem "bcrypt", "~> 3.1.20"
|
7
|
+
gem "activerecord", "~> 7.1", ">= 7.1.3", require: "active_record"
|
8
|
+
gem "type_validator"
|
9
|
+
gem "solid-process", path: "../../"
|
10
|
+
|
11
|
+
gem "rake", "~> 13.0", require: false
|
12
|
+
gem "standard", "~> 1.34", require: false
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
Bundler.require(:default)
|
6
|
+
|
7
|
+
require "standard/rake"
|
8
|
+
|
9
|
+
if RUBY_VERSION <= "3.1"
|
10
|
+
puts "This example requires Ruby 3.1 or higher."
|
11
|
+
exit! 1
|
12
|
+
end
|
13
|
+
|
14
|
+
task :config do
|
15
|
+
require_relative "config"
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: %i[solid_result]
|
19
|
+
|
20
|
+
desc "Do pattern matching in Solid::Result"
|
21
|
+
task solid_result: %i[config] do
|
22
|
+
input = {
|
23
|
+
uuid: SecureRandom.uuid,
|
24
|
+
owner: {
|
25
|
+
name: "\tJohn Doe \n",
|
26
|
+
email: " JOHN.doe@email.com",
|
27
|
+
password: "123123123",
|
28
|
+
password_confirmation: "123123123"
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
case Account::OwnerCreation.call(input)
|
33
|
+
in Solid::Result(user:, account:)
|
34
|
+
puts "Account and owner user created: #{account.uuid} and #{user.uuid}"
|
35
|
+
in Solid::Result(type:, value:)
|
36
|
+
puts "Account creation failed: #{type} - #{value}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Different ways to match
|
40
|
+
#
|
41
|
+
# in Solid::Result(value: {user:, account:})
|
42
|
+
# in Solid::Result(type:, value: {user:, account:})
|
43
|
+
# in Solid::Result(type: :account_owner_created, value: {user:, account:})
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Do pattern matching in Solid::Output"
|
47
|
+
task solid_output: %i[config] do
|
48
|
+
input = {
|
49
|
+
uuid: SecureRandom.uuid,
|
50
|
+
owner: {
|
51
|
+
name: "\tJohn Doe \n",
|
52
|
+
email: " JOHN.doe@email.com",
|
53
|
+
password: "123123123",
|
54
|
+
password_confirmation: "123123123"
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
case Account::OwnerCreation.call(input)
|
59
|
+
in Solid::Output(user:, account:)
|
60
|
+
puts "Account and owner user created: #{account.uuid} and #{user.uuid}"
|
61
|
+
in Solid::Output(type:, value:)
|
62
|
+
puts "Account creation failed: #{type} - #{value}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Different ways to match
|
66
|
+
#
|
67
|
+
# in Solid::Output(value: {user:, account:})
|
68
|
+
# in Solid::Output(type:, value: {user:, account:})
|
69
|
+
# in Solid::Output(type: :account_owner_created, value: {user:, account:})
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "Do pattern matching in Solid::Success and Solid::Failure"
|
73
|
+
task solid_success_and_failure: %i[config] do
|
74
|
+
input = {
|
75
|
+
uuid: SecureRandom.uuid,
|
76
|
+
owner: {
|
77
|
+
name: "\tJohn Doe \n",
|
78
|
+
email: " JOHN.doe@email.com",
|
79
|
+
password: "123123123",
|
80
|
+
password_confirmation: "123123123"
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
case Account::OwnerCreation.call(input)
|
85
|
+
in Solid::Success(user:, account:)
|
86
|
+
puts "Account and owner user created: #{account.uuid} and #{user.uuid}"
|
87
|
+
in Solid::Failure(type:, value:)
|
88
|
+
puts "Account creation failed: #{type} - #{value}"
|
89
|
+
end
|
90
|
+
|
91
|
+
# Different ways to match
|
92
|
+
#
|
93
|
+
# in Solid::Success(value: {user:, account:})
|
94
|
+
# in Solid::Success(type:, value: {user:, account:})
|
95
|
+
# in Solid::Success(type: :account_owner_created, value: {user:, account:})
|
96
|
+
#
|
97
|
+
# in Solid::Failure(input:)
|
98
|
+
# in Solid::Failure(value: {input:})
|
99
|
+
# in Solid::Failure(type: :invalid_input, value: {input:})
|
100
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Account::Member < ActiveRecord::Base
|
4
|
+
self.table_name = "account_members"
|
5
|
+
|
6
|
+
enum role: {owner: 0, admin: 1, contributor: 2}
|
7
|
+
|
8
|
+
belongs_to :user, inverse_of: :memberships
|
9
|
+
belongs_to :account, inverse_of: :memberships
|
10
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Account
|
4
|
+
class OwnerCreation < Solid::Process
|
5
|
+
deps do
|
6
|
+
attribute :user_creation, default: ::User::Creation
|
7
|
+
end
|
8
|
+
|
9
|
+
input do
|
10
|
+
attribute :uuid, :string, default: -> { ::SecureRandom.uuid }
|
11
|
+
attribute :owner
|
12
|
+
|
13
|
+
before_validation do |input|
|
14
|
+
input.uuid = input.uuid.strip.downcase
|
15
|
+
end
|
16
|
+
|
17
|
+
validates :uuid, presence: true, format: {with: /\A[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}\z/i}
|
18
|
+
validates :owner, presence: true
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(attributes)
|
22
|
+
rollback_on_failure {
|
23
|
+
Given(attributes)
|
24
|
+
.and_then(:create_owner)
|
25
|
+
.and_then(:create_account)
|
26
|
+
.and_then(:link_owner_to_account)
|
27
|
+
}.and_expose(:account_owner_created, %i[user account])
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_owner(owner:, **)
|
33
|
+
case deps.user_creation.call(owner)
|
34
|
+
in Solid::Success(user:, token:)
|
35
|
+
Continue(user:, user_token: token)
|
36
|
+
in Solid::Failure(type:, value:)
|
37
|
+
Failure(:invalid_owner, **{type => value})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_account(uuid:, **)
|
42
|
+
account = ::Account.create(uuid:)
|
43
|
+
|
44
|
+
account.persisted? ? Continue(account:) : Failure(:invalid_account, account:)
|
45
|
+
end
|
46
|
+
|
47
|
+
def link_owner_to_account(account:, user:, **)
|
48
|
+
Member.create!(account:, user:, role: :owner)
|
49
|
+
|
50
|
+
Continue()
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Account < ActiveRecord::Base
|
4
|
+
has_many :memberships, inverse_of: :account, dependent: :destroy, class_name: "::Account::Member"
|
5
|
+
has_many :users, through: :memberships, inverse_of: :accounts
|
6
|
+
|
7
|
+
where_ownership = -> { where(account_members: {role: :owner}) }
|
8
|
+
|
9
|
+
has_one :ownership, where_ownership, dependent: nil, inverse_of: :account, class_name: "::Account::Member"
|
10
|
+
has_one :owner, through: :ownership, source: :user
|
11
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class User
|
4
|
+
class Creation < Solid::Process
|
5
|
+
deps do
|
6
|
+
attribute :token_creation, default: ::User::Token::Creation
|
7
|
+
end
|
8
|
+
|
9
|
+
input do
|
10
|
+
attribute :uuid, :string, default: -> { ::SecureRandom.uuid }
|
11
|
+
attribute :name, :string
|
12
|
+
attribute :email, :string
|
13
|
+
attribute :password, :string
|
14
|
+
attribute :password_confirmation, :string
|
15
|
+
|
16
|
+
before_validation do |input|
|
17
|
+
input.uuid = input.uuid.strip.downcase
|
18
|
+
input.name = input.name.strip.gsub(/\s+/, " ")
|
19
|
+
input.email = input.email.strip.downcase
|
20
|
+
end
|
21
|
+
|
22
|
+
validates :uuid, presence: true, format: {with: /\A[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}\z/i}
|
23
|
+
validates :name, presence: true
|
24
|
+
validates :email, presence: true, format: {with: ::URI::MailTo::EMAIL_REGEXP}
|
25
|
+
validates :password, :password_confirmation, presence: true
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(attributes)
|
29
|
+
Given(attributes)
|
30
|
+
.and_then(:validate_email_uniqueness)
|
31
|
+
.then { |result|
|
32
|
+
rollback_on_failure {
|
33
|
+
result
|
34
|
+
.and_then(:create_user)
|
35
|
+
.and_then(:create_user_token)
|
36
|
+
}
|
37
|
+
}
|
38
|
+
.and_expose(:user_created, %i[user token])
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def validate_email_uniqueness(email:, **)
|
44
|
+
::User.exists?(email:) ? Failure(:email_already_taken) : Continue()
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_user(uuid:, name:, email:, password:, password_confirmation:)
|
48
|
+
user = ::User.create(uuid:, name:, email:, password:, password_confirmation:)
|
49
|
+
|
50
|
+
user.persisted? ? Continue(user:) : Failure(:invalid_record, **user.errors.messages)
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_user_token(user:, **)
|
54
|
+
case deps.token_creation.call(user: user)
|
55
|
+
in Solid::Success(token:)
|
56
|
+
Continue(token:)
|
57
|
+
in Solid::Failure
|
58
|
+
raise "Token creation failed"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class User::Token
|
4
|
+
class Creation < Solid::Process
|
5
|
+
input do
|
6
|
+
attribute :user
|
7
|
+
attribute :executed_at, :time, default: -> { ::Time.current }
|
8
|
+
|
9
|
+
validates :user, presence: true
|
10
|
+
validates :executed_at, presence: true
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(attributes)
|
14
|
+
Given(attributes)
|
15
|
+
.and_then(:validate_token_existence)
|
16
|
+
.and_then(:create_token_if_not_exists)
|
17
|
+
.and_expose(:token_created, %i[token])
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def validate_token_existence(user:, **)
|
23
|
+
token = user.token
|
24
|
+
|
25
|
+
token&.persisted? ? Success(:token_already_exists, token:) : Continue()
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_token_if_not_exists(user:, executed_at:, **)
|
29
|
+
token = user.create_token(
|
30
|
+
access_token: ::SecureRandom.hex(24),
|
31
|
+
refresh_token: ::SecureRandom.hex(24),
|
32
|
+
access_token_expires_at: executed_at + 15.days,
|
33
|
+
refresh_token_expires_at: executed_at + 30.days
|
34
|
+
)
|
35
|
+
|
36
|
+
token.persisted? ? Continue(token:) : Failure(:token_creation_failed, **token.errors.messages)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
has_secure_password
|
5
|
+
|
6
|
+
has_many :memberships, inverse_of: :user, dependent: :destroy, class_name: "::Account::Member"
|
7
|
+
has_many :accounts, through: :memberships, inverse_of: :users
|
8
|
+
|
9
|
+
where_ownership = -> { where(account_members: {role: :owner}) }
|
10
|
+
|
11
|
+
has_one :ownership, where_ownership, inverse_of: :user, class_name: "::Account::Member"
|
12
|
+
has_one :account, through: :ownership, inverse_of: :owner
|
13
|
+
|
14
|
+
has_one :token, inverse_of: :user, dependent: :destroy, class_name: "::User::Token"
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(__dir__)
|
4
|
+
|
5
|
+
require "db/setup"
|
6
|
+
|
7
|
+
require "app/models/account"
|
8
|
+
require "app/models/account/member"
|
9
|
+
require "app/models/user"
|
10
|
+
require "app/models/user/token"
|
11
|
+
|
12
|
+
require "app/models/user/token/creation"
|
13
|
+
require "app/models/user/creation"
|
14
|
+
require "app/models/account/owner_creation"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/all"
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection(
|
6
|
+
host: "localhost",
|
7
|
+
adapter: "sqlite3",
|
8
|
+
database: ":memory:"
|
9
|
+
)
|
10
|
+
|
11
|
+
ActiveRecord::Schema.define do
|
12
|
+
suppress_messages do
|
13
|
+
create_table :accounts do |t|
|
14
|
+
t.string :uuid, null: false, index: {unique: true}
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table :users do |t|
|
20
|
+
t.string :uuid, null: false, index: {unique: true}
|
21
|
+
t.string :name, null: false
|
22
|
+
t.string :email, null: false, index: {unique: true}
|
23
|
+
t.string :password_digest, null: false
|
24
|
+
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table :user_tokens do |t|
|
29
|
+
t.belongs_to :user, null: false, foreign_key: true, index: true
|
30
|
+
t.string :access_token, null: false
|
31
|
+
t.string :refresh_token, null: false
|
32
|
+
t.datetime :access_token_expires_at, null: false
|
33
|
+
t.datetime :refresh_token_expires_at, null: false
|
34
|
+
|
35
|
+
t.timestamps
|
36
|
+
end
|
37
|
+
|
38
|
+
create_table :account_members do |t|
|
39
|
+
t.integer :role, null: false, default: 0
|
40
|
+
t.belongs_to :user, null: false, foreign_key: true, index: true
|
41
|
+
t.belongs_to :account, null: false, foreign_key: true, index: true
|
42
|
+
|
43
|
+
t.timestamps
|
44
|
+
|
45
|
+
t.index %i[account_id role], unique: true, where: "(role = 0)"
|
46
|
+
t.index %i[account_id user_id], unique: true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/solid/input.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solid::Model
|
4
|
+
# Implementation based on ActiveModel::Access
|
5
|
+
# https://github.com/rails/rails/blob/7-1-stable/activemodel/lib/active_model/access.rb
|
6
|
+
module Access
|
7
|
+
# Returns a hash of the given methods with their names as keys and returned
|
8
|
+
# values as values.
|
9
|
+
#
|
10
|
+
# person = Person.new(id: 1, name: "bob")
|
11
|
+
# person.slice(:id, :name)
|
12
|
+
# => { "id" => 1, "name" => "bob" }
|
13
|
+
def slice(*methods)
|
14
|
+
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns an array of the values returned by the given methods.
|
18
|
+
#
|
19
|
+
# person = Person.new(id: 1, name: "bob")
|
20
|
+
# person.values_at(:id, :name)
|
21
|
+
# => [1, "bob"]
|
22
|
+
def values_at(*methods)
|
23
|
+
methods.flatten.map! { |method| public_send(method) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/solid/model.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "model/access"
|
4
|
+
|
5
|
+
module Solid::Model
|
6
|
+
extend ::ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ::ActiveModel.const_defined?(:Api, false) ? ::ActiveModel::Api : ::ActiveModel::Model
|
10
|
+
include ::ActiveModel.const_defined?(:Access, false) ? ::ActiveModel::Access : ::Solid::Model::Access
|
11
|
+
|
12
|
+
include ::ActiveModel::Attributes
|
13
|
+
include ::ActiveModel::Dirty
|
14
|
+
include ::ActiveModel::Validations::Callbacks
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def [](...)
|
19
|
+
new(...)
|
20
|
+
end
|
21
|
+
|
22
|
+
def inherited(subclass)
|
23
|
+
subclass.include(::Solid::Model)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect
|
28
|
+
"#<#{self.class.name} #{attributes.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")}>"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "active_record"
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
8
|
+
module Solid
|
9
|
+
class Process
|
10
|
+
private
|
11
|
+
|
12
|
+
if defined?(::ActiveRecord)
|
13
|
+
def rollback_on_failure(model: ::ActiveRecord::Base)
|
14
|
+
result = nil
|
15
|
+
|
16
|
+
model.transaction do
|
17
|
+
result = yield
|
18
|
+
|
19
|
+
raise ::ActiveRecord::Rollback if result.failure?
|
20
|
+
end
|
21
|
+
|
22
|
+
result
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Solid::Process
|
4
|
+
module Callbacks
|
5
|
+
def self.included(subclass)
|
6
|
+
subclass.include ActiveSupport::Callbacks
|
7
|
+
|
8
|
+
subclass.define_callbacks(:call, :success, :failure)
|
9
|
+
|
10
|
+
subclass.extend ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def before_call(*filters, &block)
|
15
|
+
set_callback(:call, :before, *filters, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def around_call(*filters, &block)
|
19
|
+
set_callback(:call, :around, *filters, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def after_call(*filters, &block)
|
23
|
+
set_callback(:call, :after, *filters, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def after_success(*filters, &block)
|
27
|
+
set_callback(:success, :after, *filters, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def after_failure(*filters, &block)
|
31
|
+
set_callback(:failure, :after, *filters, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Lint/RescueException
|
4
|
+
class Solid::Process
|
5
|
+
module Caller
|
6
|
+
def call(arg = nil)
|
7
|
+
output_already_set! if output?
|
8
|
+
|
9
|
+
self.input = arg
|
10
|
+
|
11
|
+
run_callbacks(:call) do
|
12
|
+
::BCDD::Result.event_logs(name: self.class.name) do
|
13
|
+
self.output =
|
14
|
+
if dependencies&.invalid?
|
15
|
+
Failure(:invalid_dependencies, dependencies: dependencies)
|
16
|
+
elsif input.invalid?
|
17
|
+
Failure(:invalid_input, input: input)
|
18
|
+
else
|
19
|
+
super(input.attributes.deep_symbolize_keys)
|
20
|
+
end
|
21
|
+
rescue ::Exception => exception
|
22
|
+
rescue_with_handler(exception) || raise
|
23
|
+
|
24
|
+
output
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
run_callbacks(:success) if output.success?
|
29
|
+
run_callbacks(:failure) if output.failure?
|
30
|
+
|
31
|
+
output
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
# rubocop:enable Lint/RescueException
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Solid::Process
|
4
|
+
module ClassMethods
|
5
|
+
def input=(klass)
|
6
|
+
const_defined?(:Input, false) and raise Error, "#{const_get(:Input, false)} class already defined"
|
7
|
+
|
8
|
+
const_set(:Input, Config::SolidModel[klass])
|
9
|
+
end
|
10
|
+
|
11
|
+
def input(&block)
|
12
|
+
return const_get(:Input, false) if const_defined?(:Input, false)
|
13
|
+
|
14
|
+
block.nil? and raise Error, "#{self}::Input is undefined. Use #{self}.input { ... } to define it."
|
15
|
+
|
16
|
+
klass = ::Class.new(Config.instance.input_class)
|
17
|
+
klass.class_eval(&block)
|
18
|
+
|
19
|
+
self.input = klass
|
20
|
+
end
|
21
|
+
|
22
|
+
def dependencies=(klass)
|
23
|
+
const_defined?(:Dependencies, false) and raise Error, "#{const_get(:Dependencies, false)} class already defined"
|
24
|
+
|
25
|
+
const_set(:Dependencies, Config::SolidModel[klass])
|
26
|
+
end
|
27
|
+
|
28
|
+
def dependencies(&block)
|
29
|
+
return const_get(:Dependencies, false) if const_defined?(:Dependencies, false)
|
30
|
+
|
31
|
+
return if block.nil?
|
32
|
+
|
33
|
+
klass = ::Class.new(Config.instance.dependencies_class)
|
34
|
+
klass.class_eval(&block)
|
35
|
+
|
36
|
+
self.dependencies = klass
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :deps, :dependencies
|
40
|
+
alias_method :deps=, :dependencies=
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Solid::Process
|
4
|
+
class Config
|
5
|
+
SolidModel = ->(klass) do
|
6
|
+
return klass if klass.is_a?(::Class) && klass < ::Solid::Model
|
7
|
+
|
8
|
+
raise ArgumentError, "#{klass.inspect} must be a class that includes #{::Solid::Model}"
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :input_class, :dependencies_class
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
self.input_class = ::Solid::Input
|
15
|
+
self.dependencies_class = ::Solid::Input
|
16
|
+
end
|
17
|
+
|
18
|
+
def input_class=(klass)
|
19
|
+
@input_class = SolidModel[klass]
|
20
|
+
end
|
21
|
+
|
22
|
+
def dependencies_class=(klass)
|
23
|
+
@dependencies_class = SolidModel[klass]
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :deps_class, :dependencies_class
|
27
|
+
alias_method :deps_class=, :dependencies_class=
|
28
|
+
|
29
|
+
class << self
|
30
|
+
attr_reader :instance
|
31
|
+
end
|
32
|
+
|
33
|
+
@instance = new
|
34
|
+
end
|
35
|
+
end
|
data/lib/solid/process.rb
CHANGED
@@ -1,10 +1,140 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "active_support/all"
|
4
|
+
require "active_model"
|
5
|
+
require "bcdd/result"
|
4
6
|
|
5
7
|
module Solid
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
require "solid/input"
|
9
|
+
require "solid/result"
|
10
|
+
|
11
|
+
class Process
|
12
|
+
require "solid/process/version"
|
13
|
+
require "solid/process/error"
|
14
|
+
require "solid/process/config"
|
15
|
+
require "solid/process/caller"
|
16
|
+
require "solid/process/callbacks"
|
17
|
+
require "solid/process/class_methods"
|
18
|
+
require "solid/process/active_record"
|
19
|
+
|
20
|
+
extend ClassMethods
|
21
|
+
|
22
|
+
include Callbacks
|
23
|
+
include ::ActiveSupport::Rescuable
|
24
|
+
include ::BCDD::Context.mixin(config: {addon: {continue: true}})
|
25
|
+
|
26
|
+
def self.inherited(subclass)
|
27
|
+
super
|
28
|
+
|
29
|
+
subclass.prepend(Caller)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.call(arg = nil)
|
33
|
+
new.call(arg)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.configuration(&block)
|
37
|
+
yield config
|
38
|
+
|
39
|
+
config.freeze
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.config
|
43
|
+
Config.instance
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :output, :input, :dependencies
|
47
|
+
|
48
|
+
def initialize(arg = nil)
|
49
|
+
self.dependencies = arg
|
50
|
+
end
|
51
|
+
|
52
|
+
def call(_arg = nil)
|
53
|
+
raise Error, "#{self.class}#call must be implemented."
|
54
|
+
end
|
55
|
+
|
56
|
+
def with(dependencies)
|
57
|
+
self.class.new(dependencies.with_indifferent_access.with_defaults(deps&.attributes))
|
58
|
+
end
|
59
|
+
|
60
|
+
def new(dependencies = {})
|
61
|
+
with(dependencies)
|
62
|
+
end
|
63
|
+
|
64
|
+
def input?
|
65
|
+
!input.nil?
|
66
|
+
end
|
67
|
+
|
68
|
+
def output?(type = nil)
|
69
|
+
type.nil? ? !output.nil? : !!output&.is?(type)
|
70
|
+
end
|
71
|
+
|
72
|
+
def dependencies?
|
73
|
+
!dependencies.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
def success?(type = nil)
|
77
|
+
!!output&.success?(type)
|
78
|
+
end
|
79
|
+
|
80
|
+
def failure?(type = nil)
|
81
|
+
!!output&.failure?(type)
|
82
|
+
end
|
83
|
+
|
84
|
+
def inspect
|
85
|
+
"#<#{self.class.name} dependencies=#{dependencies.inspect} input=#{input.inspect} output=#{output.inspect}>"
|
86
|
+
end
|
87
|
+
|
88
|
+
def method_missing(name, *args, &block)
|
89
|
+
name.end_with?("?") ? output&.is?(name.to_s.chomp("?")) : super
|
90
|
+
end
|
91
|
+
|
92
|
+
def respond_to_missing?(name, include_private = false)
|
93
|
+
name.end_with?("?") || super
|
94
|
+
end
|
95
|
+
|
96
|
+
alias_method :deps, :dependencies
|
97
|
+
alias_method :deps?, :dependencies?
|
98
|
+
alias_method :result, :output
|
99
|
+
alias_method :result?, :output?
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def dependencies=(arg)
|
104
|
+
raise Error, "The `#{self.class}#dependencies` is already set." unless dependencies.nil?
|
105
|
+
|
106
|
+
@dependencies = self.class.dependencies&.then { arg.instance_of?(_1) ? arg : _1.new(arg) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def input=(arg)
|
110
|
+
raise Error, "The `#{self.class}#input` is already set." unless input.nil?
|
111
|
+
|
112
|
+
@input = self.class.input.then { arg.instance_of?(_1) ? arg : _1.new(arg) }
|
113
|
+
end
|
114
|
+
|
115
|
+
def output_already_set!
|
116
|
+
raise Error, "The `#{self.class}#output` is already set. " \
|
117
|
+
"Use `.output` to access the result or create a new instance to call again."
|
118
|
+
end
|
119
|
+
|
120
|
+
def output=(result)
|
121
|
+
output_already_set! unless output.nil?
|
122
|
+
|
123
|
+
raise Error, "The result #{result.inspect} must be a BCDD::Context." unless result.is_a?(::BCDD::Context)
|
124
|
+
|
125
|
+
@output = result
|
126
|
+
end
|
127
|
+
|
128
|
+
def Success!(...)
|
129
|
+
return self.output = Success(...) if output.nil?
|
130
|
+
|
131
|
+
raise Error, "`Success!()` cannot be called because the `#{self.class}#output` is already set."
|
132
|
+
end
|
133
|
+
|
134
|
+
def Failure!(...)
|
135
|
+
return self.output = Failure(...) if output.nil?
|
136
|
+
|
137
|
+
raise Error, "`Failure!()` cannot be called because the `#{self.class}#output` is already set."
|
138
|
+
end
|
9
139
|
end
|
10
140
|
end
|
data/lib/solid/result.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Solid
|
4
|
+
Output = ::BCDD::Context
|
5
|
+
|
6
|
+
Result = ::BCDD::Context
|
7
|
+
Success = Result::Success
|
8
|
+
Failure = Result::Failure
|
9
|
+
|
10
|
+
def self.Success(...)
|
11
|
+
Result::Success(...)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.Failure(...)
|
15
|
+
Result::Failure(...)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "instance_of_validator"
|
4
|
+
require_relative "is_a_validator"
|
5
|
+
require_relative "kind_of_validator"
|
6
|
+
require_relative "respond_to_validator"
|
7
|
+
require_relative "singleton_validator"
|
8
|
+
|
9
|
+
require_relative "bool_validator"
|
10
|
+
require_relative "email_validator"
|
11
|
+
require_relative "persisted_validator"
|
12
|
+
require_relative "uuid_validator"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class EmailValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(obj, attribute, value)
|
5
|
+
return if value.is_a?(String) && URI::MailTo::EMAIL_REGEXP.match?(value)
|
6
|
+
|
7
|
+
obj.errors.add attribute, (options[:message] || "is not an email")
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class InstanceOfValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(obj, attribute, value)
|
5
|
+
with_option = Array.wrap(options[:with] || options[:in])
|
6
|
+
|
7
|
+
return if with_option.any? { |type| value.instance_of?(type) }
|
8
|
+
|
9
|
+
expectation = with_option.map(&:name).join(" | ")
|
10
|
+
|
11
|
+
obj.errors.add(attribute, (options[:message] || "is not an instance of #{expectation}"))
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class KindOfValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(obj, attribute, value)
|
5
|
+
with_option = Array.wrap(options[:with] || options[:in])
|
6
|
+
|
7
|
+
return if with_option.any? { |type| value.is_a?(type) }
|
8
|
+
|
9
|
+
expectation = with_option.map(&:name).join(" | ")
|
10
|
+
|
11
|
+
obj.errors.add(attribute, (options[:message] || "is not a #{expectation}"))
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PersistedValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
return if (options[:allow_nil] && value.nil?) || value.try(:persisted?)
|
6
|
+
|
7
|
+
record.errors.add(attribute, (options[:message] || "must be persisted"))
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RespondToValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(obj, attribute, value)
|
5
|
+
with_option = Array.wrap(options[:with] || options[:in])
|
6
|
+
|
7
|
+
return if with_option.all? { value.respond_to?(_1) }
|
8
|
+
|
9
|
+
expectation = with_option.map(&:inspect).join(" & ")
|
10
|
+
|
11
|
+
obj.errors.add(attribute, (options[:message] || "does not respond to #{expectation}"))
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SingletonValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(obj, attribute, value)
|
5
|
+
with_option = Array.wrap(options[:with] || options[:in])
|
6
|
+
|
7
|
+
unless value.is_a?(Module)
|
8
|
+
return obj.errors.add(attribute, options[:message] || "is not a class or module")
|
9
|
+
end
|
10
|
+
|
11
|
+
is_valid = with_option.any? do |type|
|
12
|
+
type.is_a?(Module) or raise ArgumentError, "#{type.inspect} is not a class or module"
|
13
|
+
|
14
|
+
value == type || (value < type || value.is_a?(type))
|
15
|
+
end
|
16
|
+
|
17
|
+
expectation = with_option.map(&:name).join(" | ")
|
18
|
+
|
19
|
+
is_valid or obj.errors.add(attribute, (options[:message] || "is not #{expectation}"))
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UuidValidator < ActiveModel::EachValidator
|
4
|
+
PATTERN = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
5
|
+
CASE_SENSITIVE = /\A#{PATTERN}\z/.freeze
|
6
|
+
CASE_INSENSITIVE = /\A#{PATTERN}\z/i.freeze
|
7
|
+
|
8
|
+
def validate_each(obj, attribute, value)
|
9
|
+
case_sensitive = options.fetch(:case_sensitive, true)
|
10
|
+
|
11
|
+
regexp = case_sensitive ? CASE_SENSITIVE : CASE_INSENSITIVE
|
12
|
+
|
13
|
+
return if value.is_a?(String) && value.match?(regexp)
|
14
|
+
|
15
|
+
message = options[:message] || "is not a valid UUID (case #{case_sensitive ? "sensitive" : "insensitive"})"
|
16
|
+
|
17
|
+
obj.errors.add(attribute, message)
|
18
|
+
end
|
19
|
+
|
20
|
+
private_constant :PATTERN
|
21
|
+
end
|
metadata
CHANGED
@@ -1,31 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solid-process
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Serradura
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2024-03-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bcdd-result
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activemodel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6.0'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '8.0'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '6.0'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '8.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: appraisal
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.5'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.5'
|
61
|
+
description: Ruby on Rails + Business Processes
|
14
62
|
email:
|
15
63
|
- rodrigo.serradura@gmail.com
|
16
64
|
executables: []
|
17
65
|
extensions: []
|
18
66
|
extra_rdoc_files: []
|
19
67
|
files:
|
20
|
-
- ".rubocop.yml"
|
21
68
|
- CHANGELOG.md
|
22
69
|
- CODE_OF_CONDUCT.md
|
23
70
|
- LICENSE.txt
|
24
71
|
- README.md
|
25
72
|
- Rakefile
|
73
|
+
- examples/business_processes/.rubocop.yml
|
74
|
+
- examples/business_processes/.ruby-version
|
75
|
+
- examples/business_processes/.standard.yml
|
76
|
+
- examples/business_processes/Gemfile
|
77
|
+
- examples/business_processes/Rakefile
|
78
|
+
- examples/business_processes/app/models/account.rb
|
79
|
+
- examples/business_processes/app/models/account/member.rb
|
80
|
+
- examples/business_processes/app/models/account/owner_creation.rb
|
81
|
+
- examples/business_processes/app/models/user.rb
|
82
|
+
- examples/business_processes/app/models/user/creation.rb
|
83
|
+
- examples/business_processes/app/models/user/token.rb
|
84
|
+
- examples/business_processes/app/models/user/token/creation.rb
|
85
|
+
- examples/business_processes/config.rb
|
86
|
+
- examples/business_processes/db/setup.rb
|
87
|
+
- lib/solid/input.rb
|
88
|
+
- lib/solid/model.rb
|
89
|
+
- lib/solid/model/access.rb
|
26
90
|
- lib/solid/process.rb
|
91
|
+
- lib/solid/process/active_record.rb
|
92
|
+
- lib/solid/process/callbacks.rb
|
93
|
+
- lib/solid/process/caller.rb
|
94
|
+
- lib/solid/process/class_methods.rb
|
95
|
+
- lib/solid/process/config.rb
|
96
|
+
- lib/solid/process/error.rb
|
27
97
|
- lib/solid/process/version.rb
|
28
|
-
-
|
98
|
+
- lib/solid/result.rb
|
99
|
+
- lib/solid/validators/all.rb
|
100
|
+
- lib/solid/validators/bool_validator.rb
|
101
|
+
- lib/solid/validators/email_validator.rb
|
102
|
+
- lib/solid/validators/instance_of_validator.rb
|
103
|
+
- lib/solid/validators/is_a_validator.rb
|
104
|
+
- lib/solid/validators/kind_of_validator.rb
|
105
|
+
- lib/solid/validators/persisted_validator.rb
|
106
|
+
- lib/solid/validators/respond_to_validator.rb
|
107
|
+
- lib/solid/validators/singleton_validator.rb
|
108
|
+
- lib/solid/validators/uuid_validator.rb
|
29
109
|
homepage: https://github.com/serradura/solid-process
|
30
110
|
licenses:
|
31
111
|
- MIT
|
@@ -49,8 +129,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
129
|
- !ruby/object:Gem::Version
|
50
130
|
version: '0'
|
51
131
|
requirements: []
|
52
|
-
rubygems_version: 3.
|
132
|
+
rubygems_version: 3.1.6
|
53
133
|
signing_key:
|
54
134
|
specification_version: 4
|
55
|
-
summary: Ruby on Rails
|
135
|
+
summary: Ruby on Rails + Business Processes
|
56
136
|
test_files: []
|
data/.rubocop.yml
DELETED