teckel 0.1.0 → 0.6.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +114 -0
  3. data/LICENSE_LOGO +4 -0
  4. data/README.md +22 -14
  5. data/lib/teckel.rb +11 -2
  6. data/lib/teckel/chain.rb +47 -152
  7. data/lib/teckel/chain/config.rb +246 -0
  8. data/lib/teckel/chain/result.rb +38 -0
  9. data/lib/teckel/chain/runner.rb +62 -0
  10. data/lib/teckel/chain/step.rb +18 -0
  11. data/lib/teckel/config.rb +41 -52
  12. data/lib/teckel/contracts.rb +19 -0
  13. data/lib/teckel/operation.rb +108 -253
  14. data/lib/teckel/operation/config.rb +396 -0
  15. data/lib/teckel/operation/result.rb +92 -0
  16. data/lib/teckel/operation/runner.rb +75 -0
  17. data/lib/teckel/result.rb +52 -53
  18. data/lib/teckel/version.rb +1 -1
  19. data/spec/chain/default_settings_spec.rb +39 -0
  20. data/spec/chain/inheritance_spec.rb +116 -0
  21. data/spec/chain/none_input_spec.rb +36 -0
  22. data/spec/chain/results_spec.rb +53 -0
  23. data/spec/chain_around_hook_spec.rb +100 -0
  24. data/spec/chain_spec.rb +180 -0
  25. data/spec/config_spec.rb +26 -0
  26. data/spec/doctest_helper.rb +7 -0
  27. data/spec/operation/contract_trace_spec.rb +116 -0
  28. data/spec/operation/default_settings_spec.rb +94 -0
  29. data/spec/operation/inheritance_spec.rb +94 -0
  30. data/spec/operation/result_spec.rb +34 -0
  31. data/spec/operation/results_spec.rb +117 -0
  32. data/spec/operation_spec.rb +483 -0
  33. data/spec/rb27/pattern_matching_spec.rb +193 -0
  34. data/spec/result_spec.rb +22 -0
  35. data/spec/spec_helper.rb +25 -0
  36. data/spec/support/dry_base.rb +8 -0
  37. data/spec/support/fake_db.rb +12 -0
  38. data/spec/support/fake_models.rb +20 -0
  39. data/spec/teckel_spec.rb +7 -0
  40. metadata +64 -46
  41. data/.github/workflows/ci.yml +0 -67
  42. data/.github/workflows/pages.yml +0 -50
  43. data/.gitignore +0 -13
  44. data/.rspec +0 -3
  45. data/.rubocop.yml +0 -12
  46. data/.ruby-version +0 -1
  47. data/DEVELOPMENT.md +0 -28
  48. data/Gemfile +0 -8
  49. data/Gemfile.lock +0 -71
  50. data/Rakefile +0 -30
  51. data/bin/console +0 -15
  52. data/bin/rake +0 -29
  53. data/bin/rspec +0 -29
  54. data/bin/rubocop +0 -18
  55. data/bin/setup +0 -8
  56. data/lib/teckel/operation/results.rb +0 -71
  57. data/teckel.gemspec +0 -33
