smart_initializer 0.0.0 → 0.1.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +5 -5
- data/README.md +18 -0
- data/lib/smart_core/initializer/attribute/definer.rb +2 -2
- data/lib/smart_core/initializer/attribute/factory.rb +8 -4
- data/lib/smart_core/initializer/attribute/finalizer/abstract.rb +37 -0
- data/lib/smart_core/initializer/attribute/finalizer/anonymous_block.rb +27 -25
- data/lib/smart_core/initializer/attribute/finalizer/instance_method.rb +27 -25
- data/lib/smart_core/initializer/attribute/finalizer.rb +1 -6
- data/lib/smart_core/initializer/attribute/list.rb +28 -0
- data/lib/smart_core/initializer/attribute/parameters.rb +30 -6
- data/lib/smart_core/initializer/attribute.rb +40 -13
- data/lib/smart_core/initializer/constructor.rb +158 -0
- data/lib/smart_core/initializer/dsl/inheritance.rb +18 -0
- data/lib/smart_core/initializer/dsl.rb +36 -2
- data/lib/smart_core/initializer/errors.rb +16 -0
- data/lib/smart_core/initializer/type_aliasing/alias_list.rb +102 -0
- data/lib/smart_core/initializer/type_aliasing.rb +50 -0
- data/lib/smart_core/initializer/version.rb +1 -1
- data/lib/smart_core/initializer.rb +22 -1
- data/smart_initializer.gemspec +2 -2
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd7d1a7f5aa327457a601a1b1a0110d8178e6bd83b557a53365e0cf96d336080
|
4
|
+
data.tar.gz: 1487df01e94537cf79292f293f525f9ecde081edb0438e61d9674c7b2ac2cf6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7395f7428558b2a891090376c455c0a2cd4a8d730e615d69a1d33aeac2703bae64642e9a0024072c2efbdc4dfdff9bbe8ae26481ea6706e8355825fb30bf8559
|
7
|
+
data.tar.gz: 662340beb7c3d1980d6870b9a9d555e8e86191c08fda50c9925ed99ba065b99e2bb6d6de9b906521298fa1add43a955ee5cd9f2bd9bdad67f04e58a7ee72be5f
|
data/Gemfile.lock
CHANGED
@@ -2,8 +2,8 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
smart_initializer (0.1.0)
|
5
|
-
smart_engine (~> 0.
|
6
|
-
smart_types (~> 0.1.0.
|
5
|
+
smart_engine (~> 0.5)
|
6
|
+
smart_types (~> 0.1.0.alpha4)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
@@ -60,9 +60,9 @@ GEM
|
|
60
60
|
json (>= 1.8, < 3)
|
61
61
|
simplecov-html (~> 0.10.0)
|
62
62
|
simplecov-html (0.10.2)
|
63
|
-
smart_engine (0.
|
64
|
-
smart_types (0.1.0.
|
65
|
-
smart_engine (~> 0.
|
63
|
+
smart_engine (0.5.0)
|
64
|
+
smart_types (0.1.0.alpha4)
|
65
|
+
smart_engine (~> 0.5)
|
66
66
|
unicode-display_width (1.6.1)
|
67
67
|
|
68
68
|
PLATFORMS
|
data/README.md
CHANGED
@@ -36,6 +36,24 @@ end
|
|
36
36
|
User.new(1, 'John', 'test123', role: :admin, metadata: {}, enabled: false)
|
37
37
|
```
|
38
38
|
|
39
|
+
**Limitations**:
|
40
|
+
|
41
|
+
- `param` has no :default option (at all);
|
42
|
+
- last hash argument will be treated as `kwarg`s;
|
43
|
+
|
44
|
+
**Type aliasing**:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
SmartCore::Initializer.type_alias(:hash, SmartCore::Types::Value::Hash)
|
48
|
+
|
49
|
+
class User
|
50
|
+
include SmartCore::Initializer
|
51
|
+
|
52
|
+
param :data, :hash
|
53
|
+
option :metadata, :hash
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
39
57
|
---
|
40
58
|
|
41
59
|
## Contributing
|
@@ -41,7 +41,7 @@ class SmartCore::Initializer::Attribute::Definer
|
|
41
41
|
names.map do |name|
|
42
42
|
build_attribute(
|
43
43
|
name,
|
44
|
-
SmartCore::Types::Any,
|
44
|
+
SmartCore::Types::Value::Any,
|
45
45
|
SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
|
46
46
|
SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
|
47
47
|
SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
|
@@ -83,7 +83,7 @@ class SmartCore::Initializer::Attribute::Definer
|
|
83
83
|
names.map do |name|
|
84
84
|
build_attribute(
|
85
85
|
name,
|
86
|
-
SmartCore::Types::Any,
|
86
|
+
SmartCore::Types::Value::Any,
|
87
87
|
SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
|
88
88
|
SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
|
89
89
|
SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
|
@@ -14,7 +14,7 @@ class SmartCore::Initializer::Attribute::Factory
|
|
14
14
|
#
|
15
15
|
# @api private
|
16
16
|
# @since 0.1.0
|
17
|
-
def create(name, type,
|
17
|
+
def create(name, type, privacy, finalize, cast, dynamic_options)
|
18
18
|
name = prepare_name_param(name)
|
19
19
|
type = prepare_type_param(type)
|
20
20
|
privacy = prepare_privacy_param(privacy)
|
@@ -28,7 +28,7 @@ class SmartCore::Initializer::Attribute::Factory
|
|
28
28
|
private
|
29
29
|
|
30
30
|
# @param name [String, Symbol]
|
31
|
-
# @return [
|
31
|
+
# @return [Symbol]
|
32
32
|
#
|
33
33
|
# @api private
|
34
34
|
# @since 0.1.0
|
@@ -39,7 +39,7 @@ class SmartCore::Initializer::Attribute::Factory
|
|
39
39
|
ERROR_MESSAGE
|
40
40
|
end
|
41
41
|
|
42
|
-
name.
|
42
|
+
name.to_sym
|
43
43
|
end
|
44
44
|
|
45
45
|
# @param type [String, Symbol, SmartCore::Types::Primitive]
|
@@ -54,7 +54,11 @@ class SmartCore::Initializer::Attribute::Factory
|
|
54
54
|
ERROR_MESSAGE
|
55
55
|
end
|
56
56
|
|
57
|
-
type
|
57
|
+
if type.is_a?(String) || type.is_a?(Symbol)
|
58
|
+
SmartCore::Initializer.type_from_alias(type)
|
59
|
+
else
|
60
|
+
type
|
61
|
+
end
|
58
62
|
end
|
59
63
|
|
60
64
|
# @param cast [Boolean]
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Initializer::Attribute::Finalizer::Abstract
|
6
|
+
# @param finalizer [Any]
|
7
|
+
# @return [void]
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
# @since 0.1.0
|
11
|
+
def initialize(finalizer)
|
12
|
+
@finalizer = finalizer
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param value [Any]
|
16
|
+
# @param instance [Any]
|
17
|
+
# @return [Any]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 0.1.0
|
21
|
+
def call(value, instance)
|
22
|
+
raise NoMethodError
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [SmartCore::Initializer::Attribute::Finalizer::Abstract]
|
26
|
+
def dup
|
27
|
+
self.class.new(finalizer)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# @return [Any]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
# @since 0.1.0
|
36
|
+
attr_reader :finalizer
|
37
|
+
end
|
@@ -1,32 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
# @since 0.1.0
|
5
|
-
class SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock
|
6
|
-
# @param finalizer [Proc]
|
7
|
-
# @return [void]
|
8
|
-
#
|
9
|
-
# @api private
|
10
|
-
# @since 0.1.0
|
11
|
-
def initialize(finalizer)
|
12
|
-
@finalizer = finalizer
|
13
|
-
end
|
14
|
-
|
15
|
-
# @param value [Any]
|
16
|
-
# @param isntance [Any]
|
17
|
-
# @return [value]
|
18
|
-
#
|
3
|
+
module SmartCore::Initializer::Attribute::Finalizer
|
19
4
|
# @pai private
|
20
5
|
# @since 0.1.0
|
21
|
-
|
22
|
-
|
23
|
-
|
6
|
+
class AnonymousBlock < Abstract
|
7
|
+
# @param finalizer [Proc]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def initialize(finalizer)
|
13
|
+
@finalizer = finalizer
|
14
|
+
end
|
24
15
|
|
25
|
-
|
16
|
+
# @param value [Any]
|
17
|
+
# @param instance [Any]
|
18
|
+
# @return [value]
|
19
|
+
#
|
20
|
+
# @pai private
|
21
|
+
# @since 0.1.0
|
22
|
+
def call(value, instance)
|
23
|
+
instance.instance_exec(value, &finalizer)
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
private
|
27
|
+
|
28
|
+
# @return [NilClass, Any]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
# @since 0.1.0
|
32
|
+
attr_reader :finalizer
|
33
|
+
end
|
32
34
|
end
|
@@ -1,32 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
# @since 0.1.0
|
5
|
-
class SmartCore::Initializer::Attribute::Finalizer::InstanceMethod
|
6
|
-
# @param finalizer [String, Symbol]
|
7
|
-
# @return [void]
|
8
|
-
#
|
9
|
-
# @api private
|
10
|
-
# @since 0.1.0
|
11
|
-
def initialize(finalizer)
|
12
|
-
@finalizer = finalizer
|
13
|
-
end
|
14
|
-
|
15
|
-
# @param value [Any]
|
16
|
-
# @param instance [Any]
|
17
|
-
# @return [value]
|
18
|
-
#
|
3
|
+
module SmartCore::Initializer::Attribute::Finalizer
|
19
4
|
# @pai private
|
20
5
|
# @since 0.1.0
|
21
|
-
|
22
|
-
|
23
|
-
|
6
|
+
class InstanceMethod < Abstract
|
7
|
+
# @param finalizer [String, Symbol]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def initialize(finalizer)
|
13
|
+
@finalizer = finalizer
|
14
|
+
end
|
24
15
|
|
25
|
-
|
16
|
+
# @param value [Any]
|
17
|
+
# @param instance [Any]
|
18
|
+
# @return [value]
|
19
|
+
#
|
20
|
+
# @pai private
|
21
|
+
# @since 0.1.0
|
22
|
+
def call(value, instance)
|
23
|
+
instance.send(finalizer, value)
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
private
|
27
|
+
|
28
|
+
# @return [NilClass, Any]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
# @since 0.1.0
|
32
|
+
attr_reader :finalizer
|
33
|
+
end
|
32
34
|
end
|
@@ -3,15 +3,10 @@
|
|
3
3
|
# @api private
|
4
4
|
# @since 0.1.0
|
5
5
|
module SmartCore::Initializer::Attribute::Finalizer
|
6
|
+
require_relative 'finalizer/abstract'
|
6
7
|
require_relative 'finalizer/instance_method'
|
7
8
|
require_relative 'finalizer/anonymous_block'
|
8
9
|
|
9
|
-
# @return [Proc]
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
# @since 0.1.0
|
13
|
-
DEFAULT_FINALIZER = proc { |value| value }.freeze
|
14
|
-
|
15
10
|
class << self
|
16
11
|
# @param finalization_approach [String, Symbol, Proc]
|
17
12
|
# @return [SmartCore::Initializer::Attribute::Finalizer::InstanceMethod]
|
@@ -25,6 +25,17 @@ class SmartCore::Initializer::Attribute::List
|
|
25
25
|
end
|
26
26
|
alias_method :<<, :add
|
27
27
|
|
28
|
+
# @param list [SmartCore::Initializer::Attribute::List]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def concat(list)
|
34
|
+
thread_safe do
|
35
|
+
list.each { |attribute| add(attribute.dup) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
28
39
|
# @param attribute [SmartCore::Initializer::Attribute]
|
29
40
|
# @return [void]
|
30
41
|
#
|
@@ -45,6 +56,23 @@ class SmartCore::Initializer::Attribute::List
|
|
45
56
|
end
|
46
57
|
end
|
47
58
|
|
59
|
+
# @return [Integer]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
# @since 0.1.0
|
63
|
+
def size
|
64
|
+
thread_safe { attributes.size }
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param block [Block]
|
68
|
+
# @return [Integer]
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
# @since 0.1.0
|
72
|
+
def count(&block)
|
73
|
+
thread_safe { attributes.values.count(&block) }
|
74
|
+
end
|
75
|
+
|
48
76
|
private
|
49
77
|
|
50
78
|
# @return [Hash<String,SmartCore::Initializer::Attribute>]
|
@@ -10,7 +10,7 @@ class SmartCore::Initializer::Attribute::Parameters
|
|
10
10
|
PRIVACY_MODES = {
|
11
11
|
public: :public,
|
12
12
|
protected: :protected,
|
13
|
-
private: :private
|
13
|
+
private: :private
|
14
14
|
}.freeze
|
15
15
|
|
16
16
|
# @return [Symbol]
|
@@ -37,7 +37,7 @@ class SmartCore::Initializer::Attribute::Parameters
|
|
37
37
|
# @since 0.1.0
|
38
38
|
DEFAULT_DYNAMIC_OPTIONS = {}.freeze
|
39
39
|
|
40
|
-
# @return [
|
40
|
+
# @return [Symbol]
|
41
41
|
#
|
42
42
|
# @api private
|
43
43
|
# @since 0.1.0
|
@@ -67,13 +67,21 @@ class SmartCore::Initializer::Attribute::Parameters
|
|
67
67
|
# @api private
|
68
68
|
# @since 0.1.0
|
69
69
|
attr_reader :cast
|
70
|
+
alias_method :cast?, :cast
|
70
71
|
|
71
|
-
# @
|
72
|
+
# @return [Hash<Symbol,Any>]
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
# @since 0.1.0
|
76
|
+
attr_reader :dynamic_options
|
77
|
+
|
78
|
+
# @param name [Symbol]
|
72
79
|
# @param type [SmartCore::Types::Primitive]
|
73
80
|
# @param privacy [Symbol]
|
74
81
|
# @param finalizer [SmartCore::Initializer::Attribute::AnonymousBlock/InstanceMethod]
|
75
82
|
# @param cast [Boolean]
|
76
83
|
# @param dynamic_options [Hash<Symbol,Any>]
|
84
|
+
# - :default - default value (Proc value will be called)
|
77
85
|
# @return [void]
|
78
86
|
#
|
79
87
|
# @api private
|
@@ -87,11 +95,27 @@ class SmartCore::Initializer::Attribute::Parameters
|
|
87
95
|
@dynamic_options = dynamic_options
|
88
96
|
end
|
89
97
|
|
90
|
-
|
98
|
+
# @return [Boolean]
|
99
|
+
#
|
100
|
+
# @api private
|
101
|
+
# @since 0.1.0
|
102
|
+
def has_default?
|
103
|
+
dynamic_options.key?(:default)
|
104
|
+
end
|
91
105
|
|
92
|
-
# @return [
|
106
|
+
# @return [Any]
|
107
|
+
#
|
108
|
+
# @raise [SmartCore::Initializer::NoDefaultValueError]
|
93
109
|
#
|
94
110
|
# @api private
|
95
111
|
# @since 0.1.0
|
96
|
-
|
112
|
+
def default
|
113
|
+
default_value = dynamic_options.fetch(:default) do
|
114
|
+
raise(SmartCore::Initializer::NoDefaultValueError, <<~ERROR_MESSAGE)
|
115
|
+
Attribute #{name} has no default value
|
116
|
+
ERROR_MESSAGE
|
117
|
+
end
|
118
|
+
|
119
|
+
defalut_value.is_a?(Proc) ? default_value.call : default_value
|
120
|
+
end
|
97
121
|
end
|
@@ -10,39 +10,51 @@ class SmartCore::Initializer::Attribute
|
|
10
10
|
require_relative 'attribute/factory'
|
11
11
|
|
12
12
|
# @since 0.1.0
|
13
|
-
extend Forwardable
|
13
|
+
extend ::Forwardable
|
14
14
|
|
15
|
-
# @
|
15
|
+
# @return [Symbol]
|
16
16
|
#
|
17
|
+
# @pai private
|
17
18
|
# @since 0.1.0
|
18
|
-
# @version 0.1.0
|
19
19
|
def_delegator :parameters, :name
|
20
20
|
|
21
|
-
# @
|
21
|
+
# @return [SmartCore::Types::Primitive]
|
22
22
|
#
|
23
|
+
# @pai private
|
23
24
|
# @since 0.1.0
|
24
|
-
# @version 0.1.0
|
25
25
|
def_delegator :parameters, :type
|
26
26
|
|
27
|
-
# @
|
27
|
+
# @return [Symbol]
|
28
28
|
#
|
29
|
+
# @pai private
|
29
30
|
# @since 0.1.0
|
30
|
-
# @version 0.1.0
|
31
31
|
def_delegator :parameters, :privacy
|
32
32
|
|
33
|
-
# @
|
33
|
+
# @return [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock/InstanceMethod]
|
34
34
|
#
|
35
|
+
# @pai private
|
35
36
|
# @since 0.1.0
|
36
|
-
# @version 0.1.0
|
37
37
|
def_delegator :parameters, :finalizer
|
38
38
|
|
39
|
-
# @
|
39
|
+
# @return [Boolean]
|
40
40
|
#
|
41
|
+
# @pai private
|
41
42
|
# @since 0.1.0
|
42
|
-
|
43
|
-
def_delegator :parameters, :cast
|
43
|
+
def_delegators :parameters, :cast, :cast?
|
44
44
|
|
45
|
-
# @
|
45
|
+
# @return [Any]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @since 0.1.0
|
49
|
+
def_delegator :parameters, :default
|
50
|
+
|
51
|
+
# @return [Boolean]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
# @since 0.1.0
|
55
|
+
def_delegator :parameters, :has_default?
|
56
|
+
|
57
|
+
# @param name [Symbol]
|
46
58
|
# @param type [SmartCore::Types::Primitive]
|
47
59
|
# @param privacy [Symbol]
|
48
60
|
# @param finalizer [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock/InstanceMethod]
|
@@ -58,6 +70,21 @@ class SmartCore::Initializer::Attribute
|
|
58
70
|
)
|
59
71
|
end
|
60
72
|
|
73
|
+
# @return [SmartCore::Initializer::Attribute]
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
# @since 0.1.0
|
77
|
+
def dup
|
78
|
+
self.class.new(
|
79
|
+
parameters.name.dup,
|
80
|
+
parameters.type,
|
81
|
+
parameters.privacy,
|
82
|
+
parameters.finalizer.dup,
|
83
|
+
parameters.cast,
|
84
|
+
parameters.dynamic_options.dup
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
61
88
|
private
|
62
89
|
|
63
90
|
# @return [SmartCore::Initializer::Attribute::Parameters]
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Initializer::Constructor
|
6
|
+
# @param klass [Class<SmartCore::Initializer>]
|
7
|
+
# @param arguments [Array<Any>]
|
8
|
+
# @param block [Proc, NilClass]
|
9
|
+
# @return [void]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.1.0
|
13
|
+
def initialize(klass, arguments, block)
|
14
|
+
@klass = klass
|
15
|
+
@arguments = arguments
|
16
|
+
@passed_parameters, @passed_options = extract_attributes(arguments)
|
17
|
+
@passed_block = block
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Any]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @since 0.1.0
|
24
|
+
def construct
|
25
|
+
allocate_klass_instance.tap do |instance|
|
26
|
+
prevent_attribute_insufficiency
|
27
|
+
initialize_parameters(instance)
|
28
|
+
initialize_options(instance)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @return [Class]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
# @since 0.1.0
|
38
|
+
attr_reader :klass
|
39
|
+
|
40
|
+
# @return [Array<Any>]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
# @since 0.1.0
|
44
|
+
attr_reader :arguments
|
45
|
+
|
46
|
+
# @return [Array<Any>]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
# @since 0.1.0
|
50
|
+
attr_reader :passed_parameters
|
51
|
+
|
52
|
+
# @return [Hash<Symbol,Any>]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
# @since 0.1.0
|
56
|
+
attr_reader :passed_options
|
57
|
+
|
58
|
+
# @return [Proc, NilClass]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
# @since 0.1.0
|
62
|
+
attr_reader :passed_block
|
63
|
+
|
64
|
+
# @return [void]
|
65
|
+
#
|
66
|
+
# @raise [SmartCore::Initializer::ParameterArgumentError]
|
67
|
+
# @raise [SmartCore::Initializer::OptionArgumentError]
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
# @since 0.1.0
|
71
|
+
def prevent_attribute_insufficiency
|
72
|
+
required_options = klass.__options__.reject(&:has_default?).map(&:name)
|
73
|
+
required_parameter_count = klass.__params__.size
|
74
|
+
|
75
|
+
raise(
|
76
|
+
SmartCore::Initializer::ParameterArgumentError,
|
77
|
+
"Wrong number of parameters " \
|
78
|
+
"(given #{passed_parameters.size}, expected #{required_parameter_count})"
|
79
|
+
) unless passed_parameters.size == required_parameter_count
|
80
|
+
|
81
|
+
missing_options = required_options.reject { |option| passed_options.key?(option) }
|
82
|
+
|
83
|
+
raise(
|
84
|
+
SmartCore::Initializer::OptionArgumentError,
|
85
|
+
"Missing options: #{missing_options.join(', ')}"
|
86
|
+
) if missing_options.any?
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Any]
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
# @since 0.1.0
|
93
|
+
def allocate_klass_instance
|
94
|
+
klass.allocate
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param instance [Any]
|
98
|
+
# @return [void]
|
99
|
+
#
|
100
|
+
# @api private
|
101
|
+
# @since 0.1.0
|
102
|
+
def initialize_parameters(instance)
|
103
|
+
parameter_definitions = Hash[klass.__params__.zip(passed_parameters)]
|
104
|
+
|
105
|
+
parameter_definitions.each_pair do |attribute, parameter_value|
|
106
|
+
parameter_value = attribute.type.cast(parameter_value) if attribute.cast?
|
107
|
+
|
108
|
+
# TODO: fail with SmartCore::Initializer::ArgumentError
|
109
|
+
# (isntead of SmartCore::Types::TypeError)
|
110
|
+
attribute.type.validate!(parameter_value)
|
111
|
+
|
112
|
+
final_value = attribute.finalizer.call(parameter_value, instance)
|
113
|
+
instance.instance_variable_set("@#{attribute.name}", final_value)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param instance [Any]
|
118
|
+
# @return [void]
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
# @since 0.1.0
|
122
|
+
def initialize_options(instance)
|
123
|
+
klass.__options__.each do |attribute|
|
124
|
+
option_value = passed_options.fetch(attribute.name) { attribute.default }
|
125
|
+
option_value = attribute.type.cast(option_value) if attribute.cast?
|
126
|
+
|
127
|
+
# TODO: fail with SmartCore::Initializer::ArgumentError
|
128
|
+
# (isntead of SmartCore::Types::TypeError)
|
129
|
+
attribute.type.validate!(option_value)
|
130
|
+
|
131
|
+
final_value = attribute.finalizer.call(option_value, instance)
|
132
|
+
instance.instance_variable_set("@#{attribute.name}", final_value)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @param arguments [Array<Any>]
|
137
|
+
# @return [Array<Array<Any>,Hash<Symbol,Any>>]
|
138
|
+
#
|
139
|
+
# @api private
|
140
|
+
# @since 0.1.0
|
141
|
+
def extract_attributes(arguments)
|
142
|
+
parameters = []
|
143
|
+
options = {}
|
144
|
+
|
145
|
+
if (
|
146
|
+
klass.__options__.size >= 1 &&
|
147
|
+
arguments.last.is_a?(Hash) &&
|
148
|
+
arguments.last.keys.all? { |key| key.is_a?(Symbol) }
|
149
|
+
)
|
150
|
+
parameters = arguments[0..-2]
|
151
|
+
options = arguments.last
|
152
|
+
else
|
153
|
+
parameters = arguments
|
154
|
+
end
|
155
|
+
|
156
|
+
[parameters, options]
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Initializer::DSL::Inheritance
|
6
|
+
class << self
|
7
|
+
# @param base [Class]
|
8
|
+
# @param child [Class]
|
9
|
+
# @return [void]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.1.0
|
13
|
+
def inherit(base:, child:)
|
14
|
+
child.__params__.concat(base.__params__)
|
15
|
+
child.__options__.concat(base.__options__)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -3,20 +3,44 @@
|
|
3
3
|
# @api private
|
4
4
|
# @since 0.1.0
|
5
5
|
module SmartCore::Initializer::DSL
|
6
|
+
require_relative 'dsl/inheritance'
|
7
|
+
|
6
8
|
class << self
|
7
9
|
# @param base_klass [Class]
|
8
10
|
# @return [void]
|
9
11
|
#
|
10
12
|
# @api private
|
11
13
|
# @since 0.1.0
|
12
|
-
def
|
14
|
+
def extended(base_klass)
|
13
15
|
base_klass.instance_eval do
|
14
16
|
instance_variable_set(:@__params__, SmartCore::Initializer::Attribute::List.new)
|
15
17
|
instance_variable_set(:@__options__, SmartCore::Initializer::Attribute::List.new)
|
16
18
|
instance_variable_set(:@__definer__, SmartCore::Initializer::Attribute::Definer.new(self))
|
19
|
+
instance_variable_set(:@__deflock__, SmartCore::Engine::Lock.new)
|
17
20
|
end
|
18
|
-
|
19
21
|
base_klass.extend(ClassMethods)
|
22
|
+
base_klass.singleton_class.prepend(ClassInheritance)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
# @since 0.1.0
|
28
|
+
module ClassInheritance
|
29
|
+
# @param child_klass [Class]
|
30
|
+
# @return [void]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
# @since 0.1.0
|
34
|
+
def inherited(child_klass)
|
35
|
+
child_klass.instance_eval do
|
36
|
+
instance_variable_set(:@__params__, SmartCore::Initializer::Attribute::List.new)
|
37
|
+
instance_variable_set(:@__options__, SmartCore::Initializer::Attribute::List.new)
|
38
|
+
instance_variable_set(:@__definer__, SmartCore::Initializer::Attribute::Definer.new(self))
|
39
|
+
instance_variable_set(:@__deflock__, SmartCore::Engine::Lock.new)
|
40
|
+
end
|
41
|
+
child_klass.extend(ClassMethods)
|
42
|
+
SmartCore::Initializer::DSL::Inheritance.inherit(base: self, child: child_klass)
|
43
|
+
super
|
20
44
|
end
|
21
45
|
end
|
22
46
|
|
@@ -47,6 +71,16 @@ module SmartCore::Initializer::DSL
|
|
47
71
|
@__definer__
|
48
72
|
end
|
49
73
|
|
74
|
+
# @param arguments [Array]
|
75
|
+
# @param block [Block]
|
76
|
+
# @return [Any]
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
# @since 0.1.0
|
80
|
+
def new(*arguments, &block)
|
81
|
+
SmartCore::Initializer::Constructor.new(self, arguments, block).construct
|
82
|
+
end
|
83
|
+
|
50
84
|
# @param name [String, Symbol]
|
51
85
|
# @param type [String, Symbol, SmartCore::Types::Primitive]
|
52
86
|
# @option cast [Boolean]
|
@@ -9,6 +9,18 @@ module SmartCore::Initializer
|
|
9
9
|
# @since 0.1.0
|
10
10
|
ArgumentError = Class.new(SmartCore::ArgumentError)
|
11
11
|
|
12
|
+
# @api public
|
13
|
+
# @since 0.1.0
|
14
|
+
ParameterArgumentError = Class.new(ArgumentError)
|
15
|
+
|
16
|
+
# @api public
|
17
|
+
# @since 0.1.0
|
18
|
+
OptionArgumentError = Class.new(ArgumentError)
|
19
|
+
|
20
|
+
# @api public
|
21
|
+
# @since 0.1.0
|
22
|
+
NoDefaultValueError = Class.new(Error)
|
23
|
+
|
12
24
|
# @api public
|
13
25
|
# @since 0.1.0
|
14
26
|
OptionOverlapError = Class.new(ArgumentError)
|
@@ -16,4 +28,8 @@ module SmartCore::Initializer
|
|
16
28
|
# @api public
|
17
29
|
# @since 0.1.0
|
18
30
|
ParameterOverlapError = Class.new(ArgumentError)
|
31
|
+
|
32
|
+
# @api public
|
33
|
+
# @since 0.1.0
|
34
|
+
NoTypeAliasError = Class.new(Error)
|
19
35
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Initializer::TypeAliasing::AliasList
|
6
|
+
# @return [void]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.1.0
|
10
|
+
def initialize
|
11
|
+
@list = {}
|
12
|
+
@lock = SmartCore::Engine::Lock.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param alias_name [String, Symbol]
|
16
|
+
# @param type [SmartCore::Types::Primitive]
|
17
|
+
# @return [void]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 0.1.0
|
21
|
+
def associate(alias_name, type)
|
22
|
+
raise(
|
23
|
+
SmartCore::Initializer::ArgumentError,
|
24
|
+
'Type alias should be a type of string or symbol'
|
25
|
+
) unless alias_name.is_a?(String) || alias_name.is_a?(Symbol)
|
26
|
+
|
27
|
+
raise(
|
28
|
+
SmartCore::Initializer::ArgumentError,
|
29
|
+
'Type object should be a type of SmartCore::Types::Primitive'
|
30
|
+
) unless type.is_a?(SmartCore::Types::Primitive)
|
31
|
+
|
32
|
+
thread_safe { set_alias(alias_name, type) }
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param alias_name [String, Symbol]
|
36
|
+
# @return [SmartCore::Types::Primitive]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
# @since 0.1.0
|
40
|
+
def resolve(alias_name)
|
41
|
+
raise(
|
42
|
+
SmartCore::Initializer::ArgumentError,
|
43
|
+
'Type alias should be a type of string or symbol'
|
44
|
+
) unless alias_name.is_a?(String) || alias_name.is_a?(Symbol)
|
45
|
+
|
46
|
+
thread_safe { get_alias(alias_name) }
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# @return [Hash<String,SmartCore::Types::Primitive>]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
# @since 0.1.0
|
55
|
+
attr_reader :list
|
56
|
+
|
57
|
+
# @param block [Block]
|
58
|
+
# @return [Any]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
# @since 0.1.0
|
62
|
+
def thread_safe(&block)
|
63
|
+
@lock.synchronize(&block)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param alias_name [String, Symbol]
|
67
|
+
# @param type [SmartCore::Types::Primitive]
|
68
|
+
# @return [void]
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
# @since 0.1.0
|
72
|
+
def set_alias(alias_name, type)
|
73
|
+
alias_name = normalized_alias(alias_name)
|
74
|
+
::Warning.warn( # TODO: SmartCore::Engine::Instrumenting
|
75
|
+
"[SmartCore::Initializer] Type alias with name \"#{alias_name}\"" \
|
76
|
+
' is already exists and shadowed by new type.'
|
77
|
+
) if list.key?(alias_name)
|
78
|
+
list[normalized_alias(alias_name)] = type
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param alias_name [String, Symbol]
|
82
|
+
# @return [SmartCore::Types::Primitive]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
# @since 0.1.0
|
86
|
+
def get_alias(alias_name)
|
87
|
+
list.fetch(normalized_alias(alias_name)) do
|
88
|
+
raise(SmartCore::Initializer::NoTypeAliasError, <<~ERROR_MESSAGE)
|
89
|
+
Alias with name "#{alias_name}" does not exist
|
90
|
+
ERROR_MESSAGE
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param alias_name [String, Symbol]
|
95
|
+
# @return [String]
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
# @since 0.1.0
|
99
|
+
def normalized_alias(alias_name)
|
100
|
+
alias_name.to_s
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Initializer::TypeAliasing
|
6
|
+
require_relative 'type_aliasing/alias_list'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# @param base_klass [Class]
|
10
|
+
# @return [void]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
# @since 0.1.0
|
14
|
+
def extended(base_klass)
|
15
|
+
base_klass.instance_variable_set(:@__type_aliases__, AliasList.new)
|
16
|
+
base_klass.extend(ClassMethods)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
# @since 0.1.0
|
22
|
+
module ClassMethods
|
23
|
+
# @return [SmartCore::Initializer::TypeAliasing::AliasList]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
# @since 0.1.0
|
27
|
+
def __type_aliases__
|
28
|
+
@__type_aliases__
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param alias_name [String, Symbol]
|
32
|
+
# @param type [SmartCore::Types::Primitive]
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
# @since 0.1.0
|
37
|
+
def type_alias(alias_name, type)
|
38
|
+
__type_aliases__.associate(alias_name, type)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param alias_name [String, Symbol]
|
42
|
+
# @return [SmartCore::Types::Primitive]
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
# @since 0.1.0
|
46
|
+
def type_from_alias(alias_name)
|
47
|
+
__type_aliases__.resolve(alias_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'smart_core'
|
4
4
|
require 'smart_core/types'
|
5
|
+
require 'forwardable'
|
5
6
|
|
6
7
|
# @api public
|
7
8
|
# @since 0.1.0
|
@@ -9,7 +10,12 @@ module SmartCore::Initializer
|
|
9
10
|
require_relative 'initializer/version'
|
10
11
|
require_relative 'initializer/errors'
|
11
12
|
require_relative 'initializer/attribute'
|
13
|
+
require_relative 'initializer/constructor'
|
12
14
|
require_relative 'initializer/dsl'
|
15
|
+
require_relative 'initializer/type_aliasing'
|
16
|
+
|
17
|
+
# @since 0.1.0
|
18
|
+
extend SmartCore::Initializer::TypeAliasing
|
13
19
|
|
14
20
|
class << self
|
15
21
|
# @param base_klass [Class]
|
@@ -18,7 +24,22 @@ module SmartCore::Initializer
|
|
18
24
|
# @api private
|
19
25
|
# @since 0.1.0
|
20
26
|
def included(base_klass)
|
21
|
-
base_klass.
|
27
|
+
base_klass.extend(SmartCore::Initializer::DSL)
|
22
28
|
end
|
23
29
|
end
|
30
|
+
|
31
|
+
type_alias(:nil, SmartCore::Types::Value::Nil)
|
32
|
+
type_alias(:string, SmartCore::Types::Value::String)
|
33
|
+
type_alias(:symbol, SmartCore::Types::Value::Symbol)
|
34
|
+
type_alias(:text, SmartCore::Types::Value::Text)
|
35
|
+
type_alias(:integer, SmartCore::Types::Value::Integer)
|
36
|
+
type_alias(:float, SmartCore::Types::Value::Float)
|
37
|
+
type_alias(:numeric, SmartCore::Types::Value::Numeric)
|
38
|
+
type_alias(:boolean, SmartCore::Types::Value::Boolean)
|
39
|
+
type_alias(:array, SmartCore::Types::Value::Array)
|
40
|
+
type_alias(:hash, SmartCore::Types::Value::Hash)
|
41
|
+
type_alias(:proc, SmartCore::Types::Value::Proc)
|
42
|
+
type_alias(:class, SmartCore::Types::Value::Class)
|
43
|
+
type_alias(:module, SmartCore::Types::Value::Module)
|
44
|
+
type_alias(:any, SmartCore::Types::Value::Any)
|
24
45
|
end
|
data/smart_initializer.gemspec
CHANGED
@@ -27,8 +27,8 @@ 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.
|
31
|
-
spec.add_dependency 'smart_types', '~> 0.1.0.
|
30
|
+
spec.add_dependency 'smart_engine', '~> 0.5'
|
31
|
+
spec.add_dependency 'smart_types', '~> 0.1.0.alpha4'
|
32
32
|
|
33
33
|
spec.add_development_dependency 'bundler', '~> 2.1'
|
34
34
|
spec.add_development_dependency 'rake', '~> 13.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_initializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.1.0.alpha1
|
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-
|
11
|
+
date: 2020-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: smart_engine
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.5'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.5'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: smart_types
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.1.0.
|
33
|
+
version: 0.1.0.alpha4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.1.0.
|
40
|
+
version: 0.1.0.alpha4
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,12 +133,17 @@ files:
|
|
133
133
|
- lib/smart_core/initializer/attribute/definer.rb
|
134
134
|
- lib/smart_core/initializer/attribute/factory.rb
|
135
135
|
- lib/smart_core/initializer/attribute/finalizer.rb
|
136
|
+
- lib/smart_core/initializer/attribute/finalizer/abstract.rb
|
136
137
|
- lib/smart_core/initializer/attribute/finalizer/anonymous_block.rb
|
137
138
|
- lib/smart_core/initializer/attribute/finalizer/instance_method.rb
|
138
139
|
- lib/smart_core/initializer/attribute/list.rb
|
139
140
|
- lib/smart_core/initializer/attribute/parameters.rb
|
141
|
+
- lib/smart_core/initializer/constructor.rb
|
140
142
|
- lib/smart_core/initializer/dsl.rb
|
143
|
+
- lib/smart_core/initializer/dsl/inheritance.rb
|
141
144
|
- lib/smart_core/initializer/errors.rb
|
145
|
+
- lib/smart_core/initializer/type_aliasing.rb
|
146
|
+
- lib/smart_core/initializer/type_aliasing/alias_list.rb
|
142
147
|
- lib/smart_core/initializer/version.rb
|
143
148
|
- smart_initializer.gemspec
|
144
149
|
homepage: https://github.com/smart-rb/smart_initialier
|
@@ -159,9 +164,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
164
|
version: 2.4.9
|
160
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
166
|
requirements:
|
162
|
-
- - "
|
167
|
+
- - ">"
|
163
168
|
- !ruby/object:Gem::Version
|
164
|
-
version:
|
169
|
+
version: 1.3.1
|
165
170
|
requirements: []
|
166
171
|
rubygems_version: 3.1.2
|
167
172
|
signing_key:
|