teckel 0.1.0 → 0.6.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 +114 -0
- data/LICENSE_LOGO +4 -0
- data/README.md +22 -14
- data/lib/teckel.rb +11 -2
- data/lib/teckel/chain.rb +47 -152
- data/lib/teckel/chain/config.rb +246 -0
- data/lib/teckel/chain/result.rb +38 -0
- data/lib/teckel/chain/runner.rb +62 -0
- data/lib/teckel/chain/step.rb +18 -0
- data/lib/teckel/config.rb +41 -52
- data/lib/teckel/contracts.rb +19 -0
- data/lib/teckel/operation.rb +108 -253
- data/lib/teckel/operation/config.rb +396 -0
- data/lib/teckel/operation/result.rb +92 -0
- data/lib/teckel/operation/runner.rb +75 -0
- data/lib/teckel/result.rb +52 -53
- data/lib/teckel/version.rb +1 -1
- data/spec/chain/default_settings_spec.rb +39 -0
- data/spec/chain/inheritance_spec.rb +116 -0
- data/spec/chain/none_input_spec.rb +36 -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/contract_trace_spec.rb +116 -0
- data/spec/operation/default_settings_spec.rb +94 -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 +483 -0
- data/spec/rb27/pattern_matching_spec.rb +193 -0
- data/spec/result_spec.rb +22 -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 +64 -46
- data/.github/workflows/ci.yml +0 -67
- data/.github/workflows/pages.yml +0 -50
- data/.gitignore +0 -13
- data/.rspec +0 -3
- data/.rubocop.yml +0 -12
- data/.ruby-version +0 -1
- data/DEVELOPMENT.md +0 -28
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -71
- data/Rakefile +0 -30
- 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/operation/results.rb +0 -71
- data/teckel.gemspec +0 -33
data/.github/workflows/ci.yml
DELETED
@@ -1,67 +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
|
-
container:
|
54
|
-
image: ${{matrix.image}}
|
55
|
-
|
56
|
-
steps:
|
57
|
-
- uses: actions/checkout@v1
|
58
|
-
- name: Install git
|
59
|
-
run: |
|
60
|
-
apt-get update
|
61
|
-
apt-get install -y --no-install-recommends git
|
62
|
-
- name: Bundle install
|
63
|
-
run: |
|
64
|
-
gem install bundler
|
65
|
-
bundle install --jobs 4 --retry 3 --without tools docs benchmarks
|
66
|
-
- name: Run all tests
|
67
|
-
run: bundle exec rake
|
data/.github/workflows/pages.yml
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
name: pages
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches:
|
6
|
-
- master
|
7
|
-
paths:
|
8
|
-
- .github/workflows/pages.yml
|
9
|
-
- lib/**
|
10
|
-
- README.md
|
11
|
-
- .yardopts
|
12
|
-
- Rakefile
|
13
|
-
|
14
|
-
jobs:
|
15
|
-
build-docs:
|
16
|
-
runs-on: ubuntu-latest
|
17
|
-
steps:
|
18
|
-
- uses: actions/checkout@v2
|
19
|
-
- name: Set up Ruby
|
20
|
-
uses: actions/setup-ruby@v1
|
21
|
-
with:
|
22
|
-
ruby-version: 2.6.x
|
23
|
-
- name: Bundle install
|
24
|
-
run: |
|
25
|
-
gem install bundler
|
26
|
-
bundle install --jobs 4 --retry 3 --without tools docs benchmarks
|
27
|
-
- name: Build docs
|
28
|
-
run: 'bin/rake docs:yard'
|
29
|
-
- name: config git
|
30
|
-
run: |
|
31
|
-
git config --local user.email "action@github.com"
|
32
|
-
git config --local user.name "GitHub Action"
|
33
|
-
- name: Checkout Pages
|
34
|
-
run: 'git fetch origin gh-pages && git checkout gh-pages'
|
35
|
-
- name: Replace and commit docs
|
36
|
-
run: |
|
37
|
-
rm -rf doc && mv _yardoc doc
|
38
|
-
git add -A doc
|
39
|
-
git commit -m"Update API docs"
|
40
|
-
- name: Replace index
|
41
|
-
run: |
|
42
|
-
git checkout master README.md
|
43
|
-
mv -f README.md index.md
|
44
|
-
if [ ! -z "$(git diff --name-only -- index.md)" ]; then
|
45
|
-
git commit index.md -m"update index"
|
46
|
-
fi
|
47
|
-
- name: Push
|
48
|
-
env:
|
49
|
-
INPUT_GITHUB_TOKEN: "${{ secrets.DEPLOY_TOKEN }}"
|
50
|
-
run: git push https://git:${INPUT_GITHUB_TOKEN}@github.com/fnordfish/teckel.git gh-pages
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby-2.6.5
|
data/DEVELOPMENT.md
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# Development Guidelines
|
2
|
-
|
3
|
-
- Keep is simple.
|
4
|
-
- Favor easy debug-ability over clever solutions.
|
5
|
-
- Aim to be a 0-dependency lib (at runtime)
|
6
|
-
|
7
|
-
## Roadmap
|
8
|
-
|
9
|
-
- Add "Settings" for Operations and Chains
|
10
|
-
|
11
|
-
```
|
12
|
-
MyOp.with(foo: "bar").call("input")
|
13
|
-
|
14
|
-
class MyOp
|
15
|
-
settings Types::Hash.schema(foo: Types::String)
|
16
|
-
|
17
|
-
def call(input)
|
18
|
-
input == "input"
|
19
|
-
settings.foo == "bar"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
MyCain.with(:step1) { { foo: "bar" } }.with(:stepX) { { another: :setting} }.call(params)
|
24
|
-
```
|
25
|
-
- Add support for around hooks in Chains (for db transactions etc.)
|
26
|
-
- Add a dry-monads mixin to wrap Operations and Chains result/error into a Result Monad
|
27
|
-
- ...
|
28
|
-
|
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
teckel (0.1.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
concurrent-ruby (1.1.5)
|
10
|
-
diff-lcs (1.3)
|
11
|
-
dry-configurable (0.9.0)
|
12
|
-
concurrent-ruby (~> 1.0)
|
13
|
-
dry-core (~> 0.4, >= 0.4.7)
|
14
|
-
dry-container (0.7.2)
|
15
|
-
concurrent-ruby (~> 1.0)
|
16
|
-
dry-configurable (~> 0.1, >= 0.1.3)
|
17
|
-
dry-core (0.4.9)
|
18
|
-
concurrent-ruby (~> 1.0)
|
19
|
-
dry-equalizer (0.3.0)
|
20
|
-
dry-inflector (0.2.0)
|
21
|
-
dry-logic (1.0.5)
|
22
|
-
concurrent-ruby (~> 1.0)
|
23
|
-
dry-core (~> 0.2)
|
24
|
-
dry-equalizer (~> 0.2)
|
25
|
-
dry-struct (1.2.0)
|
26
|
-
dry-core (~> 0.4, >= 0.4.3)
|
27
|
-
dry-equalizer (~> 0.3)
|
28
|
-
dry-types (~> 1.0)
|
29
|
-
ice_nine (~> 0.11)
|
30
|
-
dry-types (1.2.2)
|
31
|
-
concurrent-ruby (~> 1.0)
|
32
|
-
dry-container (~> 0.3)
|
33
|
-
dry-core (~> 0.4, >= 0.4.4)
|
34
|
-
dry-equalizer (~> 0.3)
|
35
|
-
dry-inflector (~> 0.1, >= 0.1.2)
|
36
|
-
dry-logic (~> 1.0, >= 1.0.2)
|
37
|
-
ice_nine (0.11.2)
|
38
|
-
minitest (5.13.0)
|
39
|
-
rake (13.0.1)
|
40
|
-
rspec (3.9.0)
|
41
|
-
rspec-core (~> 3.9.0)
|
42
|
-
rspec-expectations (~> 3.9.0)
|
43
|
-
rspec-mocks (~> 3.9.0)
|
44
|
-
rspec-core (3.9.1)
|
45
|
-
rspec-support (~> 3.9.1)
|
46
|
-
rspec-expectations (3.9.0)
|
47
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
48
|
-
rspec-support (~> 3.9.0)
|
49
|
-
rspec-mocks (3.9.1)
|
50
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
51
|
-
rspec-support (~> 3.9.0)
|
52
|
-
rspec-support (3.9.2)
|
53
|
-
yard (0.9.22)
|
54
|
-
yard-doctest (0.1.17)
|
55
|
-
minitest
|
56
|
-
yard
|
57
|
-
|
58
|
-
PLATFORMS
|
59
|
-
ruby
|
60
|
-
|
61
|
-
DEPENDENCIES
|
62
|
-
bundler (~> 2.0)
|
63
|
-
dry-struct (>= 1.1.1, < 2)
|
64
|
-
rake (>= 10.0)
|
65
|
-
rspec (~> 3.0)
|
66
|
-
teckel!
|
67
|
-
yard
|
68
|
-
yard-doctest
|
69
|
-
|
70
|
-
BUNDLED WITH
|
71
|
-
2.1.2
|
data/Rakefile
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "bundler/gem_tasks"
|
4
|
-
require "rspec/core/rake_task"
|
5
|
-
require "yard"
|
6
|
-
require "yard/doctest/rake"
|
7
|
-
|
8
|
-
RSpec::Core::RakeTask.new(:spec)
|
9
|
-
|
10
|
-
namespace :docs do
|
11
|
-
YARD::Rake::YardocTask.new do |t|
|
12
|
-
t.files = ['lib/**/*.rb']
|
13
|
-
t.options = []
|
14
|
-
t.stats_options = ['--list-undoc']
|
15
|
-
end
|
16
|
-
|
17
|
-
task :fswatch do
|
18
|
-
sh 'fswatch -0 lib | while read -d "" e; do rake docs:yard; done'
|
19
|
-
end
|
20
|
-
|
21
|
-
YARD::Doctest::RakeTask.new do |task|
|
22
|
-
task.doctest_opts = %w[-v]
|
23
|
-
task.pattern = Dir.glob('lib/**/*.rb')
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
task :default do
|
28
|
-
Rake::Task["spec"].invoke
|
29
|
-
Rake::Task["docs:yard:doctest"].invoke
|
30
|
-
end
|
data/bin/console
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "bundler/setup"
|
5
|
-
require "teckel"
|
6
|
-
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
9
|
-
|
10
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
-
# require "pry"
|
12
|
-
# Pry.start
|
13
|
-
|
14
|
-
require "irb"
|
15
|
-
IRB.start(__FILE__)
|
data/bin/rake
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
#
|
5
|
-
# This file was generated by Bundler.
|
6
|
-
#
|
7
|
-
# The application 'rake' is installed as part of a gem, and
|
8
|
-
# this file is here to facilitate running it.
|
9
|
-
#
|
10
|
-
|
11
|
-
require "pathname"
|
12
|
-
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
-
Pathname.new(__FILE__).realpath)
|
14
|
-
|
15
|
-
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
-
|
17
|
-
if File.file?(bundle_binstub)
|
18
|
-
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
-
load(bundle_binstub)
|
20
|
-
else
|
21
|
-
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
-
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
require "rubygems"
|
27
|
-
require "bundler/setup"
|
28
|
-
|
29
|
-
load Gem.bin_path("rake", "rake")
|
data/bin/rspec
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
#
|
5
|
-
# This file was generated by Bundler.
|
6
|
-
#
|
7
|
-
# The application 'rspec' is installed as part of a gem, and
|
8
|
-
# this file is here to facilitate running it.
|
9
|
-
#
|
10
|
-
|
11
|
-
require "pathname"
|
12
|
-
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
-
Pathname.new(__FILE__).realpath)
|
14
|
-
|
15
|
-
bundle_binstub = File.expand_path('bundle', __dir__)
|
16
|
-
|
17
|
-
if File.file?(bundle_binstub)
|
18
|
-
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
-
load(bundle_binstub)
|
20
|
-
else
|
21
|
-
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
-
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
require "rubygems"
|
27
|
-
require "bundler/setup"
|
28
|
-
|
29
|
-
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/rubocop
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require 'bundler/inline'
|
5
|
-
require 'bundler'
|
6
|
-
|
7
|
-
# We need the `Bundler.settings.temporary` for a bundler bug:
|
8
|
-
# https://github.com/bundler/bundler/issues/7114
|
9
|
-
# Will get fixed in bundler version 2.1.0
|
10
|
-
Bundler.settings.temporary(frozen: false) do
|
11
|
-
gemfile do
|
12
|
-
source 'https://rubygems.org'
|
13
|
-
gem 'rubocop', '~> 0.78.0'
|
14
|
-
gem 'relaxed-rubocop', '2.4'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
load Gem.bin_path("rubocop", "rubocop")
|
data/bin/setup
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Teckel
|
4
|
-
module Operation
|
5
|
-
# Works just like +Teckel::Operation+, but wraps +output+ and +error+ into a +Teckel::Result+.
|
6
|
-
#
|
7
|
-
# A +Teckel::Result+ given as +input+ will get unwrapped, so that the original +value+
|
8
|
-
# gets passed to your Operation code.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
#
|
12
|
-
# class CreateUser
|
13
|
-
# include Teckel::Operation::Results
|
14
|
-
#
|
15
|
-
# input Types::Hash.schema(name: Types::String, age: Types::Coercible::Integer)
|
16
|
-
# output Types.Instance(User)
|
17
|
-
# error Types::Hash.schema(message: Types::String, errors: Types::Array.of(Types::Hash))
|
18
|
-
#
|
19
|
-
# # @param [Hash<name: String, age: Integer>]
|
20
|
-
# # @return [User | Hash<message: String, errors: [Hash]>]
|
21
|
-
# def call(input)
|
22
|
-
# user = User.new(name: input[:name], age: input[:age])
|
23
|
-
# if user.safe
|
24
|
-
# # exits early with success, prevents any further execution
|
25
|
-
# success!(user)
|
26
|
-
# else
|
27
|
-
# fail!(message: "Could not safe User", errors: user.errors)
|
28
|
-
# end
|
29
|
-
# end
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# # A success call:
|
33
|
-
# CreateUser.call(name: "Bob", age: 23).is_a?(Teckel::Result) #=> true
|
34
|
-
# CreateUser.call(name: "Bob", age: 23).success.is_a?(User) #=> true
|
35
|
-
#
|
36
|
-
# # A failure call:
|
37
|
-
# CreateUser.call(name: "Bob", age: 10).is_a?(Teckel::Result) #=> true
|
38
|
-
# CreateUser.call(name: "Bob", age: 10).failure.is_a?(Hash) #=> true
|
39
|
-
#
|
40
|
-
# # Unwrapping success input:
|
41
|
-
# CreateUser.call(Teckel::Result.new({name: "Bob", age: 23}, true)).success.is_a?(User) #=> true
|
42
|
-
#
|
43
|
-
# # Unwrapping failure input:
|
44
|
-
# CreateUser.call(Teckel::Result.new({name: "Bob", age: 23}, false)).success.is_a?(User) #=> true
|
45
|
-
#
|
46
|
-
# @api public
|
47
|
-
module Results
|
48
|
-
module InstanceMethods
|
49
|
-
private
|
50
|
-
|
51
|
-
def build_input(input)
|
52
|
-
input = input.value if input.is_a?(Teckel::Result)
|
53
|
-
super(input)
|
54
|
-
end
|
55
|
-
|
56
|
-
def build_output(*args)
|
57
|
-
Teckel::Result.new(super, true)
|
58
|
-
end
|
59
|
-
|
60
|
-
def build_error(*args)
|
61
|
-
Teckel::Result.new(super, false)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.included(receiver)
|
66
|
-
receiver.send :include, Teckel::Operation unless Teckel::Operation >= receiver
|
67
|
-
receiver.send :include, InstanceMethods
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|