@@ -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
+ success! 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
+ success!(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
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'support/dry_base'
4
+ require 'support/fake_models'
5
+
6
+ module TeckelResultTest
7
+ class MissingResultImplementation
8
+ include Teckel::Result
9
+ def initialize(value, success); end
10
+ end
11
+ end
12
+
13
+ RSpec.describe Teckel::Result do
14
+ describe "missing initialize" do
15
+ specify do
16
+ result = TeckelResultTest::MissingResultImplementation["value", true]
17
+ expect { result.successful? }.to raise_error(NotImplementedError)
18
+ expect { result.failure? }.to raise_error(NotImplementedError)
19
+ expect { result.value }.to raise_error(NotImplementedError)
20
+ end
21
+ end
22
+ end
@@ -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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-types'
4
+ require 'dry-struct'
5
+
6
+ module Types
7
+ include Dry.Types()
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FakeDB
4
+ Rollback = Class.new(RuntimeError)
5
+
6
+ def self.transaction
7
+ yield
8
+ rescue Rollback
9
+ # doing rollback ...
10
+ raise
11
+ end
12
+ 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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Teckel do
4
+ it "has a version number" do
5
+ expect(Teckel::VERSION).not_to be nil
6
+ end
7
+ end
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.1.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Schulze
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-02 00:00:00.000000000 Z
11
+ date: 2020-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,26 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: dry-struct
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.1.1
34
- - - "<"
35
- - !ruby/object:Gem::Version
36
- version: '2'
37
- type: :development
38
- prerelease: false
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 1.1.1
44
- - - "<"
45
- - !ruby/object:Gem::Version
46
- version: '2'
47
27
  - !ruby/object:Gem::Dependency
48
28
  name: rake
49
29
  requirement: !ruby/object:Gem::Requirement
@@ -108,38 +88,55 @@ executables: []
108
88
  extensions: []
109
89
  extra_rdoc_files: []
110
90
  files:
111
- - ".github/workflows/ci.yml"
112
- - ".github/workflows/pages.yml"
113
- - ".gitignore"
114
- - ".rspec"
115
- - ".rubocop.yml"
116
- - ".ruby-version"
117
91
  - ".yardopts"
118
92
  - CHANGELOG.md
119
- - DEVELOPMENT.md
120
- - Gemfile
121
- - Gemfile.lock
122
93
  - LICENSE
94
+ - LICENSE_LOGO
123
95
  - README.md
124
- - Rakefile
125
- - bin/console
126
- - bin/rake
127
- - bin/rspec
128
- - bin/rubocop
129
- - bin/setup
130
96
  - lib/teckel.rb
131
97
  - lib/teckel/chain.rb
98
+ - lib/teckel/chain/config.rb
99
+ - lib/teckel/chain/result.rb
100
+ - lib/teckel/chain/runner.rb
101
+ - lib/teckel/chain/step.rb
132
102
  - lib/teckel/config.rb
103
+ - lib/teckel/contracts.rb
133
104
  - lib/teckel/operation.rb
134
- - lib/teckel/operation/results.rb
105
+ - lib/teckel/operation/config.rb
106
+ - lib/teckel/operation/result.rb
107
+ - lib/teckel/operation/runner.rb
135
108
  - lib/teckel/result.rb
136
109
  - lib/teckel/version.rb
137
- - teckel.gemspec
138
- homepage: https://github.com/dotless-de/teckel
110
+ - spec/chain/default_settings_spec.rb
111
+ - spec/chain/inheritance_spec.rb
112
+ - spec/chain/none_input_spec.rb
113
+ - spec/chain/results_spec.rb
114
+ - spec/chain_around_hook_spec.rb
115
+ - spec/chain_spec.rb
116
+ - spec/config_spec.rb
117
+ - spec/doctest_helper.rb
118
+ - spec/operation/contract_trace_spec.rb
119
+ - spec/operation/default_settings_spec.rb
120
+ - spec/operation/inheritance_spec.rb
121
+ - spec/operation/result_spec.rb
122
+ - spec/operation/results_spec.rb
123
+ - spec/operation_spec.rb
124
+ - spec/rb27/pattern_matching_spec.rb
125
+ - spec/result_spec.rb
126
+ - spec/spec_helper.rb
127
+ - spec/support/dry_base.rb
128
+ - spec/support/fake_db.rb
129
+ - spec/support/fake_models.rb
130
+ - spec/teckel_spec.rb
131
+ homepage: https://github.com/fnordfish/teckel
139
132
  licenses:
140
133
  - Apache-2.0
141
- metadata: {}
142
- post_install_message:
134
+ metadata:
135
+ changelog_uri: https://github.com/github.com/fnordfish/blob/master/CHANGELOG.md
136
+ source_code_uri: https://github.com/github.com/fnordfish
137
+ bug_tracker_uri: https://github.com/github.com/fnordfish/issues
138
+ documentation_uri: https://www.rubydoc.info/gems/teckel/0.6.0
139
+ post_install_message:
143
140
  rdoc_options: []
144
141
  require_paths:
145
142
  - lib
@@ -147,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
147
144
  requirements:
148
145
  - - ">="
149
146
  - !ruby/object:Gem::Version
150
- version: '0'
147
+ version: 2.4.0
151
148
  required_rubygems_version: !ruby/object:Gem::Requirement
152
149
  requirements:
153
150
  - - ">="
@@ -155,7 +152,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
152
  version: '0'
156
153
  requirements: []
157
154
  rubygems_version: 3.0.3
158
- signing_key:
155
+ signing_key:
159
156
  specification_version: 4
160
157
  summary: Operations with enforced in/out/err data structures
161
- test_files: []
158
+ test_files:
159
+ - spec/chain/default_settings_spec.rb
160
+ - spec/chain/inheritance_spec.rb
161
+ - spec/chain/none_input_spec.rb
162
+ - spec/chain/results_spec.rb
163
+ - spec/chain_around_hook_spec.rb
164
+ - spec/chain_spec.rb
165
+ - spec/config_spec.rb
166
+ - spec/doctest_helper.rb
167
+ - spec/operation/contract_trace_spec.rb
168
+ - spec/operation/default_settings_spec.rb
169
+ - spec/operation/inheritance_spec.rb
170
+ - spec/operation/result_spec.rb
171
+ - spec/operation/results_spec.rb
172
+ - spec/operation_spec.rb
173
+ - spec/rb27/pattern_matching_spec.rb
174
+ - spec/result_spec.rb
175
+ - spec/spec_helper.rb
176
+ - spec/support/dry_base.rb
177
+ - spec/support/fake_db.rb
178
+ - spec/support/fake_models.rb
179
+ - spec/teckel_spec.rb