typed_operation 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []