typed_operation 0.2.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/README.md +32 -4
- data/lib/generators/USAGE +25 -0
- data/lib/generators/templates/operation.rb +35 -0
- data/lib/generators/templates/operation_test.rb +47 -0
- data/lib/generators/typed_operation/install/USAGE +21 -0
- data/lib/generators/typed_operation/install/install_generator.rb +23 -0
- data/lib/generators/typed_operation/install/templates/application_operation.rb +14 -0
- data/lib/generators/typed_operation_generator.rb +27 -0
- data/lib/typed_operation/base.rb +6 -7
- data/lib/typed_operation/railtie.rb +4 -0
- data/lib/typed_operation/version.rb +1 -1
- data/lib/typed_operation.rb +1 -2
- metadata +18 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c80a027434c29b23257b43e03eeb8acb61a3ac300a59e0c04068ffada1dd4aa6
|
4
|
+
data.tar.gz: 6b78a70b2a46710746129f8dac3a403bdc692c761c93f3ec111bf09efec8a70e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35baa03191cfa29e1786de975d7f8d2baf62040859922544f0d79109a8f088996521e85e3dce0c66bde1f7dd5bb2b62a5332cb7841a63a1ebe4b369d48005bb6
|
7
|
+
data.tar.gz: ebf8aea46fb0d3dcd72aa846b772f228aca21be2e04695989266218e9303e9b7760770d67f53f57ca231b41b7f502ad5145bf621a0648c6706b6e741a8e6c80e
|
data/README.md
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
# TypedOperation
|
2
|
-
Short description and motivation.
|
3
|
-
|
4
|
-
## Usage
|
5
2
|
|
6
3
|
An implementation of a Command pattern, which is callable, and can be partially applied (curried).
|
7
4
|
|
8
5
|
Inputs to the operation are specified as typed attributes using the `param` method.
|
9
6
|
|
10
|
-
|
7
|
+
Result format of the operation is up to you, but plays nicely with `Dry::Monads`.
|
11
8
|
|
12
9
|
### Examples:
|
13
10
|
|
@@ -15,6 +12,8 @@ A base operation class:
|
|
15
12
|
|
16
13
|
```ruby
|
17
14
|
class ApplicationOperation < ::TypedOperation::Base
|
15
|
+
include Dry::Monads[:result, :do]
|
16
|
+
|
18
17
|
param :initiator, ::RegisteredUser, allow_nil: true
|
19
18
|
|
20
19
|
private
|
@@ -96,6 +95,35 @@ Or install it yourself as:
|
|
96
95
|
$ gem install typed_operation
|
97
96
|
```
|
98
97
|
|
98
|
+
### Add an `ApplicationOperation` to your project
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
bin/rails g typed_operation:install
|
102
|
+
```
|
103
|
+
|
104
|
+
Use the `--dry_monads` switch to `include Dry::Monads[:result]` into your `ApplicationOperation` (don't forget to also
|
105
|
+
add `gem "dry-monads"` to your Gemfile)
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
bin/rails g typed_operation:install --dry_monads
|
109
|
+
```
|
110
|
+
|
111
|
+
## Generate a new Operation
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
bin/rails g typed_operation TestOperation
|
115
|
+
```
|
116
|
+
|
117
|
+
You can optionally specify the directory to generate the operation in:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
bin/rails g typed_operation TestOperation --path=app/operations
|
121
|
+
```
|
122
|
+
|
123
|
+
The default path is `app/operations`.
|
124
|
+
|
125
|
+
The generator will also create a test file.
|
126
|
+
|
99
127
|
## Contributing
|
100
128
|
Contribution directions go here.
|
101
129
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Operation Generator
|
2
|
+
===================
|
3
|
+
|
4
|
+
Description:
|
5
|
+
------------
|
6
|
+
This generator creates an 'TypedOperation' class that inherits from ApplicationOperation.
|
7
|
+
|
8
|
+
Command:
|
9
|
+
--------
|
10
|
+
rails generate typed_operation NAME [options]
|
11
|
+
|
12
|
+
Arguments:
|
13
|
+
----------
|
14
|
+
NAME: The class name of the Operation class to be generated, e.g. 'MyOperation'.
|
15
|
+
|
16
|
+
Options:
|
17
|
+
--------
|
18
|
+
--path=path/to/directory: The path to the directory in which the operation class should be generated. The generated class will be namespaced according to the provided path.
|
19
|
+
|
20
|
+
Example:
|
21
|
+
--------
|
22
|
+
rails generate typed_operation MyOperation --path=app/operations
|
23
|
+
|
24
|
+
This will create the following file:
|
25
|
+
app/operations/my_operation.rb
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<% if namespace_name.present? %>
|
4
|
+
module <%= namespace_name %>
|
5
|
+
class <%= name %> < ::ApplicationOperation
|
6
|
+
# Replace with implementation...
|
7
|
+
param :my_param, String, convert: true
|
8
|
+
param :an_optional_param, Integer, allow_nil: true
|
9
|
+
|
10
|
+
def prepare
|
11
|
+
# Prepare...
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
# Perform...
|
16
|
+
"Hello World!"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
<% else %>
|
21
|
+
class <%= name %> < ::ApplicationOperation
|
22
|
+
# Replace with implementation...
|
23
|
+
param :my_param, String, convert: true
|
24
|
+
param :an_optional_param, Integer, allow_nil: true
|
25
|
+
|
26
|
+
def prepare
|
27
|
+
# Prepare...
|
28
|
+
end
|
29
|
+
|
30
|
+
def call
|
31
|
+
# Perform...
|
32
|
+
"Hello World!"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
<% end %>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<% if namespace_name.present? %>
|
4
|
+
module <%= namespace_name %>
|
5
|
+
class <%= name %>Test < ActiveSupport::TestCase
|
6
|
+
def setup
|
7
|
+
@operation = <%= name %>.new(my_param: "test")
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'should raise ParameterError if my_param is nil' do
|
11
|
+
assert_raises(ParameterError) do
|
12
|
+
<%= name %>.new(my_param: nil)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
test 'should convert my_param if it is not a string' do
|
17
|
+
assert_equal <%= name %>.new(my_param: 123).my_param, "123"
|
18
|
+
end
|
19
|
+
|
20
|
+
test 'call returns after operation' do
|
21
|
+
result = @operation.call
|
22
|
+
assert_equal result, "Hello World!"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
<% else %>
|
27
|
+
class <%= name %>Test < ActiveSupport::TestCase
|
28
|
+
def setup
|
29
|
+
@operation = <%= name %>.new(my_param: "test")
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'should raise ParameterError if my_param is nil' do
|
33
|
+
assert_raises(ParameterError) do
|
34
|
+
<%= name %>.new(my_param: nil)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'should convert my_param if it is not a string' do
|
39
|
+
assert_equal <%= name %>.new(my_param: 123).my_param, "123"
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'call returns after operation' do
|
43
|
+
result = @operation.call
|
44
|
+
assert_equal result, "Hello World!"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Install Generator
|
2
|
+
=================
|
3
|
+
|
4
|
+
Description:
|
5
|
+
------------
|
6
|
+
This generator installs a `ApplicationOperation` class which is your base class for all Operations.
|
7
|
+
|
8
|
+
Command:
|
9
|
+
--------
|
10
|
+
rails generate typed_operation:install
|
11
|
+
|
12
|
+
Options:
|
13
|
+
--------
|
14
|
+
--dry_monads: if specified the ApplicationOperation will include dry-monads Result and Do notation.
|
15
|
+
|
16
|
+
Example:
|
17
|
+
--------
|
18
|
+
rails generate typed_operation:install
|
19
|
+
|
20
|
+
This will create the following file:
|
21
|
+
app/operations/application_operation.rb
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/base"
|
4
|
+
|
5
|
+
module TypedOperation
|
6
|
+
module Install
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
8
|
+
class_option :dry_monads, type: :boolean, default: false
|
9
|
+
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
def copy_application_operation_file
|
13
|
+
template "application_operation.rb", "app/operations/application_operation.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def include_dry_monads?
|
19
|
+
options[:dry_monads]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ApplicationOperation < ::TypedOperation::Base
|
4
|
+
<% if include_dry_monads? -%>
|
5
|
+
include Dry::Monads[:result, :do]
|
6
|
+
|
7
|
+
def call!
|
8
|
+
call.value!
|
9
|
+
end
|
10
|
+
|
11
|
+
<% end -%>
|
12
|
+
# Other common parameters & methods for Operations of this application...
|
13
|
+
# ...
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/named_base"
|
4
|
+
|
5
|
+
class TypedOperationGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
class_option :path, type: :string, default: "app/operations"
|
9
|
+
|
10
|
+
def generate_operation
|
11
|
+
template(
|
12
|
+
File.join(self.class.source_root, "operation.rb"),
|
13
|
+
File.join(options[:path], "#{file_name}.rb")
|
14
|
+
)
|
15
|
+
template(
|
16
|
+
File.join(self.class.source_root, "operation_test.rb"),
|
17
|
+
File.join("test/", options[:path].gsub(/\Aapp\//, ""), "#{file_name}_test.rb")
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def namespace_name
|
24
|
+
namespace_path = options[:path].gsub(/^app\/[^\/]*\//, "")
|
25
|
+
namespace_path.split("/").map(&:camelize).join("::")
|
26
|
+
end
|
27
|
+
end
|
data/lib/typed_operation/base.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "vident/typed"
|
4
4
|
require "vident/typed/attributes"
|
5
5
|
|
6
6
|
module TypedOperation
|
7
7
|
class Base
|
8
|
-
include Dry::Monads[:result, :do]
|
9
8
|
include Vident::Typed::Attributes
|
10
9
|
|
11
10
|
class << self
|
@@ -34,7 +33,11 @@ module TypedOperation
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def initialize(**attributes)
|
37
|
-
|
36
|
+
begin
|
37
|
+
prepare_attributes(attributes)
|
38
|
+
rescue ::Dry::Struct::Error => e
|
39
|
+
raise ParameterError, e.message
|
40
|
+
end
|
38
41
|
prepare if respond_to?(:prepare)
|
39
42
|
end
|
40
43
|
|
@@ -42,10 +45,6 @@ module TypedOperation
|
|
42
45
|
raise NotImplementedError, "You must implement #call"
|
43
46
|
end
|
44
47
|
|
45
|
-
def call!
|
46
|
-
call.value!
|
47
|
-
end
|
48
|
-
|
49
48
|
def to_proc
|
50
49
|
method(:call).to_proc
|
51
50
|
end
|
data/lib/typed_operation.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typed_operation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Ierodiaconou
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '6.0'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '8.0'
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '6.0'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '8.0'
|
@@ -45,26 +45,21 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 0.1.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name: dry-
|
48
|
+
name: dry-initializer
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '1'
|
54
|
-
- - "<"
|
51
|
+
- - "~>"
|
55
52
|
- !ruby/object:Gem::Version
|
56
|
-
version: '
|
53
|
+
version: '3.0'
|
57
54
|
type: :runtime
|
58
55
|
prerelease: false
|
59
56
|
version_requirements: !ruby/object:Gem::Requirement
|
60
57
|
requirements:
|
61
|
-
- - "
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: '1'
|
64
|
-
- - "<"
|
58
|
+
- - "~>"
|
65
59
|
- !ruby/object:Gem::Version
|
66
|
-
version: '
|
67
|
-
description: TypedOperation is a command pattern implementation
|
60
|
+
version: '3.0'
|
61
|
+
description: TypedOperation is a command pattern implementation where inputs can be
|
62
|
+
defined with runtime type checks. Operations can be partially applied.
|
68
63
|
email:
|
69
64
|
- stevegeek@gmail.com
|
70
65
|
executables: []
|
@@ -74,6 +69,13 @@ files:
|
|
74
69
|
- MIT-LICENSE
|
75
70
|
- README.md
|
76
71
|
- Rakefile
|
72
|
+
- lib/generators/USAGE
|
73
|
+
- lib/generators/templates/operation.rb
|
74
|
+
- lib/generators/templates/operation_test.rb
|
75
|
+
- lib/generators/typed_operation/install/USAGE
|
76
|
+
- lib/generators/typed_operation/install/install_generator.rb
|
77
|
+
- lib/generators/typed_operation/install/templates/application_operation.rb
|
78
|
+
- lib/generators/typed_operation_generator.rb
|
77
79
|
- lib/tasks/typed_operation_tasks.rake
|
78
80
|
- lib/typed_operation.rb
|
79
81
|
- lib/typed_operation/base.rb
|