smart_operation 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54cb9fb84904049ae0b50b5c025894d03514795ed7e44a3a665d75701064c869
4
- data.tar.gz: 3392debe732ff5d2f0eeb38909b5e78d3ac3da3a50ec90bf610d5d1f21b932b7
3
+ metadata.gz: 1453c74d289398cb24928e6f6d79fdc6f0188f8c95cf2622ef31d63841bdf796
4
+ data.tar.gz: 521ae1a830b8ad8674e6012d7190f79382eb7501bd181431e49e7177f00c4b72
5
5
  SHA512:
6
- metadata.gz: faaf96bb0a1563803d6dbf2ffc479aff7b8e45b273725d9a958c739b7c617d7ef5540608f3bfba3afb2eb3dec349ff141df4a9e6a3f8f107a6f90e4c0951f597
7
- data.tar.gz: de57323f81dcf36f546f4335acc95e7f62d85462460fcb71e763863879dd45a87ee2fb77018e82d21f6bd9d7d7800db5dc80356b30b182847993f32a89edb341
6
+ metadata.gz: 351fb2c08fc514cf2461e7f90d51a4a8fa2cd2731ab20be006461b8edeebb0ffe4f6d2c725f40a9f56ff7b8296710f0ee3b767d6b6ecf08561cd95122b561a3a
7
+ data.tar.gz: 89246f9e0c6d0a919c269f00449c82bc06b35ac00c7c549f9dda002fb13276f2563a389f49924cb17b3edc5b97210222a53154482c8c4932fb08771c67bc8e6b
@@ -5,7 +5,7 @@ inherit_gem:
5
5
  - lib/rubocop.rspec.yml
6
6
 
7
7
  AllCops:
8
- TargetRubyVersion: 2.4.9
8
+ TargetRubyVersion: 2.7.1
9
9
  Include:
10
10
  - lib/**/*.rb
11
11
  - spec/**/*.rb
@@ -2,17 +2,18 @@
2
2
  language: ruby
3
3
  cache: bundler
4
4
  os: linux
5
- before_install: gem install bundler -v 2.1.2
5
+ dist: xenial
6
+ before_install: gem install bundler
6
7
  script:
7
8
  - bundle exec rake rubocop
8
9
  - bundle exec rake rspec
9
10
  jobs:
10
11
  fast_finish: true
11
12
  include:
12
- - rvm: 2.4.9
13
- - rvm: 2.5.7
14
- - rvm: 2.6.5
15
- - rvm: 2.7.0
13
+ - rvm: 2.4.10
14
+ - rvm: 2.5.8
15
+ - rvm: 2.6.6
16
+ - rvm: 2.7.1
16
17
  - rvm: ruby-head
17
18
  - rvm: jruby-head
18
19
  allow_failures:
@@ -1,2 +1,5 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
+
4
+ # [0.1.0] - 2020-07-10
5
+ - Realease :)
@@ -1,77 +1,109 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_operation (0.0.0)
5
- smart_engine (~> 0.5)
4
+ smart_operation (0.1.0)
5
+ smart_engine (~> 0.7)
6
+ smart_initializer (~> 0.2)
7
+ smart_injection (~> 0.1)
6
8
 
7
9
  GEM
8
10
  remote: https://rubygems.org/
9
11
  specs:
10
- armitage-rubocop (0.79.0)
11
- rubocop (= 0.79.0)
12
- rubocop-performance (= 1.5.2)
13
- rubocop-rails (= 2.4.1)
14
- rubocop-rake (= 0.5.0)
15
- rubocop-rspec (= 1.37.1)
16
- ast (2.4.0)
17
- diff-lcs (1.3)
12
+ activesupport (6.0.3.2)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ zeitwerk (~> 2.2, >= 2.2.2)
18
+ armitage-rubocop (0.87.1.1)
19
+ rubocop (= 0.87.1)
20
+ rubocop-performance (= 1.7.0)
21
+ rubocop-rails (= 2.6.0)
22
+ rubocop-rake (= 0.5.1)
23
+ rubocop-rspec (= 1.41.0)
24
+ ast (2.4.1)
25
+ concurrent-ruby (1.1.6)
26
+ diff-lcs (1.4.4)
18
27
  docile (1.3.2)
19
- jaro_winkler (1.5.4)
20
- json (2.3.0)
21
- parallel (1.19.1)
22
- parser (2.7.0.2)
23
- ast (~> 2.4.0)
24
- rack (2.1.1)
28
+ i18n (1.8.3)
29
+ concurrent-ruby (~> 1.0)
30
+ minitest (5.14.1)
31
+ parallel (1.19.2)
32
+ parser (2.7.1.4)
33
+ ast (~> 2.4.1)
34
+ qonfig (0.24.1)
35
+ rack (2.2.3)
25
36
  rainbow (3.0.0)
26
37
  rake (13.0.1)
