on_strum-service 1.0.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: 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: []