teckel 0.3.0 → 0.4.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 +53 -0
- data/LICENSE_LOGO +4 -0
- data/README.md +4 -4
- data/lib/teckel.rb +9 -3
- data/lib/teckel/chain.rb +99 -271
- data/lib/teckel/chain/result.rb +38 -0
- data/lib/teckel/chain/runner.rb +51 -0
- data/lib/teckel/chain/step.rb +18 -0
- data/lib/teckel/config.rb +1 -23
- data/lib/teckel/contracts.rb +19 -0
- data/lib/teckel/operation.rb +309 -215
- data/lib/teckel/operation/result.rb +92 -0
- data/lib/teckel/operation/runner.rb +70 -0
- data/lib/teckel/result.rb +52 -53
- data/lib/teckel/version.rb +1 -1
- data/spec/chain/inheritance_spec.rb +116 -0
- data/spec/chain/results_spec.rb +53 -0
- data/spec/chain_around_hook_spec.rb +100 -0
- data/spec/chain_spec.rb +180 -0
- data/spec/config_spec.rb +26 -0
- data/spec/doctest_helper.rb +7 -0
- data/spec/operation/inheritance_spec.rb +94 -0
- data/spec/operation/result_spec.rb +34 -0
- data/spec/operation/results_spec.rb +117 -0
- data/spec/operation_spec.rb +485 -0
- data/spec/rb27/pattern_matching_spec.rb +193 -0
- data/spec/result_spec.rb +20 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/dry_base.rb +8 -0
- data/spec/support/fake_db.rb +12 -0
- data/spec/support/fake_models.rb +20 -0
- data/spec/teckel_spec.rb +7 -0
- metadata +52 -25
- data/.codeclimate.yml +0 -3
- data/.github/workflows/ci.yml +0 -92
- data/.github/workflows/pages.yml +0 -50
- data/.gitignore +0 -15
- data/.rspec +0 -3
- data/.rubocop.yml +0 -12
- data/.ruby-version +0 -1
- data/DEVELOPMENT.md +0 -32
- data/Gemfile +0 -16
- data/Rakefile +0 -35
- data/bin/console +0 -15
- data/bin/rake +0 -29
- data/bin/rspec +0 -29
- data/bin/rubocop +0 -18
- data/bin/setup +0 -8
- data/lib/teckel/none.rb +0 -18
- data/lib/teckel/operation/results.rb +0 -72
- data/teckel.gemspec +0 -32
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
@warning = Warning[:experimental]
|
3
|
+
Warning[:experimental] = false
|
4
|
+
|
5
|
+
require 'support/dry_base'
|
6
|
+
require 'support/fake_models'
|
7
|
+
|
8
|
+
RSpec.describe "Ruby 2.7 pattern matches for Result and Chain" do
|
9
|
+
module TeckelChainPatternMatchingTest
|
10
|
+
class CreateUser
|
11
|
+
include ::Teckel::Operation
|
12
|
+
|
13
|
+
result!
|
14
|
+
|
15
|
+
input Types::Hash.schema(name: Types::String, age: Types::Coercible::Integer.optional)
|
16
|
+
output Types.Instance(User)
|
17
|
+
error Types::Hash.schema(message: Types::String, errors: Types::Array.of(Types::Hash))
|
18
|
+
|
19
|
+
def call(input)
|
20
|
+
user = User.new(name: input[:name], age: input[:age])
|
21
|
+
if user.save
|
22
|
+
success!(user)
|
23
|
+
else
|
24
|
+
fail!(message: "Could not save User", errors: user.errors)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class LogUser
|
30
|
+
include ::Teckel::Operation
|
31
|
+
|
32
|
+
result!
|
33
|
+
|
34
|
+
input Types.Instance(User)
|
35
|
+
error none
|
36
|
+
output input
|
37
|
+
|
38
|
+
def call(usr)
|
39
|
+
Logger.new(File::NULL).info("User #{usr.name} created")
|
40
|
+
usr
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class AddFriend
|
45
|
+
include ::Teckel::Operation
|
46
|
+
|
47
|
+
result!
|
48
|
+
|
49
|
+
settings Struct.new(:fail_befriend)
|
50
|
+
|
51
|
+
input Types.Instance(User)
|
52
|
+
output Types::Hash.schema(user: Types.Instance(User), friend: Types.Instance(User))
|
53
|
+
error Types::Hash.schema(message: Types::String)
|
54
|
+
|
55
|
+
def call(user)
|
56
|
+
if settings&.fail_befriend
|
57
|
+
fail!(message: "Did not find a friend.")
|
58
|
+
else
|
59
|
+
{ user: user, friend: User.new(name: "A friend", age: 42) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Chain
|
65
|
+
include Teckel::Chain
|
66
|
+
|
67
|
+
step :create, CreateUser
|
68
|
+
step :log, LogUser
|
69
|
+
step :befriend, AddFriend
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "Operation Result" do
|
74
|
+
context "success" do
|
75
|
+
specify "pattern matching with keys" do
|
76
|
+
x =
|
77
|
+
case TeckelChainPatternMatchingTest::AddFriend.call(User.new(name: "bob", age: 23))
|
78
|
+
in { success: false, value: value }
|
79
|
+
["Failed", value]
|
80
|
+
in { success: true, value: value }
|
81
|
+
["Success result", value]
|
82
|
+
else
|
83
|
+
raise "Unexpected Result"
|
84
|
+
end
|
85
|
+
|
86
|
+
expect(x).to contain_exactly("Success result", hash_including(:friend, :user))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "failure" do
|
91
|
+
specify "pattern matching with keys" do
|
92
|
+
result =
|
93
|
+
TeckelChainPatternMatchingTest::AddFriend.
|
94
|
+
with(befriend: :fail).
|
95
|
+
call(User.new(name: "bob", age: 23))
|
96
|
+
|
97
|
+
x =
|
98
|
+
case result
|
99
|
+
in { success: false, value: value }
|
100
|
+
["Failed", value]
|
101
|
+
in { success: true, value: value }
|
102
|
+
["Success result", value]
|
103
|
+
else
|
104
|
+
raise "Unexpected Result"
|
105
|
+
end
|
106
|
+
|
107
|
+
expect(x).to contain_exactly("Failed", hash_including(:message))
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "pattern matching array" do
|
111
|
+
result =
|
112
|
+
TeckelChainPatternMatchingTest::AddFriend.
|
113
|
+
with(befriend: :fail).
|
114
|
+
call(User.new(name: "bob", age: 23))
|
115
|
+
|
116
|
+
x =
|
117
|
+
case result
|
118
|
+
in [false, value]
|
119
|
+
["Failed", value]
|
120
|
+
in [true, value]
|
121
|
+
["Success result", value]
|
122
|
+
else
|
123
|
+
raise "Unexpected Result"
|
124
|
+
end
|
125
|
+
expect(x).to contain_exactly("Failed", hash_including(:message))
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "Chain" do
|
131
|
+
context "success" do
|
132
|
+
specify "pattern matching with keys" do
|
133
|
+
x =
|
134
|
+
case TeckelChainPatternMatchingTest::Chain.call(name: "Bob", age: 23)
|
135
|
+
in { success: false, step: :befriend, value: value }
|
136
|
+
["Failed", value]
|
137
|
+
in { success: true, value: value }
|
138
|
+
["Success result", value]
|
139
|
+
else
|
140
|
+
raise "Unexpected Result"
|
141
|
+
end
|
142
|
+
expect(x).to contain_exactly("Success result", hash_including(:friend, :user))
|
143
|
+
end
|
144
|
+
|
145
|
+
specify "pattern matching array" do
|
146
|
+
x =
|
147
|
+
case TeckelChainPatternMatchingTest::Chain.call(name: "Bob", age: 23)
|
148
|
+
in [false, :befriend, value]
|
149
|
+
"Failed in befriend with #{value}"
|
150
|
+
in [true, _, value]
|
151
|
+
"Success result"
|
152
|
+
end
|
153
|
+
expect(x).to eq("Success result")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context "failure" do
|
158
|
+
specify "pattern matching with keys" do
|
159
|
+
result =
|
160
|
+
TeckelChainPatternMatchingTest::Chain.
|
161
|
+
with(befriend: :fail).
|
162
|
+
call(name: "bob", age: 23)
|
163
|
+
|
164
|
+
x =
|
165
|
+
case result
|
166
|
+
in { success: false, step: :befriend, value: value }
|
167
|
+
"Failed in befriend with #{value}"
|
168
|
+
in { success: true, value: value }
|
169
|
+
"Success result"
|
170
|
+
end
|
171
|
+
expect(x).to eq("Failed in befriend with #{ {message: "Did not find a friend."} }")
|
172
|
+
end
|
173
|
+
|
174
|
+
specify "pattern matching array" do
|
175
|
+
result =
|
176
|
+
TeckelChainPatternMatchingTest::Chain.
|
177
|
+
with(befriend: :fail).
|
178
|
+
call(name: "Bob", age: 23)
|
179
|
+
|
180
|
+
x =
|
181
|
+
case result
|
182
|
+
in [false, :befriend, value]
|
183
|
+
"Failed in befriend with #{value}"
|
184
|
+
in [true, value]
|
185
|
+
"Success result"
|
186
|
+
end
|
187
|
+
expect(x).to eq("Failed in befriend with #{ {message: "Did not find a friend."} }")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
Warning[:experimental] = @warning
|
data/spec/result_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'support/dry_base'
|
4
|
+
require 'support/fake_models'
|
5
|
+
|
6
|
+
RSpec.describe Teckel::Result do
|
7
|
+
describe "missing initialize" do
|
8
|
+
class MissingResultImplementation
|
9
|
+
include Teckel::Result
|
10
|
+
def initialize(value, success); end
|
11
|
+
end
|
12
|
+
|
13
|
+
specify do
|
14
|
+
result = MissingResultImplementation["value", true]
|
15
|
+
expect { result.successful? }.to raise_error(NotImplementedError)
|
16
|
+
expect { result.failure? }.to raise_error(NotImplementedError)
|
17
|
+
expect { result.value }.to raise_error(NotImplementedError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
if ENV['COVERAGE'] == 'true'
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start do
|
7
|
+
add_filter %r{^/spec/}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require "teckel"
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
# Enable flags like --only-failures and --next-failure
|
15
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
16
|
+
|
17
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
18
|
+
config.disable_monkey_patching!
|
19
|
+
|
20
|
+
config.formatter = config.files_to_run.size > 1 ? :progress : :documentation
|
21
|
+
|
22
|
+
config.expect_with :rspec do |c|
|
23
|
+
c.syntax = :expect
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class User
|
4
|
+
def initialize(name:, age:)
|
5
|
+
@name, @age = name, age
|
6
|
+
end
|
7
|
+
attr_reader :name, :age
|
8
|
+
|
9
|
+
def save
|
10
|
+
!underage?
|
11
|
+
end
|
12
|
+
|
13
|
+
def errors
|
14
|
+
underage? ? [{ age: "underage" }] : nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def underage?
|
18
|
+
@age <= 18
|
19
|
+
end
|
20
|
+
end
|
data/spec/teckel_spec.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teckel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Schulze
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -88,38 +88,48 @@ executables: []
|
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
90
90
|
files:
|
91
|
-
- ".codeclimate.yml"
|
92
|
-
- ".github/workflows/ci.yml"
|
93
|
-
- ".github/workflows/pages.yml"
|
94
|
-
- ".gitignore"
|
95
|
-
- ".rspec"
|
96
|
-
- ".rubocop.yml"
|
97
|
-
- ".ruby-version"
|
98
91
|
- ".yardopts"
|
99
92
|
- CHANGELOG.md
|
100
|
-
- DEVELOPMENT.md
|
101
|
-
- Gemfile
|
102
93
|
- LICENSE
|
94
|
+
- LICENSE_LOGO
|
103
95
|
- README.md
|
104
|
-
- Rakefile
|
105
|
-
- bin/console
|
106
|
-
- bin/rake
|
107
|
-
- bin/rspec
|
108
|
-
- bin/rubocop
|
109
|
-
- bin/setup
|
110
96
|
- lib/teckel.rb
|
111
97
|
- lib/teckel/chain.rb
|
98
|
+
- lib/teckel/chain/result.rb
|
99
|
+
- lib/teckel/chain/runner.rb
|
100
|
+
- lib/teckel/chain/step.rb
|
112
101
|
- lib/teckel/config.rb
|
113
|
-
- lib/teckel/
|
102
|
+
- lib/teckel/contracts.rb
|
114
103
|
- lib/teckel/operation.rb
|
115
|
-
- lib/teckel/operation/
|
104
|
+
- lib/teckel/operation/result.rb
|
105
|
+
- lib/teckel/operation/runner.rb
|
116
106
|
- lib/teckel/result.rb
|
117
107
|
- lib/teckel/version.rb
|
118
|
-
-
|
119
|
-
|
108
|
+
- spec/chain/inheritance_spec.rb
|
109
|
+
- spec/chain/results_spec.rb
|
110
|
+
- spec/chain_around_hook_spec.rb
|
111
|
+
- spec/chain_spec.rb
|
112
|
+
- spec/config_spec.rb
|
113
|
+
- spec/doctest_helper.rb
|
114
|
+
- spec/operation/inheritance_spec.rb
|
115
|
+
- spec/operation/result_spec.rb
|
116
|
+
- spec/operation/results_spec.rb
|
117
|
+
- spec/operation_spec.rb
|
118
|
+
- spec/rb27/pattern_matching_spec.rb
|
119
|
+
- spec/result_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/support/dry_base.rb
|
122
|
+
- spec/support/fake_db.rb
|
123
|
+
- spec/support/fake_models.rb
|
124
|
+
- spec/teckel_spec.rb
|
125
|
+
homepage: https://github.com/fnordfish/teckel
|
120
126
|
licenses:
|
121
127
|
- Apache-2.0
|
122
|
-
metadata:
|
128
|
+
metadata:
|
129
|
+
changelog_uri: https://github.com/github.com/fnordfish/blob/master/CHANGELOG.md
|
130
|
+
source_code_uri: https://github.com/github.com/fnordfish
|
131
|
+
bug_tracker_uri: https://github.com/github.com/fnordfish/issues
|
132
|
+
documentation_uri: https://www.rubydoc.info/gems/teckel/0.4.0
|
123
133
|
post_install_message:
|
124
134
|
rdoc_options: []
|
125
135
|
require_paths:
|
@@ -128,15 +138,32 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
128
138
|
requirements:
|
129
139
|
- - ">="
|
130
140
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
141
|
+
version: 2.4.0
|
132
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
143
|
requirements:
|
134
144
|
- - ">="
|
135
145
|
- !ruby/object:Gem::Version
|
136
146
|
version: '0'
|
137
147
|
requirements: []
|
138
|
-
rubygems_version: 3.
|
148
|
+
rubygems_version: 3.1.2
|
139
149
|
signing_key:
|
140
150
|
specification_version: 4
|
141
151
|
summary: Operations with enforced in/out/err data structures
|
142
|
-
test_files:
|
152
|
+
test_files:
|
153
|
+
- spec/chain/inheritance_spec.rb
|
154
|
+
- spec/chain/results_spec.rb
|
155
|
+
- spec/chain_around_hook_spec.rb
|
156
|
+
- spec/chain_spec.rb
|
157
|
+
- spec/config_spec.rb
|
158
|
+
- spec/doctest_helper.rb
|
159
|
+
- spec/operation/inheritance_spec.rb
|
160
|
+
- spec/operation/result_spec.rb
|
161
|
+
- spec/operation/results_spec.rb
|
162
|
+
- spec/operation_spec.rb
|
163
|
+
- spec/rb27/pattern_matching_spec.rb
|
164
|
+
- spec/result_spec.rb
|
165
|
+
- spec/spec_helper.rb
|
166
|
+
- spec/support/dry_base.rb
|
167
|
+
- spec/support/fake_db.rb
|
168
|
+
- spec/support/fake_models.rb
|
169
|
+
- spec/teckel_spec.rb
|
data/.codeclimate.yml
DELETED
data/.github/workflows/ci.yml
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
name: CI
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
paths:
|
6
|
-
- .github/workflows/ci.yml
|
7
|
-
- lib/**
|
8
|
-
- spec/**
|
9
|
-
- Gemfile
|
10
|
-
- "*.gemspec"
|
11
|
-
- ".rubocop.yml"
|
12
|
-
|
13
|
-
jobs:
|
14
|
-
rubocop:
|
15
|
-
runs-on: ubuntu-latest
|
16
|
-
steps:
|
17
|
-
- uses: actions/checkout@v1
|
18
|
-
- name: Set up Ruby
|
19
|
-
uses: actions/setup-ruby@v1
|
20
|
-
with:
|
21
|
-
ruby-version: 2.4.x
|
22
|
-
- name: Install bundler
|
23
|
-
run: gem install bundler
|
24
|
-
- name: Run rubocop
|
25
|
-
run: bin/rubocop -ESD
|
26
|
-
|
27
|
-
cruby:
|
28
|
-
runs-on: ubuntu-latest
|
29
|
-
strategy:
|
30
|
-
fail-fast: false
|
31
|
-
matrix:
|
32
|
-
ruby: ["2.6.x", "2.5.x", "2.4.x"]
|
33
|
-
|
34
|
-
steps:
|
35
|
-
- uses: actions/checkout@v1
|
36
|
-
- name: Set up Ruby
|
37
|
-
uses: actions/setup-ruby@v1
|
38
|
-
with:
|
39
|
-
ruby-version: ${{matrix.ruby}}
|
40
|
-
- name: Bundle install
|
41
|
-
run: |
|
42
|
-
gem install bundler
|
43
|
-
bundle install --jobs 4 --retry 3 --without tools docs benchmarks
|
44
|
-
- name: Run all tests
|
45
|
-
run: bundle exec rake
|
46
|
-
|
47
|
-
other-ruby:
|
48
|
-
runs-on: ubuntu-latest
|
49
|
-
strategy:
|
50
|
-
fail-fast: false
|
51
|
-
matrix:
|
52
|
-
image: ["jruby:9.2.9", "ruby:2.7"]
|
53
|
-
include:
|
54
|
-
- image: "ruby:2.7"
|
55
|
-
coverage: "true"
|
56
|
-
container:
|
57
|
-
image: ${{matrix.image}}
|
58
|
-
|
59
|
-
steps:
|
60
|
-
- uses: actions/checkout@v1
|
61
|
-
- name: Install git
|
62
|
-
run: |
|
63
|
-
apt-get update
|
64
|
-
apt-get install -y --no-install-recommends git
|
65
|
-
- name: Download test reporter
|
66
|
-
if: "matrix.coverage == 'true'"
|
67
|
-
run: |
|
68
|
-
mkdir -p tmp/
|
69
|
-
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./tmp/cc-test-reporter
|
70
|
-
chmod +x ./tmp/cc-test-reporter
|
71
|
-
./tmp/cc-test-reporter before-build
|
72
|
-
- name: Bundle install
|
73
|
-
env:
|
74
|
-
COVERAGE: ${{matrix.coverage}}
|
75
|
-
run: |
|
76
|
-
gem install bundler
|
77
|
-
bundle install --jobs 4 --retry 3 --without tools docs benchmarks
|
78
|
-
- name: Run all tests
|
79
|
-
env:
|
80
|
-
COVERAGE: ${{matrix.coverage}}
|
81
|
-
run: bundle exec rake
|
82
|
-
- name: Send coverage results
|
83
|
-
if: "matrix.coverage == 'true'"
|
84
|
-
env:
|
85
|
-
CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
|
86
|
-
GIT_COMMIT_SHA: ${{github.sha}}
|
87
|
-
GIT_BRANCH: ${{github.ref}}
|
88
|
-
GIT_COMMITTED_AT: ${{github.event.head_commit.timestamp}}
|
89
|
-
run: |
|
90
|
-
GIT_BRANCH=`ruby -e "puts ENV['GITHUB_REF'].split('/', 3).last"` \
|
91
|
-
GIT_COMMITTED_AT=`ruby -r time -e "puts Time.iso8601(ENV['GIT_COMMITTED_AT']).to_i"` \
|
92
|
-
./tmp/cc-test-reporter after-build -t simplecov
|