38
+ regexp_parser (1.7.1)
39
+ rexml (3.2.4)
27
40
  rspec (3.9.0)
28
41
  rspec-core (~> 3.9.0)
29
42
  rspec-expectations (~> 3.9.0)
30
43
  rspec-mocks (~> 3.9.0)
31
- rspec-core (3.9.1)
32
- rspec-support (~> 3.9.1)
33
- rspec-expectations (3.9.0)
44
+ rspec-core (3.9.2)
45
+ rspec-support (~> 3.9.3)
46
+ rspec-expectations (3.9.2)
34
47
  diff-lcs (>= 1.2.0, < 2.0)
35
48
  rspec-support (~> 3.9.0)
36
49
  rspec-mocks (3.9.1)
37
50
  diff-lcs (>= 1.2.0, < 2.0)
38
51
  rspec-support (~> 3.9.0)
39
- rspec-support (3.9.2)
40
- rubocop (0.79.0)
41
- jaro_winkler (~> 1.5.1)
52
+ rspec-support (3.9.3)
53
+ rubocop (0.87.1)
42
54
  parallel (~> 1.10)
43
- parser (>= 2.7.0.1)
55
+ parser (>= 2.7.1.1)
44
56
  rainbow (>= 2.2.2, < 4.0)
57
+ regexp_parser (>= 1.7)
58
+ rexml
59
+ rubocop-ast (>= 0.1.0, < 1.0)
45
60
  ruby-progressbar (~> 1.7)
46
- unicode-display_width (>= 1.4.0, < 1.7)
47
- rubocop-performance (1.5.2)
48
- rubocop (>= 0.71.0)
49
- rubocop-rails (2.4.1)
61
+ unicode-display_width (>= 1.4.0, < 2.0)
62
+ rubocop-ast (0.1.0)
63
+ parser (>= 2.7.0.1)
64
+ rubocop-performance (1.7.0)
65
+ rubocop (>= 0.82.0)
66
+ rubocop-rails (2.6.0)
67
+ activesupport (>= 4.2.0)
50
68
  rack (>= 1.1)
51
- rubocop (>= 0.72.0)
52
- rubocop-rake (0.5.0)
69
+ rubocop (>= 0.82.0)
70
+ rubocop-rake (0.5.1)
53
71
  rubocop
54
- rubocop-rspec (1.37.1)
72
+ rubocop-rspec (1.41.0)
55
73
  rubocop (>= 0.68.1)
56
74
  ruby-progressbar (1.10.1)
57
- simplecov (0.17.1)
75
+ simplecov (0.18.5)
58
76
  docile (~> 1.1)
59
- json (>= 1.8, < 3)
60
- simplecov-html (~> 0.10.0)
61
- simplecov-html (0.10.2)
62
- smart_engine (0.5.0)
63
- unicode-display_width (1.6.1)
77
+ simplecov-html (~> 0.11)
78
+ simplecov-html (0.12.2)
79
+ smart_container (0.8.1)
80
+ smart_engine (~> 0.5)
81
+ smart_engine (0.7.0)
82
+ smart_initializer (0.2.0)
83
+ qonfig (~> 0.24)
84
+ smart_engine (~> 0.6)
85
+ smart_types (~> 0.1.0)
86
+ smart_injection (0.1.0)
87
+ smart_container (~> 0.8, >= 0.8.1)
88
+ smart_engine (~> 0.7)
89
+ smart_types (0.1.0)
90
+ smart_engine (~> 0.6)
91
+ thread_safe (0.3.6)
92
+ tzinfo (1.2.7)
93
+ thread_safe (~> 0.1)
94
+ unicode-display_width (1.7.0)
95
+ zeitwerk (2.3.1)
64
96
 
65
97
  PLATFORMS
66
98
  ruby
67
99
 
68
100
  DEPENDENCIES
69
- armitage-rubocop (~> 0.78)
101
+ armitage-rubocop (~> 0.87)
70
102
  bundler (~> 2.1)
71
103
  rake (~> 13.0)
72
104
  rspec (~> 3.9)
73
- simplecov (~> 0.17)
105
+ simplecov (~> 0.18)
74
106
  smart_operation!
75
107
 
76
108
  BUNDLED WITH
77
- 2.1.2
109
+ 2.1.4
data/README.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  Smart implementation of the most-used programming pattern - Service Object.
4
4
 
