smart_core 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.travis.yml +13 -9
- data/CHANGELOG.md +6 -0
- data/README.md +65 -2
- data/lib/smart_core/operation/attribute.rb +66 -0
- data/lib/smart_core/operation/attribute_definer.rb +160 -0
- data/lib/smart_core/operation/attribute_set.rb +92 -0
- data/lib/smart_core/operation/exceptions.rb +39 -0
- data/lib/smart_core/operation/failure.rb +29 -0
- data/lib/smart_core/operation/initialization_dsl.rb +124 -0
- data/lib/smart_core/operation/instance_builder.rb +161 -0
- data/lib/smart_core/operation/result.rb +44 -0
- data/lib/smart_core/operation/success.rb +71 -0
- data/lib/smart_core/operation.rb +65 -0
- data/lib/smart_core/validator/attribute_set.rb +2 -2
- data/lib/smart_core/validator/dsl.rb +2 -2
- data/lib/smart_core/validator/instance_builder.rb +114 -0
- data/lib/smart_core/validator.rb +8 -23
- data/lib/smart_core/version.rb +1 -1
- data/lib/smart_core.rb +1 -0
- data/smart_core.gemspec +5 -4
- metadata +28 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2ff8c25822c588b21c3d5785f04998fb1bb838e30b6046cc7e1706891133c6b
|
4
|
+
data.tar.gz: 307a1f6b397dba1339c9e6d4ea701343b349c22261b59e42ae35ccce735b7ff7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7755b70015cc2cb2c0cc76c9e3436cda0f7d76170f9109e3e20655ce6e29c16a530b1b522398355329eaa64e5cd139153ba3c93043372b6e734dbfe4994b47a8
|
7
|
+
data.tar.gz: e580d37f900e4e969464b094d4fc4d4795edcc6bbd90e482716dfcbc7147e327543dcf7e8c29ae5905a15ccd29a362b1b3873cc68972e742c3a5fc579696062b
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -2,15 +2,19 @@ language: ruby
|
|
2
2
|
sudo: false
|
3
3
|
before_install: gem install bundler
|
4
4
|
cache: bundler
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
- 2.
|
9
|
-
- 2.
|
10
|
-
-
|
11
|
-
-
|
12
|
-
|
13
|
-
-
|
5
|
+
matrix:
|
6
|
+
fast_finish: true
|
7
|
+
include:
|
8
|
+
- rvm: 2.3.8
|
9
|
+
- rvm: 2.4.5
|
10
|
+
- rvm: 2.5.3
|
11
|
+
- rvm: 2.6.0
|
12
|
+
- rvm: ruby-head
|
13
|
+
- rvm: jruby-head
|
14
|
+
allow_failures:
|
15
|
+
- rvm: ruby-head
|
16
|
+
- rvm: jruby-head
|
17
|
+
script: bundle exec rspec
|
14
18
|
notifications:
|
15
19
|
slack:
|
16
20
|
secure: CUM3xnSJvn/y6Z+epQrO5uSk1EUuP4S+ugcS+48nlWD6eEzhYZwcBAK9tvD6kYGOPzoWyKSbW6Is1kzSunNr6f8ICc8HtrVHzoHE8UCzwZ7FpjgD0JgMgC4+xLLBO6lV0Hc7dNh4KLAhy4Zvbr09DPjcG8UW9/QgUdn+wBf9LHMgA+2SpBPEzMwz6pMbWW/+kkoCz2KU877kEfuFFGfvoOEFWTxUUhuCYi5a1SmTjm9A7CFTEWNkX8yHJwdgVgONjvm9lnhTeV0DvMeEOhk8Kx/hzQ2OGIicXZXWyZFkzNzpQm5xE12Hs4rY7mGPbo3bsYRDH9Ys6yf4fpNf0oZ/1agzl/gnDzacA2wL2b+eq1uZblE/fdwrNp+GIH0R+Ec2rsVKM7kh71sA6Xp1pzFb2DnHj5O4QFaPMsLyIZqD0BkVt4pNfwi4ZUB56sWkYeRQGm8x2Beh02IyFfxI65lY5kZrW6GjXx5eFeOHcmzQzeADWLSBf4iw01G/A/QqwZzlZ3fm0fRJi8BKDh3Jj0IrGndE9Bl+E7uOClKKngTPxOVLOLo/vY5mfI8M94f99kr0J45XkoAdc0SQfi3hDa/tHaakI5GJsmByjgOQwV7OU/2wzJoXAg/RPYjsYcwnTgzm9bLXPhQzfM8rUS5vLTOWIW+N0QKmWml7eWVtiedcwXA=
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [0.2.0] - 2019-01-20
|
5
|
+
### Added
|
6
|
+
- **Service object** abstraction (`SmartCore::Operation`);
|
7
|
+
- **Validator**
|
8
|
+
- Support for `&block` attribute at object instantiation;
|
9
|
+
|
4
10
|
## [0.1.0] - 2019-01-05
|
5
11
|
### Added
|
6
12
|
- Validation object abstraction;
|
data/README.md
CHANGED
@@ -1,12 +1,75 @@
|
|
1
|
-
# SmartCore · [![Build Status](https://travis-ci.org/0exp/smart_core.svg?branch=master)](https://travis-ci.org/0exp/smart_core) [![Coverage Status](https://coveralls.io/repos/github/0exp/smart_core/badge.svg?branch=master)](https://coveralls.io/github/0exp/smart_core?branch=master)
|
1
|
+
# SmartCore · [![Gem Version](https://badge.fury.io/rb/smart_core.svg)](https://badge.fury.io/rb/smart_core) [![Build Status](https://travis-ci.org/0exp/smart_core.svg?branch=master)](https://travis-ci.org/0exp/smart_core) [![Coverage Status](https://coveralls.io/repos/github/0exp/smart_core/badge.svg?branch=master)](https://coveralls.io/github/0exp/smart_core?branch=master)
|
2
2
|
|
3
3
|
In active development.
|
4
4
|
|
5
|
+
---
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'smart_core'
|
11
|
+
```
|
12
|
+
|
13
|
+
```shell
|
14
|
+
bundle install
|
15
|
+
# --- or ---
|
16
|
+
gem install smart_core
|
17
|
+
```
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'smart_core'
|
21
|
+
```
|
22
|
+
|
23
|
+
---
|
24
|
+
|
5
25
|
#### Completed abstractions:
|
6
26
|
|
7
|
-
- **
|
27
|
+
- [**Operation Object**](#operation-object) (aka `Service Object`) (`SmartCore::Operation`)
|
28
|
+
- attribute definition DSL (`param`, `option`, `params`, `options`);
|
29
|
+
- yieldable result object abstraction (`Success`, `Failure`, `#success?`, `#failure?`);
|
30
|
+
- yieldable `#call` (and `.call`);
|
31
|
+
- inheritance works as expected `:)`;
|
32
|
+
- no dependencies;
|
33
|
+
|
34
|
+
- [**Validation Object**](#validation-object) (`SmartCore::Validator`)
|
8
35
|
- support for nested validations;
|
9
36
|
- inheritance works as expected `:)`;
|
10
37
|
- command-style DSL;
|
11
38
|
- thread-safe;
|
12
39
|
- no dependencies;
|
40
|
+
|
41
|
+
---
|
42
|
+
|
43
|
+
#### Operation Object
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
class Service < SmartCore::Operation
|
47
|
+
# soon...
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
#### Validation Object
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class Validator < SmartCore::Validator
|
55
|
+
# soon...
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
---
|
60
|
+
|
61
|
+
## Contributing
|
62
|
+
|
63
|
+
- Fork it ( https://github.com/0exp/smart_core/fork )
|
64
|
+
- Create your feature branch (`git checkout -b feature/my-new-feature`)
|
65
|
+
- Commit your changes (`git commit -am 'Add some feature'`)
|
66
|
+
- Push to the branch (`git push origin feature/my-new-feature`)
|
67
|
+
- Create new Pull Request
|
68
|
+
|
69
|
+
## License
|
70
|
+
|
71
|
+
Released under MIT License.
|
72
|
+
|
73
|
+
## Authors
|
74
|
+
|
75
|
+
[Rustam Ibragimov](https://github.com/0exp)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::Attribute
|
6
|
+
# @return [Symbol]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.2.0
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [Hash<Symbol,Any>]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.2.0
|
16
|
+
attr_reader :options
|
17
|
+
|
18
|
+
# @param name [String, Symbol]
|
19
|
+
# @param options [Hash<Symbol,Any>] Supported options:
|
20
|
+
# - :default (see #default_value) (proc or object)
|
21
|
+
# @return [void]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
# @since 0.2.0
|
25
|
+
def initialize(name, **options)
|
26
|
+
unless name.is_a?(Symbol) || name.is_a?(String)
|
27
|
+
raise(
|
28
|
+
SmartCore::Operation::IncorrectAttributeNameError,
|
29
|
+
'Attribute name should be a symbol or a string'
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
@name = name
|
34
|
+
@options = options # TODO: check for unsupported options (and fail if found)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Boolean]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
# @since 0.2.0
|
41
|
+
def has_default_value?
|
42
|
+
options.key?(:default)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Any]
|
46
|
+
#
|
47
|
+
# @raise [SmartCore::Operation::ArgumentError]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
# @since 0.2.0
|
51
|
+
def default_value
|
52
|
+
default_value = options.fetch(:default) do
|
53
|
+
raise(SmartCore::Operation::ArgumentError, 'Default value is not provided.')
|
54
|
+
end
|
55
|
+
|
56
|
+
default_value.is_a?(Proc) ? default_value.call : default_value
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [SmartCore::Operation::Attribute]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
# @since 0.2.0
|
63
|
+
def dup
|
64
|
+
self.class.new(name, **options)
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::AttributeDefiner
|
6
|
+
# @param operation_klass [Class<SmartCore::Operation>]
|
7
|
+
# @return [void]
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
# @since 0.2.0
|
11
|
+
def initialize(operation_klass)
|
12
|
+
@operation_klass = operation_klass
|
13
|
+
@definition_lock = Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param param_name [Symbol, String]
|
17
|
+
# @return [void]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 0.2.0
|
21
|
+
def define_param(param_name)
|
22
|
+
thread_safe do
|
23
|
+
parameter = build_attribute(param_name)
|
24
|
+
prevent_intersection_with_already_defined_option(parameter)
|
25
|
+
append_parameter(parameter)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param param_names [Array<String, Symbol>]
|
30
|
+
# @return [void]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
# @since 0.2.0
|
34
|
+
def define_params(*param_names)
|
35
|
+
thread_safe do
|
36
|
+
parameters = param_names.map do |param_name|
|
37
|
+
build_attribute(param_name).tap do |parameter|
|
38
|
+
prevent_intersection_with_already_defined_option(parameter)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
parameters.each { |parameter| append_parameter(parameter) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param option_name [Symbol, String]
|
47
|
+
# @return [void]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
# @since 0.2.0
|
51
|
+
def define_option(option_name, **options)
|
52
|
+
thread_safe do
|
53
|
+
option = build_attribute(option_name, **options)
|
54
|
+
prevent_intersection_with_already_defined_param(option)
|
55
|
+
append_option(option)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param option_names [Array<String, Symbol>]
|
60
|
+
# @return [void]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
# @since 0.2.0
|
64
|
+
def define_options(*option_names)
|
65
|
+
thread_safe do
|
66
|
+
options = option_names.map do |option_name|
|
67
|
+
build_attribute(option_name).tap do |option|
|
68
|
+
prevent_intersection_with_already_defined_param(option)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
options.each { |option| append_option(option) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# @return [Class<SmartCore::Operation>]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
# @since 0.2.0
|
82
|
+
attr_reader :operation_klass
|
83
|
+
|
84
|
+
# @return [Mutex]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
# @since 0.2.0
|
88
|
+
attr_reader :definition_lock
|
89
|
+
|
90
|
+
# @param attribute_name [Symbol, String]
|
91
|
+
# @param attribute_options [Hash<Symbol,Any>]
|
92
|
+
# @return [SmartCore::Operation::Attribute]
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
# @since 0.2.0
|
96
|
+
def build_attribute(attribute_name, **attribute_options)
|
97
|
+
SmartCore::Operation::Attribute.new(attribute_name, **attribute_options)
|
98
|
+
end
|
99
|
+
|
100
|
+
# @param parameter [SmartCore::Operation::Attribute]
|
101
|
+
# @return [void]
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
# @since 0.2.0
|
105
|
+
def append_parameter(parameter)
|
106
|
+
operation_klass.__params__ << parameter
|
107
|
+
operation_klass.send(:attr_reader, parameter.name)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @param option [SmartCore::Operation::Attribute]
|
111
|
+
# @return [void]
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
# @since 0.2.0
|
115
|
+
def append_option(option)
|
116
|
+
operation_klass.__options__ << option
|
117
|
+
operation_klass.send(:attr_reader, option.name)
|
118
|
+
end
|
119
|
+
|
120
|
+
# @param parameter [SmartCore::Operation::Attribute]
|
121
|
+
# @return [void]
|
122
|
+
#
|
123
|
+
# @raise [SmartCore::Operation::OptionOverlapError]
|
124
|
+
#
|
125
|
+
# @api private
|
126
|
+
# @since 0.2.0
|
127
|
+
def prevent_intersection_with_already_defined_option(parameter)
|
128
|
+
if operation_klass.__options__.conflicts_with?(parameter)
|
129
|
+
raise(
|
130
|
+
SmartCore::Operation::OptionOverlapError,
|
131
|
+
"You have already defined option with :#{parameter.name} name"
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @param option [SmartCore::Operation::Attribute]
|
137
|
+
# @return [void]
|
138
|
+
#
|
139
|
+
# @raise [SmartCore::Operation::ParamOverlapError]
|
140
|
+
#
|
141
|
+
# @api private
|
142
|
+
# @since 0.2.0
|
143
|
+
def prevent_intersection_with_already_defined_param(option)
|
144
|
+
if operation_klass.__params__.conflicts_with?(option)
|
145
|
+
raise(
|
146
|
+
SmartCore::Operation::ParamOverlapError,
|
147
|
+
"You have already defined param with :#{option.name} name"
|
148
|
+
)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @param block [Proc]
|
153
|
+
# @return [Any]
|
154
|
+
#
|
155
|
+
# @api private
|
156
|
+
# @since 0.2.0
|
157
|
+
def thread_safe(&block)
|
158
|
+
definition_lock.synchronize(&block)
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::AttributeSet
|
6
|
+
# @since 0.2.0
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
# @return [Hash<Symbol, SmartCore::Operation::Attribute>]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.2.0
|
13
|
+
attr_reader :attributes
|
14
|
+
|
15
|
+
# @return [void]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.2.0
|
19
|
+
def initialize
|
20
|
+
@attributes = {}
|
21
|
+
@access_lock = Mutex.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param attribute [SmartCore::Operation::Attribute]
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
# @since 0.2.0
|
29
|
+
def add_attribute(attribute)
|
30
|
+
thread_safe { attributes[attribute.name] = attribute }
|
31
|
+
end
|
32
|
+
alias_method :<<, :add_attribute
|
33
|
+
|
34
|
+
# @param attribute_set [SmartCore::Operation::AttributeSet]
|
35
|
+
# @return [void]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @sinec 0.2.0
|
39
|
+
def concat(attribute_set)
|
40
|
+
thread_safe { attributes.merge!(attribute_set.dup.attributes) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param attribute [SmartCore::Operation::Attribute]
|
44
|
+
# @return [Boolean]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
# @since 0.2.0
|
48
|
+
def conflicts_with?(attribute)
|
49
|
+
thread_safe { attributes.key?(attribute.name) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [SmartCore::Operation::AttributeSet]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
# @since 0.2.0
|
56
|
+
def dup
|
57
|
+
thread_safe do
|
58
|
+
self.class.new.tap do |duplicate|
|
59
|
+
attributes.each_value do |attribute|
|
60
|
+
duplicate.add_attribute(attribute.dup)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Integer]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
# @since 0.2.0
|
70
|
+
def size
|
71
|
+
thread_safe { attributes.size }
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Enumerable]
|
75
|
+
#
|
76
|
+
# @api private
|
77
|
+
# @since 0.2.0
|
78
|
+
def each(&block)
|
79
|
+
thread_safe { block_given? ? attributes.each_value(&block) : attributes.each_value }
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# @param block [Proc]
|
85
|
+
# @return [Any]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
# @since 0.2.0
|
89
|
+
def thread_safe(&block)
|
90
|
+
@access_lock.synchronize(&block)
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SmartCore::Operation
|
4
|
+
# @api public
|
5
|
+
# @since 0.2.0
|
6
|
+
Error = Class.new(StandardError)
|
7
|
+
|
8
|
+
# @api public
|
9
|
+
# @since 0.2.0
|
10
|
+
ArgumentError = Class.new(::ArgumentError)
|
11
|
+
|
12
|
+
# @api public
|
13
|
+
# @since 0.2.0
|
14
|
+
ParameterError = Class.new(ArgumentError)
|
15
|
+
|
16
|
+
# @api public
|
17
|
+
# @since 0.2.0
|
18
|
+
ParamOverlapError = Class.new(ParameterError)
|
19
|
+
|
20
|
+
# @api public
|
21
|
+
# @since 0.2.0
|
22
|
+
OptionError = Class.new(ArgumentError)
|
23
|
+
|
24
|
+
# @api public
|
25
|
+
# @since 0.2.0
|
26
|
+
OptionOverlapError = Class.new(OptionError)
|
27
|
+
|
28
|
+
# @api public
|
29
|
+
# @since 0.2.0
|
30
|
+
IncorrectAttributeNameError = Class.new(Error)
|
31
|
+
|
32
|
+
# @api public
|
33
|
+
# @since 0.2.0
|
34
|
+
ResultMethodIntersectionError = Class.new(Error)
|
35
|
+
|
36
|
+
# @api public
|
37
|
+
# @since 0.2.0
|
38
|
+
IncompatibleResultObjectKeyError = Class.new(Error)
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::Failure < SmartCore::Operation::Result
|
6
|
+
# @return [Array<Symbol|Any>]
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
# @since 0.2.0
|
10
|
+
alias_method :errors, :__result_attributes__
|
11
|
+
|
12
|
+
# @param errors [Array<Symbol|Any>]
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
# @api pubic
|
16
|
+
# @since 0.2.0
|
17
|
+
def initialize(*errors)
|
18
|
+
super(*errors)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @yield [nil]
|
22
|
+
# @return [Boolean]
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
# @since 0.2.0
|
26
|
+
def failure?
|
27
|
+
true.tap { yield(self) if block_given? }
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SmartCore::Operation
|
4
|
+
# @api private
|
5
|
+
# @since 0.2.0
|
6
|
+
module InitializationDSL
|
7
|
+
class << self
|
8
|
+
# @param base_klass [Class]
|
9
|
+
# @return [void]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.2.0
|
13
|
+
def included(base_klass) # rubocop:disable Metrics/AbcSize
|
14
|
+
base_klass.extend(DSLMethods)
|
15
|
+
base_klass.singleton_class.prepend(InitializationMethods)
|
16
|
+
|
17
|
+
base_klass.instance_variable_set(:@__attr_definer__, AttributeDefiner.new(base_klass))
|
18
|
+
base_klass.instance_variable_set(:@__params__, AttributeSet.new)
|
19
|
+
base_klass.instance_variable_set(:@__options__, AttributeSet.new)
|
20
|
+
|
21
|
+
base_klass.singleton_class.prepend(Module.new do
|
22
|
+
# @param child_klass [Class]
|
23
|
+
# @return [void]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
# @since 0.2.0
|
27
|
+
def inherited(child_klass)
|
28
|
+
child_klass.singleton_class.prepend(InitializationMethods)
|
29
|
+
|
30
|
+
child_klass.instance_variable_set(:@__attr_definer__, AttributeDefiner.new(child_klass))
|
31
|
+
child_klass.instance_variable_set(:@__params__, AttributeSet.new)
|
32
|
+
child_klass.instance_variable_set(:@__options__, AttributeSet.new)
|
33
|
+
|
34
|
+
child_klass.__params__.concat(__params__)
|
35
|
+
child_klass.__options__.concat(__options__)
|
36
|
+
|
37
|
+
super(child_klass)
|
38
|
+
end
|
39
|
+
end)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
# @since 0.2.0
|
45
|
+
module InitializationMethods
|
46
|
+
# @param parameters [Any]
|
47
|
+
# @param options [Hash<Symbol,Any>]
|
48
|
+
# @return [Any]
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
# @since 0.2.0
|
52
|
+
def new(*parameters, **options)
|
53
|
+
allocate.tap do |object|
|
54
|
+
InstanceBuilder.call(object, self, parameters, options)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @api private
|
60
|
+
# @since 0.2.0
|
61
|
+
module DSLMethods
|
62
|
+
# @param param_name [String, Symbol]
|
63
|
+
# @return [void]
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
# @since 0.2.0
|
67
|
+
def param(param_name)
|
68
|
+
__attr_definer__.define_param(param_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @param param_names [Array<String, Symbol>]
|
72
|
+
# @return [void]
|
73
|
+
#
|
74
|
+
# @api public
|
75
|
+
# @since 0.2.0
|
76
|
+
def params(*param_names)
|
77
|
+
__attr_definer__.define_params(*param_names)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @param option_name [String, Symbol]
|
81
|
+
# @param options [Hash<Symbol,Any>]
|
82
|
+
# @return [void]
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
# @since 0.2.0
|
86
|
+
def option(option_name, **options)
|
87
|
+
__attr_definer__.define_option(option_name, **options)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param option_names [Array<String, Symbol>]
|
91
|
+
# @return [void]
|
92
|
+
#
|
93
|
+
# @api public
|
94
|
+
# @since 0.2.0
|
95
|
+
def options(*option_names)
|
96
|
+
__attr_definer__.define_options(*option_names)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [SmartCore::Operation::AttributeSet]
|
100
|
+
#
|
101
|
+
# @api private
|
102
|
+
# @since 0.2.0
|
103
|
+
def __params__
|
104
|
+
@__params__
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [SmartCore::Operation::AttributeSet]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
# @since 0.2.0
|
111
|
+
def __options__
|
112
|
+
@__options__
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [SmartCore::Operation::AttributeDefiner]
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
# @since 0.2.0
|
119
|
+
def __attr_definer__
|
120
|
+
@__attr_definer__
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::InstanceBuilder
|
6
|
+
class << self
|
7
|
+
# @param operation_object [SmartCore::Operation]
|
8
|
+
# @param operation_klass [Class<SmartCore::Operation>]
|
9
|
+
# @param parameters [Array<Any>]
|
10
|
+
# @param options [Hash<Symbol,Any>]
|
11
|
+
# @return [SmartCore::Operation]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since 0.2.0
|
15
|
+
def call(operation_object, operation_klass, parameters, options)
|
16
|
+
new(operation_object, operation_klass, parameters, options).call
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param operation_object [SmartCore::Operation]
|
21
|
+
# @param operation_klass [Class<SmartCore::Operation>]
|
22
|
+
# @param parameters [Array<Any>]
|
23
|
+
# @param options [Hash<Symbol,Any>]
|
24
|
+
# @return [void]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
# @since 0.2.0
|
28
|
+
def initialize(operation_object, operation_klass, parameters, options)
|
29
|
+
@operation_object = operation_object
|
30
|
+
@operation_klass = operation_klass
|
31
|
+
@parameters = parameters
|
32
|
+
@options = options
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [SmartCore::Operation]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since 0.2.0
|
39
|
+
def call
|
40
|
+
operation_object.tap do
|
41
|
+
prevent_parameters_incomparability
|
42
|
+
initialize_parameters
|
43
|
+
initialize_options
|
44
|
+
call_original_methods
|
45
|
+
make_operation_caller_yieldable
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# @return [SmartCore::Operation]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
# @since 0.2.0
|
55
|
+
attr_reader :operation_object
|
56
|
+
|
57
|
+
# @return [Class<SmartCore::Operation>]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
# @since 0.2.0
|
61
|
+
attr_reader :operation_klass
|
62
|
+
|
63
|
+
# @return [Array<Any>]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
# @since 0.2.0
|
67
|
+
attr_reader :parameters
|
68
|
+
|
69
|
+
# @return [Hash<Symbol,Any>]
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
# @since 0.2.0
|
73
|
+
attr_reader :options
|
74
|
+
|
75
|
+
# An array of the required option attribute names (parameters without default values)
|
76
|
+
#
|
77
|
+
# @return [Array<Symbol>]
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
# @since 0.2.0
|
81
|
+
def required_options
|
82
|
+
operation_klass.__options__.each.reject(&:has_default_value?).map(&:name)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Integer]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
# @since 0.2.0
|
89
|
+
def required_attributes_count
|
90
|
+
operation_klass.__params__.size
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [void]
|
94
|
+
#
|
95
|
+
# @raise [SmartCore::Operation::AttributeError]
|
96
|
+
# @raise [SmartCore::Operation::ParameterError]
|
97
|
+
# @raise [SmartCore::Operation::OptionError]
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
# @since 0.2.0
|
101
|
+
def prevent_parameters_incomparability
|
102
|
+
raise(
|
103
|
+
SmartCore::Operation::ParameterError,
|
104
|
+
"Wrong number of parameters " \
|
105
|
+
"(given #{parameters.size}, expected #{required_attributes_count})"
|
106
|
+
) unless parameters.size == required_attributes_count
|
107
|
+
|
108
|
+
missing_options = required_options.reject { |option| options.key?(option) }
|
109
|
+
|
110
|
+
raise(
|
111
|
+
SmartCore::Operation::OptionError,
|
112
|
+
"Missing options: :#{missing_options.join(', :')}"
|
113
|
+
) unless missing_options.empty?
|
114
|
+
end
|
115
|
+
|
116
|
+
# @return [void]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
# @since 0.2.0
|
120
|
+
def initialize_parameters
|
121
|
+
parameter_names = operation_klass.__params__.map(&:name)
|
122
|
+
parameter_pairs = Hash[parameter_names.zip(parameters)]
|
123
|
+
|
124
|
+
parameter_pairs.each_pair do |parameter_name, parameter_value|
|
125
|
+
operation_object.instance_variable_set("@#{parameter_name}", parameter_value)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# @return [void]
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
# @since 0.2.0
|
133
|
+
def initialize_options
|
134
|
+
operation_klass.__options__.each do |option|
|
135
|
+
option_name = option.name
|
136
|
+
option_value = options.fetch(option_name) { option.default_value }
|
137
|
+
|
138
|
+
operation_object.instance_variable_set("@#{option_name}", option_value)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# @return [void]
|
143
|
+
#
|
144
|
+
# @api private
|
145
|
+
# @since 0.2.0
|
146
|
+
def call_original_methods
|
147
|
+
operation_object.send(:initialize, *parameters, **options)
|
148
|
+
end
|
149
|
+
|
150
|
+
# @return [void]
|
151
|
+
#
|
152
|
+
# @api private
|
153
|
+
# @since 0.2.0
|
154
|
+
def make_operation_caller_yieldable
|
155
|
+
operation_object.singleton_class.prepend(Module.new do
|
156
|
+
def call
|
157
|
+
super.tap { |result| yield(result) if block_given? }
|
158
|
+
end
|
159
|
+
end)
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::Result
|
6
|
+
# @return [Array<Any>]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.2.0
|
10
|
+
attr_reader :__result_attributes__
|
11
|
+
|
12
|
+
# @return [Hash<Symbol,Any>]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.2.0
|
16
|
+
attr_reader :__result_options__
|
17
|
+
|
18
|
+
# @param result_attributes [Array<Any>]
|
19
|
+
# @param result_options [Hash<Symbol,Any>]
|
20
|
+
# @return [void]
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
# @since 0.2.0
|
24
|
+
def initialize(*result_attributes, **result_options)
|
25
|
+
@__result_attributes__ = result_attributes
|
26
|
+
@__result_options__ = result_options
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Boolean]
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
# @since 0.2.0
|
33
|
+
def success?
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Boolean]
|
38
|
+
#
|
39
|
+
# @api public
|
40
|
+
# @since 0.2.0
|
41
|
+
def failure?
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation::Success < SmartCore::Operation::Result
|
6
|
+
# @param result_options [Hash<Symbol,Any>]
|
7
|
+
# @return [void]
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
# @since 0.2.0
|
11
|
+
def initialize(**result_options)
|
12
|
+
__prevent_method_overlapping__(result_options)
|
13
|
+
super(**result_options) # NOTE: initialize result object
|
14
|
+
__define_virtual_result_data_accessors__(result_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @yield [nil]
|
18
|
+
# @return [Boolean]
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
# @since 0.2.0
|
22
|
+
def success?
|
23
|
+
true.tap { yield(self) if block_given? }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# @param result_options [Hash<Symbol,Any>]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @raise [SmartCore::Operation::IncompatibleResultKeyError]
|
32
|
+
# @raise [SmartCore::Operation::ResultMethodIntersectionError]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
# @since 0.2.0
|
36
|
+
def __prevent_method_overlapping__(result_options)
|
37
|
+
overlappings = result_options.each_key.each_with_object([]) do |key, overlap|
|
38
|
+
overlap << key if self.class.__core_methods__.include?(key)
|
39
|
+
end
|
40
|
+
|
41
|
+
raise(
|
42
|
+
SmartCore::Operation::ResultMethodIntersectionError,
|
43
|
+
"Result keys can not overlap core methods " \
|
44
|
+
"(overlapping keys: #{overlappings.join(', ')})."
|
45
|
+
) if overlappings.any?
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param result_options [Hash<Symbol,Any>]
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
# @since 0.2.0
|
53
|
+
def __define_virtual_result_data_accessors__(result_options)
|
54
|
+
result_options.each_key do |result_attribute_name|
|
55
|
+
define_singleton_method(result_attribute_name) do
|
56
|
+
__result_options__[result_attribute_name]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
core_methods = (
|
62
|
+
instance_methods(false) | private_instance_methods(false) |
|
63
|
+
superclass.instance_methods(false) | superclass.private_instance_methods(false)
|
64
|
+
).freeze
|
65
|
+
|
66
|
+
# @return [Array<Symbol>]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
# @since 0.2.0
|
70
|
+
define_singleton_method(:__core_methods__) { core_methods }
|
71
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Operation
|
6
|
+
require_relative 'operation/exceptions'
|
7
|
+
require_relative 'operation/attribute'
|
8
|
+
require_relative 'operation/attribute_set'
|
9
|
+
require_relative 'operation/result'
|
10
|
+
require_relative 'operation/success'
|
11
|
+
require_relative 'operation/failure'
|
12
|
+
require_relative 'operation/instance_builder'
|
13
|
+
require_relative 'operation/attribute_definer'
|
14
|
+
require_relative 'operation/initialization_dsl'
|
15
|
+
|
16
|
+
# @since 0.2.0
|
17
|
+
include InitializationDSL
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# @param arguments [Any]
|
21
|
+
# @param options [Hash<Symbol,Any>]
|
22
|
+
# @param block [Proc]
|
23
|
+
# @return [SmartCore::Operation::Success, SmartCore::Operation::Failure]
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
# @since 0.2.0
|
27
|
+
def call(*arguments, **options, &block)
|
28
|
+
new(*arguments, **options).call(&block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [void]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
# @since 0.2.0
|
36
|
+
def initialize(*, **); end
|
37
|
+
|
38
|
+
# @return [SmartCore::Operation::Success, SmartCore::Operation::Failure]
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
# @since 0.2.0
|
42
|
+
def call
|
43
|
+
Success()
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# @param result_data [Hash<Symbol,Any>]
|
49
|
+
# @return [SmartCore::Operation::Success]
|
50
|
+
#
|
51
|
+
# @api public
|
52
|
+
# @since 0.2.0
|
53
|
+
def Success(**result_data) # rubocop:disable Naming/MethodName
|
54
|
+
SmartCore::Operation::Success.new(**result_data)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param errors [Array<Symbol|Any>]
|
58
|
+
# @return [SmartCore::Operation::Failure]
|
59
|
+
#
|
60
|
+
# @api public
|
61
|
+
# @since 0.2.0
|
62
|
+
def Failure(*errors) # rubocop:disable Naming/MethodName
|
63
|
+
SmartCore::Operation::Failure.new(*errors)
|
64
|
+
end
|
65
|
+
end
|
@@ -6,7 +6,7 @@ class SmartCore::Validator::AttributeSet
|
|
6
6
|
# @since 0.1.0
|
7
7
|
include Enumerable
|
8
8
|
|
9
|
-
# @return [Hash<Symbol,
|
9
|
+
# @return [Hash<Symbol,SmartCore::Validator::Attribute>]
|
10
10
|
#
|
11
11
|
# @api private
|
12
12
|
# @since 0.1.0
|
@@ -21,7 +21,7 @@ class SmartCore::Validator::AttributeSet
|
|
21
21
|
@access_lock = Mutex.new
|
22
22
|
end
|
23
23
|
|
24
|
-
# @param attribute [
|
24
|
+
# @param attribute [SmartCore::Validator::Attribute]
|
25
25
|
# @return [void]
|
26
26
|
#
|
27
27
|
# @api private
|
@@ -31,7 +31,7 @@ class SmartCore::Validator
|
|
31
31
|
# @param attribute_name [String, Symbol]
|
32
32
|
# @return [void]
|
33
33
|
#
|
34
|
-
# @api
|
34
|
+
# @api public
|
35
35
|
# @since 0.1.0
|
36
36
|
def attribute(attribute_name, default: nil)
|
37
37
|
attribute = SmartCore::Validator::Attribute.new(attribute_name, default)
|
@@ -86,7 +86,7 @@ class SmartCore::Validator
|
|
86
86
|
#
|
87
87
|
# @see SmartCore::Validator::Commands::ValidateWith
|
88
88
|
#
|
89
|
-
# @api
|
89
|
+
# @api public
|
90
90
|
# @since 0.1.0
|
91
91
|
def validate_with(validating_klass, &nested_validations)
|
92
92
|
commands << Commands::ValidateWith.new(validating_klass, nested_validations)
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.2.0
|
5
|
+
class SmartCore::Validator
|
6
|
+
class InstanceBuilder
|
7
|
+
class << self
|
8
|
+
# @param validator_object [SmartCore::Validator]
|
9
|
+
# @param validator_klass [Class<SmartCore::Validator>]
|
10
|
+
# @param arguments [Array<Any>]
|
11
|
+
# @param options [Hash<Symbol,Any>]
|
12
|
+
# @param block [Proc]
|
13
|
+
# @return [SmartCore::Validator]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.2.0
|
17
|
+
def call(validator_object, validator_klass, arguments, options, block)
|
18
|
+
new(validator_object, validator_klass, arguments, options, block).call
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param validator_object [SmartCore::Validator]
|
23
|
+
# @param validator_klass [Class<SmartCore::Validator>]
|
24
|
+
# @param arguments [Array<Any>]
|
25
|
+
# @param options [Hash<Symbol,Any>]
|
26
|
+
# @param block [Proc]
|
27
|
+
# @return [void]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
# @since 0.2.0
|
31
|
+
def initialize(validator_object, validator_klass, arguments, options, block)
|
32
|
+
@validator_object = validator_object
|
33
|
+
@validator_klass = validator_klass
|
34
|
+
@arguments = arguments
|
35
|
+
@options = options
|
36
|
+
@block = block
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [SmartCore::Validator]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
# @since 0.2.0
|
43
|
+
def call
|
44
|
+
validator_object.tap do
|
45
|
+
initialize_core_attributes
|
46
|
+
initialize_custom_attributes
|
47
|
+
invoke_original_methods
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# @return [SmartCore::Validator]
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
# @since 0.2.0
|
57
|
+
attr_reader :validator_object
|
58
|
+
|
59
|
+
# @return [Class<SmartCore::Validator>]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
# @since 0.2.0
|
63
|
+
attr_reader :validator_klass
|
64
|
+
|
65
|
+
# @return [Array<Any>]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
# @since 0.2.0
|
69
|
+
attr_reader :arguments
|
70
|
+
|
71
|
+
# @return [Hash<Symbol,Any>]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
# @since 0.2.0
|
75
|
+
attr_reader :options
|
76
|
+
|
77
|
+
# @return [Proc]
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
# @since 0.2.0
|
81
|
+
attr_reader :block
|
82
|
+
|
83
|
+
# @return [void]
|
84
|
+
#
|
85
|
+
# @api private
|
86
|
+
# @since 0.2.0
|
87
|
+
def initialize_core_attributes
|
88
|
+
validator_object.instance_variable_set(:@__validation_errors__, ErrorSet.new)
|
89
|
+
validator_object.instance_variable_set(:@__invokation_lock__, Mutex.new)
|
90
|
+
validator_object.instance_variable_set(:@__access_lock__, Mutex.new)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [void]
|
94
|
+
#
|
95
|
+
# @api private
|
96
|
+
# @since 0.2.0
|
97
|
+
def initialize_custom_attributes
|
98
|
+
validator_klass.attributes.each do |attribute|
|
99
|
+
attribute_name = attribute.name
|
100
|
+
attribute_value = options.fetch(attribute_name) { attribute.default_value }
|
101
|
+
|
102
|
+
validator_object.instance_variable_set("@#{attribute_name}", attribute_value)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [void]
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
# @since 0.2.0
|
110
|
+
def invoke_original_methods
|
111
|
+
validator_object.send(:initialize, *arguments, **options, &block)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/lib/smart_core/validator.rb
CHANGED
@@ -11,37 +11,22 @@ class SmartCore::Validator
|
|
11
11
|
require_relative 'validator/invoker'
|
12
12
|
require_relative 'validator/commands'
|
13
13
|
require_relative 'validator/dsl'
|
14
|
+
require_relative 'validator/instance_builder'
|
14
15
|
|
15
16
|
# @since 0.1.0
|
16
17
|
extend DSL
|
17
18
|
|
18
19
|
class << self
|
19
|
-
# @param
|
20
|
-
# @param options [Hash<Symbol,
|
20
|
+
# @param arguments [Any]
|
21
|
+
# @param options [Hash<Symbol,Object>]
|
22
|
+
# @param block [Proc]
|
21
23
|
# @return [void]
|
22
24
|
#
|
23
25
|
# @api public
|
24
26
|
# @since 0.1.0
|
25
|
-
def new(*arguments, **options)
|
27
|
+
def new(*arguments, **options, &block)
|
26
28
|
allocate.tap do |object|
|
27
|
-
|
28
|
-
object.instance_variable_set(:@__invokation_lock__, Mutex.new)
|
29
|
-
object.instance_variable_set(:@__access_lock__, Mutex.new)
|
30
|
-
|
31
|
-
attributes.each do |attribute|
|
32
|
-
attribute_name = attribute.name
|
33
|
-
|
34
|
-
attribute_value =
|
35
|
-
if options.key?(attribute_name)
|
36
|
-
options[attribute_name]
|
37
|
-
else
|
38
|
-
attribute.default_value
|
39
|
-
end
|
40
|
-
|
41
|
-
object.instance_variable_set("@#{attribute_name}", attribute_value)
|
42
|
-
end
|
43
|
-
|
44
|
-
object.send(:initialize, *arguments, **options)
|
29
|
+
InstanceBuilder.call(object, self, arguments, options, block)
|
45
30
|
end
|
46
31
|
end
|
47
32
|
end
|
@@ -56,7 +41,7 @@ class SmartCore::Validator
|
|
56
41
|
#
|
57
42
|
# @api public
|
58
43
|
# @since 0.1.0
|
59
|
-
def initialize(*,
|
44
|
+
def initialize(*, **, &block); end
|
60
45
|
|
61
46
|
# @return [Boolean]
|
62
47
|
#
|
@@ -91,7 +76,7 @@ class SmartCore::Validator
|
|
91
76
|
end
|
92
77
|
end
|
93
78
|
|
94
|
-
# @return [Hash<Symbol,
|
79
|
+
# @return [Hash<Symbol,Object>]
|
95
80
|
#
|
96
81
|
# @api private
|
97
82
|
# @since 0.1.0
|
data/lib/smart_core/version.rb
CHANGED
data/lib/smart_core.rb
CHANGED
data/smart_core.gemspec
CHANGED
@@ -26,9 +26,10 @@ Gem::Specification.new do |spec|
|
|
26
26
|
|
27
27
|
spec.add_development_dependency 'coveralls', '~> 0.8.22'
|
28
28
|
spec.add_development_dependency 'simplecov', '~> 0.16.1'
|
29
|
-
spec.add_development_dependency 'armitage-rubocop', '~> 0.
|
29
|
+
spec.add_development_dependency 'armitage-rubocop', '~> 0.17.0'
|
30
30
|
spec.add_development_dependency 'rspec', '~> 3.8.0'
|
31
|
-
|
32
|
-
spec.add_development_dependency '
|
33
|
-
spec.add_development_dependency '
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler'
|
33
|
+
spec.add_development_dependency 'rake'
|
34
|
+
spec.add_development_dependency 'pry'
|
34
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rustam Ibragimov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coveralls
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.17.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: 0.17.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,44 +70,44 @@ dependencies:
|
|
70
70
|
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: pry
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0
|
103
|
+
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0
|
110
|
+
version: '0'
|
111
111
|
description: "(in active development) A set of common abstractions"
|
112
112
|
email:
|
113
113
|
- iamdaiver@icloud.com
|
@@ -128,6 +128,16 @@ files:
|
|
128
128
|
- bin/console
|
129
129
|
- bin/setup
|
130
130
|
- lib/smart_core.rb
|
131
|
+
- lib/smart_core/operation.rb
|
132
|
+
- lib/smart_core/operation/attribute.rb
|
133
|
+
- lib/smart_core/operation/attribute_definer.rb
|
134
|
+
- lib/smart_core/operation/attribute_set.rb
|
135
|
+
- lib/smart_core/operation/exceptions.rb
|
136
|
+
- lib/smart_core/operation/failure.rb
|
137
|
+
- lib/smart_core/operation/initialization_dsl.rb
|
138
|
+
- lib/smart_core/operation/instance_builder.rb
|
139
|
+
- lib/smart_core/operation/result.rb
|
140
|
+
- lib/smart_core/operation/success.rb
|
131
141
|
- lib/smart_core/validator.rb
|
132
142
|
- lib/smart_core/validator/attribute.rb
|
133
143
|
- lib/smart_core/validator/attribute_set.rb
|
@@ -141,6 +151,7 @@ files:
|
|
141
151
|
- lib/smart_core/validator/dsl.rb
|
142
152
|
- lib/smart_core/validator/error_set.rb
|
143
153
|
- lib/smart_core/validator/exceptions.rb
|
154
|
+
- lib/smart_core/validator/instance_builder.rb
|
144
155
|
- lib/smart_core/validator/invoker.rb
|
145
156
|
- lib/smart_core/version.rb
|
146
157
|
- smart_core.gemspec
|
@@ -163,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
163
174
|
- !ruby/object:Gem::Version
|
164
175
|
version: '0'
|
165
176
|
requirements: []
|
166
|
-
rubygems_version: 3.0.
|
177
|
+
rubygems_version: 3.0.2
|
167
178
|
signing_key:
|
168
179
|
specification_version: 4
|
169
180
|
summary: "(in active development) A set of common abstractions"
|