solid-process 0.0.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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