5
+ > previous generation: https://github.com/0exp/smart_core
6
+
7
+ ---
8
+
9
+ ## Main features
10
+
11
+ - multifunctional constructor DSL (powerd by [smart_initializer](https://github.com/smart-rb/smart_initializer) and [smart_types](https://github.com/smart-rb/smart_types));
12
+ - result object interface (`Success`, `Failure`, `Fatal`, `Callback`);
13
+ - `call.new.call` invocation behavior;
14
+ - support for dependency injection (powered by [smart_injection](https://github.com/smart-rb/smart_injection) and [smart_container](https://github.com/smart-rb/smart_container));
15
+
16
+ ---
17
+
5
18
  ## Installation
6
19
 
7
20
  ```ruby
@@ -20,6 +33,56 @@ require 'smart_core/operation'
20
33
 
21
34
  ---
22
35
 
36
+ ## Synopsis
37
+
38
+ ```ruby
39
+ class CreateUser < SmartCore::Operation
40
+ register_container(ReposContainer)
41
+
42
+ import({ user_repo: 'business.users' }, access: :private)
43
+
44
+ option :name, 'value.string'
45
+ option :password, 'value.string'
46
+ option :age, 'value.integer'
47
+
48
+ def call
49
+ user = user_repo.create({ name: name, password: password, age: age })
50
+ Success(user: user) # or Callback { puts 'wow o.O' }
51
+ end
52
+ end
53
+
54
+ CreateUser.call(name: 'Rustam', password: 'test123', age: 28) do |result|
55
+ result.success? { puts 'success!' }
56
+ result.failure? { puts 'failure!' }
57
+ result.fatal? { puts 'fatal!' }
58
+ result.callback? { result.call } # or some_object.instance_eval(&result.callback)
59
+ end
60
+ ```
61
+
62
+ Pre-requisits:
63
+
64
+ ```ruby
65
+ class UserRepo
66
+ def create(user_creds)
67
+ # ... some code
68
+ end
69
+ end
70
+
71
+ ReposContainer = SmartCore::Container.define do
72
+ namespace(:business) do
73
+ register(:users) { UserRepo.new }
74
+ end
75
+ end
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Roadmap
81
+
82
+ - pattern matching for result objects (`Success`, `Failure`, `Fatal`, `Callback`);
83
+
84
+ ---
85
+
23
86
  ## Contributing
24
87
 
25
88
  - Fork it ( https://github.com/smart-rb/smart_operation )
data/Rakefile CHANGED
@@ -4,6 +4,7 @@ require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
  require 'rubocop'
6
6
  require 'rubocop/rake_task'
7
+ require 'rubocop-rails'
7
8
  require 'rubocop-performance'
8
9
  require 'rubocop-rspec'
9
10
  require 'rubocop-rake'
@@ -11,8 +12,8 @@ require 'rubocop-rake'
11
12
  RuboCop::RakeTask.new(:rubocop) do |t|
12
13
  config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
13
14
  t.options = ['--config', config_path]
14
- t.requires << 'rubocop-performance'
15
15
  t.requires << 'rubocop-rspec'
16
+ t.requires << 'rubocop-performance'
16
17
  t.requires << 'rubocop-rake'
17
18
  end
18
19
 
@@ -1,9 +1,63 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'smart_core'
4
+ require 'smart_core/injection'
5
+ require 'smart_core/initializer'
4
6
 
5
7
  # @api public
6
8
  # @since 0.1.0
7
- class SmartCore::Operation
8
- require_relative 'operation/version'
9
+ module SmartCore
10
+ # @api public
11
+ # @since 0.1.0
12
+ class Operation
13
+ require_relative 'operation/version'
14
+ require_relative 'operation/errors'
15
+ require_relative 'operation/result'
16
+ require_relative 'operation/interface'
17
+ require_relative 'operation/instance_builder'
18
+ require_relative 'operation/class_constructor'
19
+
20
+ class << self
21
+ # @param child_klass [Class]
22
+ # @return [void]
23
+ #
24
+ # @api private
25
+ # @since 0.1.0
26
+ def inherited(child_klass)
27
+ SmartCore::Operation::ClassConstructor.construct(child_klass)
28
+ super
29
+ end
30
+ end
31
+
32
+ # @since 0.1.0
33
+ include SmartCore::Operation::Interface::Result
34
+ # @since 0.1.0
35
+ include SmartCore::Operation::Interface::Callable
36
+ # @since 0.1.0
37
+ include SmartCore::Operation::Interface::DI
38
+
39
+ # @return [SmartCore::Operation::Result::Success]
40
+ # @return [SmartCore::Operation::Result::Callback]
41
+ # @return [SmartCore::Operation::Result::Failure]
42
+ # @return [SmartCore::Operation::Result::Fatal]
43
+ #
44
+ # @api public
45
+ # @since 0.1.0
46
+ def call
47
+ Success()
48
+ end
49
+ end
50
+
51
+ class << self
52
+ # @param type_system [String, Symbol]
53
+ # @return [Class<SmartCore::Operation>]
54
+ #
55
+ # @api public
56
+ # @since 0.1.0
57
+ # rubocop:disable Naming/MethodName
58
+ def Operation(type_system: SmartCore::Operation::ClassConsructor.default_type_system)
59
+ SmartCore::Operation::ClassConsructor.construct(type_system: type_system)
60
+ end
61
+ # rubocop:enable Naming/MethodName
62
+ end
9
63
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Operation::ClassConstructor
6
+ require_relative 'class_constructor/parameters'
7
+
8
+ # @return [SmartCore::Engine::Lock]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ CONSYSTENCY_CONTROL = SmartCore::Engine::Lock.new
13
+
14
+ class << self
15
+ # @param klass [Class, Class<SmartCore::Operation>]
16
+ # @option type_system [String, Symbol]
17
+ # @return [Class<SmartCore::Operation>]
18
+ #
19
+ # @api private
20
+ # @since 0.1.0
21
+ def construct(klass = Class.new(SmartCore::Operation), type_system: default_type_system)
22
+ klass.tap do
23
+ consistent do
24
+ parameters = Parameters.new(type_system: type_system)
25
+ inject_initializer_interface(klass, parameters)
26
+ end
27
+ end
28
+ end
29
+
30
+ # @return [String, Symbol]
31
+ #
32
+ # @api private
33
+ # @since 0.1.0
34
+ def default_type_system
35
+ SmartCore::Initializer::Configuration[:default_type_system]
36
+ end
37
+
38
+ private
39
+
40
+ # @param klass [Class, Class<SmartCore::Operation>]
41
+ # @param parameters [SmartCore::Operation::ClassConstructor::Parameters]
42
+ # @return [void]
43
+ #
44
+ # @api private
45
+ # @since 0.1.0
46
+ def inject_initializer_interface(klass, parameters)
47
+ unless klass < SmartCore::Initializer
48
+ klass.include(SmartCore::Initializer(type_system: parameters.type_system))
49
+ klass.ext_init { |instance| SmartCore::Operation::InstanceBuilder.call(instance) }
50
+ end
51
+ end
52
+
53
+ # @param block [Block]
54
+ # @return [Any]
55
+ #
56
+ # @api private
57
+ # @since 0.1.0
58
+ def consistent(&block)
59
+ CONSYSTENCY_CONTROL.synchronize(&block)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::ClassConstructor::Parameters
6
+ # @return [String, Symbol]
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ attr_reader :type_system
11
+
12
+ # @param type_system [String, Symbol]
13
+ # @return [void]
14
+ #
15
+ # @api private
16
+ # @since 0.1.0
17
+ def initialize(type_system:)
18
+ @type_system = type_system
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SmartCore::Operation
4
+ # @api public
5
+ # @since 0.1.0
6
+ Error = Class.new(SmartCore::Error)
7
+
8
+ # @api public
9
+ # @since 0.1.0
10
+ ArgumentError = Class.new(SmartCore::ArgumentError)
11
+
12
+ # @api public
13
+ # @since 0.1.0
14
+ ResultCoreMethodOverlapError = Class.new(Error)
15
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::InstanceBuilder
6
+ class << self
7
+ # @param operation [SmartCore::Operation]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def call(operation)
13
+ new(operation).call
14
+ end
15
+ end
16
+
17
+ # @param operation [SmartCore::Operation]
18
+ # @return [void]
19
+ #
20
+ # @api private
21
+ # @since 0.1.0
22
+ def initialize(operation)
23
+ @operation = operation
24
+ end
25
+
26
+ # @return [void]
27
+ #
28
+ # @api private
29
+ # @since 0.1.0
30
+ def call
31
+ make_operation_caller_yieldable
32
+ end
33
+
34
+ private
35
+
36
+ # @return [SmartCore::Operation]
37
+ #
38
+ # @api private
39
+ # @since 0.1.0
40
+ attr_reader :operation
41
+
42
+ # @return [void]
43
+ #
44
+ # @api private
45
+ # @since 0.1.0
46
+ def make_operation_caller_yieldable
47
+ operation.singleton_class.prepend(Module.new do
48
+ def call
49
+ super.tap { |result| yield(result) if block_given? }
50
+ rescue SmartCore::Operation::Result::Fatal::FatalError => error
51
+ # NOTE: returns SmartCore::Operation::Result::Fatal instance
52
+ error.__operation_result__.tap { |result| yield(result) if block_given? }
53
+ end
54
+ end)
55
+ end
56
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Operation::Interface
6
+ require_relative 'interface/result'
7
+ require_relative 'interface/callable'
8
+ require_relative 'interface/di'
9
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module SmartCore::Operation::Interface::Callable
6
+ class << self
7
+ # @param base_klass [Class]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def included(base_klass)
13
+ base_klass.extend(ClassMethods)
14
+ end
15
+ end
16
+
17
+ # @api private
18
+ # @since 0.1.0
19
+ module ClassMethods
20
+ # @param arguments [Array<Any>]
21
+ # @param block [Block]
22
+ # @return [Any]
23
+ #
24
+ # @api public
25
+ # @since 0.1.0
26
+ def call(*arguments, &block)
27
+ new(*arguments).call(&block)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module SmartCore::Operation::Interface::DI
6
+ class << self
7
+ # @param base_klass [Class]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def included(base_klass)
13
+ base_klass.include(::SmartCore::Injection)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module SmartCore::Operation::Interface::Result
6
+ # @param result_attributes [Hash<Symbol,Any>]
7
+ # @return [SmartCore::Operation::Result::Success]
8
+ #
9
+ # @api public
10
+ # @since 0.1.0
11
+ def Success(**result_attributes)
12
+ SmartCore::Operation::Result::Success.new(**result_attributes)
13
+ end
14
+
15
+ # @param result_attributs [Array<Any>]
16
+ # @return [SmartCore::Operation::Result::Failure]
17
+ #
18
+ # @api public
19
+ # @since 0.1.0
20
+ def Failure(*result_attributes)
21
+ SmartCore::Operation::Result::Failure.new(*result_attributes)
22
+ end
23
+
24
+ # @param result_attributes [Array<Any>]
25
+ # @return [SmartCore::Operation::Result::Fatal]
26
+ #
27
+ # @api public
28
+ # @since 0.1.0
29
+ def Fatal(*result_attributes)
30
+ raise(SmartCore::Operation::Result::Fatal.new(*result_attributes))
31
+ end
32
+
33
+ # @param callback [Block]
34
+ # @return [SmartCore::Operation::Result::Callback]
35
+ #
36
+ # @api public
37
+ # @since 0.1.0
38
+ def Callback(&callback)
39
+ SmartCore::Operation::Result::Callback.new(&callback)
40
+ end
41
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Operation::Result
6
+ require_relative 'result/basic'
7
+ require_relative 'result/success'
8
+ require_relative 'result/error'
9
+ require_relative 'result/failure'
10
+ require_relative 'result/fatal'
11
+ require_relative 'result/callback'
12
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Basic
6
+ # @param result_arguments [Array<Any>]
7
+ # @param result_block [Block]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def initialize(*result_arguments, &result_block)
13
+ @__initial_result_arguments__ = result_arguments
14
+ @__result_parameters__, @__result_options__ = __extract_result_attributes__(result_arguments)
15
+ @__result_block__ = result_block
16
+ __after_initialize__
17
+ end
18
+
19
+ # @return [Boolean]
20
+ #
21
+ # @api public
22
+ # @since 0.1.0
23
+ def success?
24
+ false
25
+ end
26
+
27
+ # @return [Boolean]
28
+ #
29
+ # @api public
30
+ # @since 0.1.0
31
+ def failure?
32
+ false
33
+ end
34
+
35
+ # @return [Boolean]
36
+ #
37
+ # @api public
38
+ # @since 0.1.0
39
+ def fatal?
40
+ false
41
+ end
42
+
43
+ # @return [Boolean]
44
+ #
45
+ # @api public
46
+ # @since 0.1.0
47
+ def callback?
48
+ false
49
+ end
50
+
51
+ private
52
+
53
+ # @return [Array<Any>]
54
+ #
55
+ # @api private
56
+ # @since 0.1.0
57
+ attr_reader :__initial_result_arguments__
58
+
59
+ # @return [Array<Any>]
60
+ #
61
+ # @api private
62
+ # @since 0.1.0
63
+ attr_reader :__result_parameters__
64
+
65
+ # @return [Hash<Symbol,Any>]
66
+ #
67
+ # @api private
68
+ # @since 0.1.0
69
+ attr_reader :__result_options__
70
+
71
+ # @return [Proc]
72
+ #
73
+ # @api private
74
+ # @since 0.1.0
75
+ attr_reader :__result_block__
76
+
77
+ # @param result_arguments [Array<Any>]
78
+ # @return [Array<Array<Any>,Hash<Symbol,Any>>]
79
+ #
80
+ # @api private
81
+ # @since 0.1.0
82
+ def __extract_result_attributes__(result_arguments)
83
+ extracted_parameters = []
84
+ extracted_options = {}
85
+
86
+ if (
87
+ result_arguments.last.is_a?(Hash) &&
88
+ result_arguments.last.keys.all? { |key| key.is_a?(Symbol) }
89
+ )
90
+ extracted_parameters = result_arguments[0..-2]
91
+ extracted_options = result_arguments.last
92
+ else
93
+ extracted_parameters = result_arguments
94
+ end
95
+
96
+ [extracted_parameters, extracted_options]
97
+ end
98
+
99
+ # @return [void]
100
+ #
101
+ # @api private
102
+ # @since 0.1.0
103
+ def __after_initialize__; end
104
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Callback < SmartCore::Operation::Result::Basic
6
+ # @return [NilClass]
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ EMPTY_INVOKATION_CONTEXT = nil
11
+
12
+ # @return [Proc]
13
+ #
14
+ # @api public
15
+ # @since 0.1.0
16
+ alias_method :callback, :__result_block__
17
+ public :callback
18
+
19
+ # @param context [Any]
20
+ # @return [Any]
21
+ #
22
+ # @api public
23
+ # @since 0.1.0
24
+ def call(context = EMPTY_INVOKATION_CONTEXT)
25
+ context == EMPTY_INVOKATION_CONTEXT ? callback.call : context.instance_eval(&callback)
26
+ end
27
+
28
+ # @yield [SmartCore::Operation::Result::Callback]
29
+ # @return [Boolean]
30
+ #
31
+ # @api public
32
+ # @since 0.1.0
33
+ def callback?
34
+ true.tap { yield(self) if block_given? }
35
+ end
36
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Error < SmartCore::Operation::Result::Basic
6
+ require_relative 'error/code'
7
+ require_relative 'error/context'
8
+ require_relative 'error/case'
9
+ require_relative 'error/set'
10
+
11
+ # @return [SmartCore::Operation::Result::Error::Set]
12
+ #
13
+ # @api public
14
+ # @since 0.1.0
15
+ attr_reader :errors
16
+
17
+ # @yield [SmartCore::Operation::Result::Error]
18
+ # @return [Boolean]
19
+ #
20
+ # @api public
21
+ # @since 0.1.0
22
+ def error?
23
+ true.tap { yield(self) if block_given? }
24
+ end
25
+
26
+ # @return [Array<String|Symbol|Any>]
27
+ #
28
+ # @api public
29
+ # @since 0.1.0
30
+ def error_codes
31
+ errors.codes
32
+ end
33
+
34
+ # @return [Hash<String|Symbol,Any>]
35
+ #
36
+ # @api public
37
+ # @since 0.1.0
38
+ def error_context
39
+ errors.context
40
+ end
41
+
42
+ # @return [void]
43
+ #
44
+ # @api public
45
+ # @since 0.1.0
46
+ def each_error(&block)
47
+ errors.each(&block)
48
+ end
49
+
50
+ private
51
+
52
+ # @return [void]
53
+ #
54
+ # @api private
55
+ # @since 0.1.0
56
+ def __after_initialize__
57
+ @errors = SmartCore::Operation::Result::Error::Set.build(
58
+ __result_parameters__,
59
+ __result_options__
60
+ )
61
+ end
62
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Error::Case
6
+ # @param code [String, Symbol, Any]
7
+ # @param context [Hash, Any]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def initialize(
13
+ code: SmartCore::Operation::Result::Error::Code::EMPTY_CODE,
14
+ context: SmartCore::Operation::Result::Error::Context::EMPTY_CONTEXT
15
+ )
16
+ @code = SmartCore::Operation::Result::Error::Code.new(code)
17
+ @context = SmartCore::Operation::Result::Error::Context.new(context)
18
+ end
19
+
20
+ # @return [String, Symbol, NilClass, Any]
21
+ #
22
+ # @api public
23
+ # @since 0.1.0
24
+ def code
25
+ @code.identifier
26
+ end
27
+
28
+ # @return [Hash]
29
+ #
30
+ # @api public
31
+ # @since 0.1.0
32
+ def context
33
+ @context.data
34
+ end
35
+
36
+ # @return [Hash<Synbol,Any>]
37
+ #
38
+ # @api public
39
+ # @since 0.1.0
40
+ def to_h
41
+ { code: code, context: context }
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Error::Code
6
+ # @return [NilClass]
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ EMPTY_CODE = nil
11
+
12
+ # @return [String, Symbol, NilClass, Any]
13
+ #
14
+ # @api public
15
+ # @since 0.1.0
16
+ attr_reader :code
17
+ alias_method :identifier, :code
18
+
19
+ # @param code [String, Symbol, NilClass, Any]
20
+ # @return [void]
21
+ #
22
+ # @api private
23
+ # @since 0.1.0
24
+ def initialize(code)
25
+ @code = code
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Error::Context
6
+ # @return [Hash]
7
+ #
8
+ # @api private
9
+ # @since 0.1.0
10
+ EMPTY_CONTEXT = {}.freeze
11
+
12
+ # @return [Hash, Any]
13
+ #
14
+ # @api private
15
+ # @since 0.1.0
16
+ attr_reader :context
17
+
18
+ # @param context [Hash, Any]
19
+ # @return [void]
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ def initialize(context = EMPTY_CONTEXT.dup)
24
+ @context = context
25
+ end
26
+
27
+ # @retunr [Hash]
28
+ #
29
+ # @api public
30
+ # @since 0.1.0
31
+ def to_h
32
+ context.to_h
33
+ end
34
+ alias_method :data, :to_h
35
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Error::Set
6
+ # @since 0.1.0
7
+ include Enumerable
8
+
9
+ class << self
10
+ # @param error_codes [Array<String, Symbol, Any>]
11
+ # @param error_context [Hash<String|Symbol,Any>]
12
+ # @return [SmartCore::Operation::Result::Error::Set]
13
+ #
14
+ # @api private
15
+ # @since 0.1.0
16
+ def build(error_codes, error_context)
17
+ error_cases =
18
+ if error_codes.empty?
19
+ [SmartCore::Operation::Result::Error::Case.new(context: error_context)]
20
+ else
21
+ error_codes.map do |error_code|
22
+ SmartCore::Operation::Result::Error::Case.new(
23
+ code: error_code,
24
+ context: error_context
25
+ )
26
+ end
27
+ end
28
+
29
+ new(error_cases)
30
+ end
31
+ end
32
+
33
+ # @return [Array<SmartCore::Operation::Result::Error::Case>]
34
+ #
35
+ # @api private
36
+ # @since 0.1.0
37
+ attr_reader :cases
38
+
39
+ # @param cases [Array<SmartCore::Operation::Result::Error::Case>]
40
+ # @return [void]
41
+ #
42
+ # @api private
43
+ # @since 0.1.0
44
+ def initialize(cases)
45
+ @cases = cases.freeze
46
+ end
47
+
48
+ # @return [Array<String|Symbol|Any>]
49
+ #
50
+ # @api public
51
+ # @since 0.1.0
52
+ def codes
53
+ cases.map(&:code)
54
+ end
55
+
56
+ # @return [Hash<String|Symbol,Any>]
57
+ #
58
+ # @api public
59
+ # @since 0.1.0
60
+ def context
61
+ cases.sample.context
62
+ end
63
+
64
+ # @return [void]
65
+ #
66
+ # @api public
67
+ # @sicne 0.1.0
68
+ def each(&block)
69
+ cases.each(&block)
70
+ end
71
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Failure < SmartCore::Operation::Result::Error
6
+ # @yield [SmartCore::Operation::Result::Failure]
7
+ # @return [Boolean]
8
+ #
9
+ # @api public
10
+ # @since 0.1.0
11
+ def failure?
12
+ true.tap { yield(self) if block_given? }
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Fatal < SmartCore::Operation::Result::Error
6
+ # @api private
7
+ # @since 0.1.0
8
+ class FatalError < SmartCore::Operation::Error
9
+ # @return [SmartCore::Operation::Result::Fatal]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ attr_reader :__operation_result__
14
+
15
+ # @param operation_result [SmartCore::Operation::Result::Fatal]
16
+ # @return [void]
17
+ #
18
+ # @api private
19
+ # @since 0.1.0
20
+ def initialize(operation_result)
21
+ @__operation_result__ = operation_result
22
+ end
23
+ end
24
+
25
+ # @retrun [Smart::Operation::Result::Fatal::FatalError]
26
+ #
27
+ # @api private
28
+ # @since 0.1.0
29
+ def exception
30
+ FatalError.new(self)
31
+ end
32
+
33
+ # @yield [SmartCore::Operation::Result::Fatal]
34
+ # @return [Boolean]
35
+ #
36
+ # @api public
37
+ # @since 0.1.0
38
+ def fatal?
39
+ true.tap { yield(self) if block_given? }
40
+ end
41
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ class SmartCore::Operation::Result::Success < SmartCore::Operation::Result::Basic
6
+ # @param result_options [Hash<Symbol,Any>]
7
+ # @return [void]
8
+ #
9
+ # @api public
10
+ # @since 0.1.0
11
+ def initialize(**result_options)
12
+ __prevent_core_methods_overlapping__(result_options)
13
+ super(result_options)
14
+ __define_virtual_acessors__(result_options)
15
+ end
16
+
17
+ # @yield [SmartCore::Operation::Result::Success]
18
+ # @return [Boolean]
19
+ #
20
+ # @api public
21
+ # @since 0.1.0
22
+ def success?
23
+ true.tap { yield(self) if block_given? }
24
+ end
25
+
26
+ # @return [Hash<Symbol,Any>]
27
+ #
28
+ # @api public
29
+ # @since 0.1.0
30
+ def to_h
31
+ __result_options__.dup
32
+ end
33
+ alias_method :to_hash, :to_h
34
+
35
+ private
36
+
37
+ # @param result_options [Hash<Symbol,Any>]
38
+ # @return [void]
39
+ #
40
+ # @api private
41
+ # @since 0.1.0
42
+ def __prevent_core_methods_overlapping__(result_options)
43
+ overlappings = result_options.each_key.each_with_object([]) do |key, overlap|
44
+ overlap << key if self.class.____core_methods____.include?(key)
45
+ end
46
+
47
+ if overlappings.any?
48
+ raise(SmartCore::Operation::ResultCoreMethodOverlapError, <<~ERROR_MESSAGE)
49
+ Result keys can not overlap core methods (operlapped keys: #{overlappings.join(', ')}).
50
+ ERROR_MESSAGE
51
+ end
52
+ end
53
+
54
+ # @param result_options [Hash<Symbol,Any>]
55
+ # @return [void]
56
+ #
57
+ # @api private
58
+ # @since 0.1.0
59
+ def __define_virtual_acessors__(result_options)
60
+ result_options.each_key do |result_attribute_name|
61
+ define_singleton_method(result_attribute_name) do
62
+ result_options[result_attribute_name]
63
+ end
64
+ end
65
+ end
66
+
67
+ # @since 0.1.0
68
+ core_methods = [
69
+ *instance_methods(false),
70
+ *private_instance_methods(false),
71
+ *superclass.instance_methods(false),
72
+ *superclass.private_instance_methods(false),
73
+ :____core_methods____
74
+ ].freeze
75
+
76
+ # @return [Array<Symbol>]
77
+ #
78
+ # @api private
79
+ # @since 0.2.0
80
+ define_singleton_method(:____core_methods____) { core_methods }
81
+ end
@@ -6,6 +6,6 @@ module SmartCore
6
6
  #
7
7
  # @api public
8
8
  # @since 0.1.0
9
- VERSION = '0.0.0'
9
+ VERSION = '0.1.0'
10
10
  end
11
11
  end
@@ -3,7 +3,7 @@
3
3
  require_relative 'lib/smart_core/operation/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.required_ruby_version = Gem::Requirement.new('>= 2.4.9')
6
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.4.10')
7
7
 
8
8
  spec.name = 'smart_operation'
9
9
  spec.version = SmartCore::Operation::VERSION
@@ -27,11 +27,13 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
- spec.add_dependency 'smart_engine', '~> 0.5'
30
+ spec.add_dependency 'smart_injection', '~> 0.1'
31
+ spec.add_dependency 'smart_engine', '~> 0.7'
32
+ spec.add_dependency 'smart_initializer', '~> 0.2'
31
33
 
32
34
  spec.add_development_dependency 'bundler', '~> 2.1'
33
35
  spec.add_development_dependency 'rake', '~> 13.0'
34
36
  spec.add_development_dependency 'rspec', '~> 3.9'
35
- spec.add_development_dependency 'armitage-rubocop', '~> 0.78'
36
- spec.add_development_dependency 'simplecov', '~> 0.17'
37
+ spec.add_development_dependency 'armitage-rubocop', '~> 0.87'
38
+ spec.add_development_dependency 'simplecov', '~> 0.18'
37
39
  end
metadata CHANGED
@@ -1,29 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_operation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rustam Ibragimov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-26 00:00:00.000000000 Z
11
+ date: 2020-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: smart_injection
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: smart_engine
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '0.5'
33
+ version: '0.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: smart_initializer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
20
48
  type: :runtime
21
49
  prerelease: false
22
50
  version_requirements: !ruby/object:Gem::Requirement
23
51
  requirements:
24
52
  - - "~>"
25
53
  - !ruby/object:Gem::Version
26
- version: '0.5'
54
+ version: '0.2'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -72,28 +100,28 @@ dependencies:
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: '0.78'
103
+ version: '0.87'
76
104
  type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
- version: '0.78'
110
+ version: '0.87'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: simplecov
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
- version: '0.17'
117
+ version: '0.18'
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
- version: '0.17'
124
+ version: '0.18'
97
125
  description: Smart implementation of the most-used programming pattern - Service Object
98
126
  email:
99
127
  - iamdaiver@gmail.com
@@ -115,6 +143,25 @@ files:
115
143
  - bin/console
116
144
  - bin/setup
117
145
  - lib/smart_core/operation.rb
146
+ - lib/smart_core/operation/class_constructor.rb
147
+ - lib/smart_core/operation/class_constructor/parameters.rb
148
+ - lib/smart_core/operation/errors.rb
149
+ - lib/smart_core/operation/instance_builder.rb
150
+ - lib/smart_core/operation/interface.rb
151
+ - lib/smart_core/operation/interface/callable.rb
152
+ - lib/smart_core/operation/interface/di.rb
153
+ - lib/smart_core/operation/interface/result.rb
154
+ - lib/smart_core/operation/result.rb
155
+ - lib/smart_core/operation/result/basic.rb
156
+ - lib/smart_core/operation/result/callback.rb
157
+ - lib/smart_core/operation/result/error.rb
158
+ - lib/smart_core/operation/result/error/case.rb
159
+ - lib/smart_core/operation/result/error/code.rb
160
+ - lib/smart_core/operation/result/error/context.rb
161
+ - lib/smart_core/operation/result/error/set.rb
162
+ - lib/smart_core/operation/result/failure.rb
163
+ - lib/smart_core/operation/result/fatal.rb
164
+ - lib/smart_core/operation/result/success.rb
118
165
  - lib/smart_core/operation/version.rb
119
166
  - smart_operation.gemspec
120
167
  homepage: https://github.com/smart-rb/smart_operation
@@ -132,7 +179,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
179
  requirements:
133
180
  - - ">="
134
181
  - !ruby/object:Gem::Version
135
- version: 2.4.9
182
+ version: 2.4.10
136
183
  required_rubygems_version: !ruby/object:Gem::Requirement
137
184
  requirements:
138
185
  - - ">="