typed_operation 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 895e2a58caa6a8a40c35d3eff22b9429fed9f0c49627f275cd583ce0c2fe4bc6
4
+ data.tar.gz: 794004ac749b5ff9df514827a794ef01917e5ca4bdd2b887a5e8ea06b491a097
5
+ SHA512:
6
+ metadata.gz: e81f633626fbd914bae0c232c22d1c9b5e44cc2169691fd022c408dbbbad15179062a8d641b03f6165a033c946cde10ad740b971b636c05fc85c7f828ed643c1
7
+ data.tar.gz: 65e4065dded231777a7b2ed40ef901268da46e7d8403a20edb642d5ea815e15b280a8b46a64d24753de67daab3d7e50b9985fe6bebe6898c19f98386bb8020f8
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2023 Stephen Ierodiaconou
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # TypedOperation
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+
6
+ An implementation of a Command pattern, which is callable, and can be partially applied (curried).
7
+
8
+ Inputs to the operation are specified as typed attributes using the `param` method.
9
+
10
+ Results of the operation are a type of `Dry::Monads::Result` object.
11
+
12
+ ### Examples:
13
+
14
+ A base operation class:
15
+
16
+ ```ruby
17
+ class ApplicationOperation < ::TypedOperation::Base
18
+ param :initiator, ::RegisteredUser, allow_nil: true
19
+
20
+ private
21
+
22
+ def succeeded(value)
23
+ Success(value)
24
+ end
25
+
26
+ def failed_with_value(value, message: "Operation failed", error_code: nil)
27
+ failed(error_code || self.class.operation_key, message, value)
28
+ end
29
+
30
+ def failed_with_message(message, error_code: nil)
31
+ failed(error_code || self.class.operation_key, message)
32
+ end
33
+
34
+ def failed(error_code, message = "Operation failed", value = nil)
35
+ Failure[error_code, message, value]
36
+ end
37
+
38
+ def failed_with_code_and_value(error_code, value, message: "Operation failed")
39
+ failed(error_code, message, value)
40
+ end
41
+ end
42
+
43
+ ```
44
+
45
+ A simple operation:
46
+
47
+ ```ruby
48
+ class TestOperation < ::ApplicationOperation
49
+ param :foo, String
50
+ param :bar, String
51
+ param :baz, String, convert: true
52
+
53
+ def prepare
54
+ # to setup (optional)
55
+ puts "lets go!"
56
+ end
57
+
58
+ def call
59
+ succeeded("It worked!")
60
+ # failed_with_message("It failed!")
61
+ end
62
+ end
63
+ ```
64
+
65
+ ```ruby
66
+ TestOperation.(foo: "1", bar: "2", baz: 3)
67
+ # => Success("It worked!")
68
+
69
+ TestOperation.with(foo: "1").with(bar: "2")
70
+ # => #<TypedOperation::PartiallyApplied:0x000000014a655310 @applied_args={:foo=>"1", :bar=>"2"}, @operation=TestOperation>
71
+
72
+ TestOperation.with(foo: "1").with(bar: "2").with(baz: 3)
73
+ # => <TypedOperation::Prepared:0x000000012dac6498 @applied_args={:foo=>"1", :bar=>"2", :baz=>3}, @operation=TestOperation>
74
+
75
+ TestOperation.with(foo: "1").with(bar: "2").with(baz: 3).call
76
+ # => Success("It worked!")
77
+
78
+ TestOperation.with(foo: "1").with(bar: "2").with(baz: 3).operation
79
+ # => <TestOperation:0x000000014a0048a8 @__attributes=#<TestOperation::TypedSchema foo="1" bar="2" baz="3">>
80
+ ```
81
+
82
+ ## Installation
83
+ Add this line to your application's Gemfile:
84
+
85
+ ```ruby
86
+ gem "typed_operation"
87
+ ```
88
+
89
+ And then execute:
90
+ ```bash
91
+ $ bundle
92
+ ```
93
+
94
+ Or install it yourself as:
95
+ ```bash
96
+ $ gem install typed_operation
97
+ ```
98
+
99
+ ## Contributing
100
+ Contribution directions go here.
101
+
102
+ ## License
103
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :typed_operation do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TypedOperation
4
+ class Base
5
+ include Dry::Monads[:result, :do]
6
+ include Vident::Typed::Attributes
7
+
8
+ class << self
9
+ def call(...)
10
+ new(...).call
11
+ end
12
+
13
+ def curry(**args)
14
+ PartiallyApplied.new(self, **args).curry
15
+ end
16
+ alias_method :[], :curry
17
+ alias_method :with, :curry
18
+
19
+ def to_proc
20
+ method(:call).to_proc
21
+ end
22
+
23
+ def operation_key
24
+ name.underscore.to_sym
25
+ end
26
+
27
+ # property are required by default, you can fall back to attribute or set allow_nil: true if you want optional
28
+ def param(name, signature = :any, **options, &converter)
29
+ attribute(name, signature, **{allow_nil: false}.merge(options), &converter)
30
+ end
31
+ end
32
+
33
+ def initialize(**attributes)
34
+ prepare_attributes(attributes)
35
+ prepare if respond_to?(:prepare)
36
+ end
37
+
38
+ def call
39
+ raise NotImplementedError, "You must implement #call"
40
+ end
41
+
42
+ def call!
43
+ call.value!
44
+ end
45
+
46
+ def to_proc
47
+ method(:call).to_proc
48
+ end
49
+
50
+ private
51
+
52
+ def operation_key
53
+ self.class.operation_key
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TypedOperation
4
+ class PartiallyApplied
5
+ def initialize(operation, **applied_args)
6
+ @operation = operation
7
+ @applied_args = applied_args
8
+ end
9
+
10
+ def curry(**params)
11
+ all_args = @applied_args.merge(params)
12
+ # check if required attrs are in @applied_args
13
+ required_keys = @operation.attribute_names.select { |name| @operation.attribute_metadata(name)[:required] != false }
14
+ missing_keys = required_keys - all_args.keys
15
+
16
+ if missing_keys.size > 0
17
+ # Partially apply the arguments
18
+ PartiallyApplied.new(@operation, **all_args)
19
+ else
20
+ Prepared.new(@operation, **all_args)
21
+ end
22
+ end
23
+ alias_method :[], :curry
24
+ alias_method :with, :curry
25
+
26
+ def call(...)
27
+ prepared = curry(...)
28
+ return prepared.operation.call if prepared.is_a?(Prepared)
29
+ raise "Cannot call PartiallyApplied operation #{@operation.name} (key: #{@operation.operation_key}), are you expecting it to be Prepared?"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TypedOperation
4
+ class Prepared < PartiallyApplied
5
+ def operation
6
+ @operation.new(**@applied_args)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module TypedOperation
2
+ class Railtie < ::Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module TypedOperation
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require "typed_operation/version"
2
+ require "typed_operation/railtie"
3
+ require "typed_operation/base"
4
+ require "typed_operation/prepared"
5
+ require "typed_operation/partially_applied"
6
+
7
+ module TypedOperation
8
+ # Your code goes here...
9
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typed_operation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Ierodiaconou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '7.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: vident-typed
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.1.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: dry-monads
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">"
52
+ - !ruby/object:Gem::Version
53
+ version: '1'
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '2'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">"
62
+ - !ruby/object:Gem::Version
63
+ version: '1'
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '2'
67
+ description: TypedOperation is a command pattern implementation
68
+ email:
69
+ - stevegeek@gmail.com
70
+ executables: []
71
+ extensions: []
72
+ extra_rdoc_files: []
73
+ files:
74
+ - MIT-LICENSE
75
+ - README.md
76
+ - Rakefile
77
+ - lib/tasks/typed_operation_tasks.rake
78
+ - lib/typed_operation.rb
79
+ - lib/typed_operation/base.rb
80
+ - lib/typed_operation/partially_applied.rb
81
+ - lib/typed_operation/prepared.rb
82
+ - lib/typed_operation/railtie.rb
83
+ - lib/typed_operation/version.rb
84
+ homepage: https://github.com/stevegeek/typed_operation
85
+ licenses:
86
+ - MIT
87
+ metadata:
88
+ homepage_uri: https://github.com/stevegeek/typed_operation
89
+ source_code_uri: https://github.com/stevegeek/typed_operation
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.4.10
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: TypedOperation is a command pattern implementation
109
+ test_files: []