on_strum-service 1.0.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: 696f119acc51ed572b6d30d377e94fd6c403682f0b0b70f3e9f6d6c7c28d56a1
4
+ data.tar.gz: c3b13982bb28f3b082e3a0d28fbcb63999f6997ccd10a9a03d76eabcfc3d8902
5
+ SHA512:
6
+ metadata.gz: 5251dc7e864e3c73e68d1bcb3dbadc2d7e6ad67b70edf1e758d2f97b0a0ff9426e54c0bf41cb4824c2a1106ecc3ad120c882617b7b070783af9649e68fc2f26a
7
+ data.tar.gz: 5cddb35de5cd273d962396edce2e7b95f7c09074452dacb6de19b7fc60833fe14d77be8a9a3013f4f3fbc99bb2aa1e2401e273bac0c9abc52818db7539a88276
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.5.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 onStrum and friends
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'on_strum/service'
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/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ module ClassMethods
6
+ def call(ctx, **args, &block)
7
+ new(ctx, **args).execute(&block)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ module Error
6
+ require_relative 'error/runtime'
7
+ end
8
+
9
+ require_relative 'version'
10
+ require_relative 'class_methods'
11
+ require_relative 'instance_methods'
12
+ require_relative '../service'
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ module Error
6
+ class Runtime < ::RuntimeError
7
+ NOT_IMPLEMENTED = 'call method must be implemented'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ module InstanceMethods
6
+ COERCIVE_METHODS = %i[add_error add_errors any required sliced sliced_list].freeze
7
+ DEFAULT_CTX_KEY = :default
8
+
9
+ def initialize(ctx, **args)
10
+ self.errors = ::Hash.new { |hash, key| hash[key] = [] }
11
+ self.handlers = { on: {}, success: {}, failure: {} }
12
+ self.outputs = {}
13
+ self.inputs = args.merge(OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY => ctx)
14
+ self.inputs_snapshot = inputs.dup.freeze
15
+ init_default_proc
16
+ end
17
+
18
+ def execute
19
+ catch(:exit) do
20
+ yield(self) if block_given?
21
+ audit
22
+ call if valid?
23
+ end
24
+ valid? ? valid_result : invalid_result
25
+ end
26
+
27
+ def hook(name, data = self)
28
+ handlers_on_name = handlers.dig(:on, name)
29
+ handlers_on_name.is_a?(::Proc) && handlers_on_name.call(data)
30
+ end
31
+
32
+ def valid?
33
+ errors.empty?
34
+ end
35
+
36
+ def on(direction, &block)
37
+ handlers[:on][direction] = block
38
+ end
39
+
40
+ def success(direction = nil, &block)
41
+ handlers[:success][direction] = block
42
+ end
43
+
44
+ def failure(direction = nil, &block)
45
+ handlers[:failure][direction] = block
46
+ end
47
+
48
+ def method_missing(method_name, *_args, &_block)
49
+ if from_input?(method_name)
50
+ input[method_name]
51
+ elsif from_inputs?(method_name)
52
+ inputs[method_name]
53
+ else
54
+ super
55
+ end
56
+ end
57
+
58
+ def respond_to_missing?(method_name, include_private = false)
59
+ from_input?(method_name) || from_inputs?(method_name) || super
60
+ end
61
+
62
+ protected
63
+
64
+ attr_accessor :inputs, :inputs_snapshot, :errors, :outputs, :handlers
65
+
66
+ def input
67
+ inputs[OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY]
68
+ end
69
+
70
+ def input=(value)
71
+ inputs[OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY] = value
72
+ end
73
+
74
+ def input_snapshot
75
+ inputs_snapshot[OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY]
76
+ end
77
+
78
+ def args
79
+ inputs.slice(*inputs.keys - [OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY])
80
+ end
81
+
82
+ def output_value(key = OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY)
83
+ @outputs[key]
84
+ end
85
+
86
+ def output(key = OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY, value) # rubocop:disable Style/OptionalArguments
87
+ @outputs[key] = value
88
+ end
89
+
90
+ def add_error(field, value)
91
+ errors[field] += Array(value)
92
+ end
93
+
94
+ def add_errors(errors)
95
+ errors.each { |field, value| add_error(field, value) }
96
+ end
97
+
98
+ def required(*keys)
99
+ return add_error(:input, :must_be_hash) unless input_hash?
100
+
101
+ (keys - service_keys).each { |key| add_error(key, :field_must_exist) }
102
+ end
103
+
104
+ def any(*keys)
105
+ return add_error(:input, :must_be_hash) unless input_hash?
106
+
107
+ add_error(:input, :any_field_must_exist) if (keys & service_keys).empty?
108
+ end
109
+
110
+ def sliced(*keys)
111
+ return add_error(:input, :must_be_hash) unless input_hash?
112
+
113
+ self.input = input.merge(args).slice(*keys)
114
+ end
115
+
116
+ def sliced_list(*keys)
117
+ add_error(:input, :must_be_array) && return unless input.is_a?(::Array)
118
+ add_error(:input_subitem, :must_be_hash) && return unless input.all?(::Hash)
119
+
120
+ self.input = input.map { |item| item.slice(*keys) }
121
+ end
122
+
123
+ def service_keys
124
+ input.keys | args.keys
125
+ end
126
+
127
+ OnStrum::Service::InstanceMethods::COERCIVE_METHODS.each do |method_name|
128
+ define_method(:"#{method_name}!") do |*args, **kwargs, &block|
129
+ send(method_name, *args, **kwargs, &block)
130
+ throw :exit unless valid?
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ def method_s_sym(method_name)
137
+ [method_name.to_s, method_name.to_sym]
138
+ end
139
+
140
+ def from_input?(method_name)
141
+ method_key, method_sym = method_s_sym(method_name)
142
+ args.empty? && input_hash? && (input.key?(method_key) || input.key?(method_sym))
143
+ end
144
+
145
+ def from_inputs?(method_name)
146
+ method_key, method_sym = method_s_sym(method_name)
147
+ inputs.key?(method_key) || inputs.key?(method_sym)
148
+ end
149
+
150
+ def input_hash?
151
+ input.is_a?(::Hash)
152
+ end
153
+
154
+ def default_proc
155
+ proc do |hash, key| # string lookup in case accessing to hash by symbol
156
+ key = key.to_s
157
+ hash.key?(key) ? hash[key] : nil
158
+ end
159
+ end
160
+
161
+ def init_default_proc
162
+ inputs.default_proc = default_proc
163
+ input.default_proc = default_proc if input_hash?
164
+ end
165
+
166
+ def handler_key
167
+ ((outputs.keys << nil) & handlers[:success].keys).first
168
+ end
169
+
170
+ def valid_result
171
+ result = outputs[handler_key] || outputs[OnStrum::Service::InstanceMethods::DEFAULT_CTX_KEY]
172
+ handler = handlers[:success][handler_key]
173
+ return result unless handler.is_a?(::Proc)
174
+
175
+ handler.call(result)
176
+ end
177
+
178
+ def invalid_result
179
+ handlers_failure = handlers[:failure]
180
+ handler = handlers_failure[((errors.values.flatten << nil) & handlers_failure.keys).first]
181
+ handler.call(errors) if handler.is_a?(::Proc)
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ def self.included(base)
6
+ base.extend(OnStrum::Service::ClassMethods)
7
+ base.prepend(OnStrum::Service::InstanceMethods)
8
+ end
9
+
10
+ def audit; end
11
+
12
+ def call
13
+ raise OnStrum::Service::Error::Runtime, OnStrum::Service::Error::Runtime::NOT_IMPLEMENTED
14
+ end
15
+ end
16
+ end
data/lib/on_strum.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnStrum
4
+ module Service
5
+ require_relative 'on_strum/service/core'
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/on_strum/service/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'on_strum-service'
7
+ spec.version = OnStrum::Service::VERSION
8
+ spec.authors = ['Serhiy Nazarov']
9
+ spec.email = %w[admin@on-strum.org]
10
+
11
+ spec.summary = %(on_strum-service)
12
+ spec.description = %(Abstract class for service object scaffolding)
13
+
14
+ spec.homepage = 'https://github.com/on-strum/ruby-on-strum-service'
15
+ spec.license = 'MIT'
16
+
17
+ spec.metadata = {
18
+ 'homepage_uri' => 'https://github.com/on-strum/ruby-on-strum-service',
19
+ 'changelog_uri' => 'https://github.com/on-strum/ruby-on-strum-service/blob/master/CHANGELOG.md',
20
+ 'source_code_uri' => 'https://github.com/on-strum/ruby-on-strum-service',
21
+ 'documentation_uri' => 'https://github.com/on-strum/ruby-on-strum-service/blob/master/README.md',
22
+ 'bug_tracker_uri' => 'https://github.com/on-strum/ruby-on-strum-service/issues'
23
+ }
24
+
25
+ spec.required_ruby_version = '>= 2.5.0'
26
+ spec.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r{^(bin|lib)/|.ruby-version|on_strum-service.gemspec|LICENSE}) }
27
+ spec.require_paths = %w[lib]
28
+
29
+ spec.add_development_dependency 'ffaker', '~> 2.21'
30
+ spec.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6'
31
+ spec.add_development_dependency 'rspec', '~> 3.12'
32
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: on_strum-service
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Serhiy Nazarov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffaker
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.21'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.21'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 13.0.6
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '13.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 13.0.6
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.12'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.12'
61
+ description: Abstract class for service object scaffolding
62
+ email:
63
+ - admin@on-strum.org
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - ".ruby-version"
69
+ - LICENSE.txt
70
+ - bin/console
71
+ - bin/setup
72
+ - lib/on_strum.rb
73
+ - lib/on_strum/service.rb
74
+ - lib/on_strum/service/class_methods.rb
75
+ - lib/on_strum/service/core.rb
76
+ - lib/on_strum/service/error/runtime.rb
77
+ - lib/on_strum/service/instance_methods.rb
78
+ - lib/on_strum/service/version.rb
79
+ - on_strum-service.gemspec
80
+ homepage: https://github.com/on-strum/ruby-on-strum-service
81
+ licenses:
82
+ - MIT
83
+ metadata:
84
+ homepage_uri: https://github.com/on-strum/ruby-on-strum-service
85
+ changelog_uri: https://github.com/on-strum/ruby-on-strum-service/blob/master/CHANGELOG.md
86
+ source_code_uri: https://github.com/on-strum/ruby-on-strum-service
87
+ documentation_uri: https://github.com/on-strum/ruby-on-strum-service/blob/master/README.md
88
+ bug_tracker_uri: https://github.com/on-strum/ruby-on-strum-service/issues
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 2.5.0
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 3.4.10
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: on_strum-service
108
+ test_files: []