smart_initializer 0.1.0.alpha2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +36 -5
  4. data/CHANGELOG.md +15 -0
  5. data/Gemfile.lock +63 -43
  6. data/README.md +263 -11
  7. data/Rakefile +1 -1
  8. data/bin/rspec +54 -0
  9. data/gemfiles/with_external_deps.gemfile +7 -0
  10. data/gemfiles/with_external_deps.gemfile.lock +102 -0
  11. data/gemfiles/without_external_deps.gemfile +5 -0
  12. data/gemfiles/without_external_deps.gemfile.lock +100 -0
  13. data/lib/smart_core/initializer.rb +44 -28
  14. data/lib/smart_core/initializer/attribute.rb +12 -5
  15. data/lib/smart_core/initializer/attribute/factory.rb +47 -27
  16. data/lib/smart_core/initializer/attribute/parameters.rb +12 -4
  17. data/lib/smart_core/initializer/configuration.rb +33 -0
  18. data/lib/smart_core/initializer/constructor.rb +60 -23
  19. data/lib/smart_core/initializer/{attribute → constructor}/definer.rb +64 -12
  20. data/lib/smart_core/initializer/dsl.rb +47 -10
  21. data/lib/smart_core/initializer/dsl/inheritance.rb +1 -0
  22. data/lib/smart_core/initializer/errors.rb +44 -0
  23. data/lib/smart_core/initializer/extensions.rb +9 -0
  24. data/lib/smart_core/initializer/extensions/abstract.rb +8 -0
  25. data/lib/smart_core/initializer/extensions/ext_init.rb +31 -0
  26. data/lib/smart_core/initializer/extensions/list.rb +74 -0
  27. data/lib/smart_core/initializer/functionality.rb +36 -0
  28. data/lib/smart_core/initializer/instance_attribute_accessing.rb +51 -0
  29. data/lib/smart_core/initializer/plugins.rb +17 -0
  30. data/lib/smart_core/initializer/plugins/abstract.rb +55 -0
  31. data/lib/smart_core/initializer/plugins/access_mixin.rb +47 -0
  32. data/lib/smart_core/initializer/plugins/registry.rb +166 -0
  33. data/lib/smart_core/initializer/plugins/registry_interface.rb +77 -0
  34. data/lib/smart_core/initializer/plugins/thy_types.rb +30 -0
  35. data/lib/smart_core/initializer/plugins/thy_types/errors.rb +11 -0
  36. data/lib/smart_core/initializer/plugins/thy_types/thy_types.rb +23 -0
  37. data/lib/smart_core/initializer/plugins/thy_types/thy_types/abstract_factory.rb +78 -0
  38. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation.rb +12 -0
  39. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/base.rb +9 -0
  40. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/cast.rb +21 -0
  41. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/valid.rb +16 -0
  42. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/validate.rb +19 -0
  43. data/lib/smart_core/initializer/settings.rb +49 -0
  44. data/lib/smart_core/initializer/settings/duplicator.rb +20 -0
  45. data/lib/smart_core/initializer/settings/type_system.rb +69 -0
  46. data/lib/smart_core/initializer/type_system.rb +16 -0
  47. data/lib/smart_core/initializer/type_system/interop.rb +103 -0
  48. data/lib/smart_core/initializer/type_system/interop/abstract_factory.rb +70 -0
  49. data/lib/smart_core/initializer/type_system/interop/aliasing.rb +72 -0
  50. data/lib/smart_core/initializer/type_system/interop/aliasing/alias_list.rb +141 -0
  51. data/lib/smart_core/initializer/type_system/interop/operation.rb +30 -0
  52. data/lib/smart_core/initializer/type_system/registry.rb +174 -0
  53. data/lib/smart_core/initializer/type_system/registry_interface.rb +102 -0
  54. data/lib/smart_core/initializer/type_system/smart_types.rb +48 -0
  55. data/lib/smart_core/initializer/type_system/smart_types/abstract_factory.rb +72 -0
  56. data/lib/smart_core/initializer/type_system/smart_types/operation.rb +13 -0
  57. data/lib/smart_core/initializer/type_system/smart_types/operation/base.rb +8 -0
  58. data/lib/smart_core/initializer/type_system/smart_types/operation/cast.rb +16 -0
  59. data/lib/smart_core/initializer/type_system/smart_types/operation/valid.rb +16 -0
  60. data/lib/smart_core/initializer/type_system/smart_types/operation/validate.rb +16 -0
  61. data/lib/smart_core/initializer/version.rb +2 -1
  62. data/smart_initializer.gemspec +13 -9
  63. metadata +73 -17
  64. data/lib/smart_core/initializer/type_aliasing.rb +0 -50
  65. data/lib/smart_core/initializer/type_aliasing/alias_list.rb +0 -101
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ module SmartCore::Initializer::TypeSystem
6
+ require_relative 'type_system/interop'
7
+ require_relative 'type_system/registry'
8
+ require_relative 'type_system/smart_types'
9
+ require_relative 'type_system/registry_interface'
10
+
11
+ # @since 0.1.0
12
+ extend SmartCore::Initializer::TypeSystem::RegistryInterface
13
+
14
+ # @since 0.1.0
15
+ register(:smart_types, SmartCore::Initializer::TypeSystem::SmartTypes)
16
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @abstract
4
+ # @api private
5
+ # @since 0.1.0
6
+ class SmartCore::Initializer::TypeSystem::Interop
7
+ require_relative 'interop/operation'
8
+ require_relative 'interop/abstract_factory'
9
+ require_relative 'interop/aliasing'
10
+
11
+ # @since 0.1.0
12
+ include SmartCore::Initializer::TypeSystem::Interop::Aliasing
13
+
14
+ class << self
15
+ # @param type_object [Any]
16
+ # @return [SmartCore::Initializer::TypeSystem::Interop]
17
+ #
18
+ # @api private
19
+ # @since 0.1.0
20
+ def create(type_object)
21
+ self::AbstractFactory.create(type_object)
22
+ end
23
+
24
+ # @return [SmartCore::Initialiezr::TypeSystem::Interop]
25
+ #
26
+ # @api private
27
+ # @since 0.1.0
28
+ def generic_type_object
29
+ self::AbstractFactory.generic_type_object
30
+ end
31
+
32
+ # @param type_object [Any]
33
+ # @return [void]
34
+ #
35
+ # @raise [SmartCore::Initializer::IncorrectTypeObjectError]
36
+ #
37
+ # @api private
38
+ # @since 0.1.0
39
+ def prevent_incompatible_type!(type_object)
40
+ self::AbstractFactory.prevent_incompatible_type!(type_object)
41
+ end
42
+ end
43
+
44
+ # @param valid_op [SmartCore::Initializer::TypeSystem::Interop::Operation]
45
+ # @param validate_op [SmartCore::Initializer::TypeSystem::Interop::Operation]
46
+ # @param cast_op [SmartCore::Initializer::TypeSystem::Interop::Operation]
47
+ # @return [void]
48
+ #
49
+ # @api private
50
+ # @since 0.1.0
51
+ def initialize(valid_op, validate_op, cast_op)
52
+ @valid_op = valid_op
53
+ @validate_op = validate_op
54
+ @cast_op = cast_op
55
+ end
56
+
57
+ # @param value [Any]
58
+ # @return [Boolean]
59
+ #
60
+ # @api private
61
+ # @since 0.1.0
62
+ def valid?(value)
63
+ valid_op.call(value)
64
+ end
65
+
66
+ # @param value [Any]
67
+ # @return [void]
68
+ #
69
+ # @api private
70
+ # @since 0.1.0
71
+ def validate!(value)
72
+ validate_op.call(value)
73
+ end
74
+
75
+ # @param value [Any]
76
+ # @return [Any]
77
+ #
78
+ # @api private
79
+ # @since 0.1.0
80
+ def cast(value)
81
+ cast_op.call(value)
82
+ end
83
+
84
+ private
85
+
86
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Operation]
87
+ #
88
+ # @api private
89
+ # @since 0.1.0
90
+ attr_reader :valid_op
91
+
92
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Operation]
93
+ #
94
+ # @api private
95
+ # @since 0.1.0
96
+ attr_reader :validate_op
97
+
98
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Operation]
99
+ #
100
+ # @api private
101
+ # @since 0.1.0
102
+ attr_reader :cast_op
103
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @abstract
4
+ # @api private
5
+ # @since 0.1.0
6
+ class SmartCore::Initializer::TypeSystem::Interop::AbstractFactory
7
+ class << self
8
+ # @param type [Any]
9
+ # @return [SmartCore::Initializer::TypeSystem::Interop]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def create(type)
14
+ prevent_incompatible_type!(type)
15
+
16
+ valid_op = build_valid_operation(type)
17
+ validate_op = build_validate_operation(type)
18
+ cast_op = build_cast_operation(type)
19
+
20
+ build_interop(valid_op, validate_op, cast_op)
21
+ end
22
+
23
+ # @return [Any]
24
+ #
25
+ # @api private
26
+ # @since 0.1.0
27
+ def generic_type_object; end
28
+
29
+ # @param type [Any]
30
+ # @return [void]
31
+ #
32
+ # @raise [SmartCore::Initializer::IncorrectTypeObjectError]
33
+ #
34
+ # @api private
35
+ # @since 0.1.0
36
+ def prevent_incompatible_type!(type); end
37
+
38
+ private
39
+
40
+ # @param type [Any]
41
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Operation]
42
+ #
43
+ # @api private
44
+ # @since 0.1.0
45
+ def build_valid_operation(type); end
46
+
47
+ # @param type [Any]
48
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Operation]
49
+ #
50
+ # @api private
51
+ # @since 0.1.0
52
+ def build_validate_operation(type); end
53
+
54
+ # @param type [Any]
55
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Operation]
56
+ #
57
+ # @api private
58
+ # @since 0.1.0
59
+ def build_cast_operation(type); end
60
+
61
+ # @param valid_op [SmartCore::Initializer::TypeSystem::Interop::Operation]
62
+ # @param validate_op [SmartCore::Initializer::TypeSystem::Interop::Operation]
63
+ # @param cast_op [SmartCore::Initializer::TypeSystem::Interop::Operation]
64
+ # @return [SmartCore::Initializer::TypeSystem::Interop]
65
+ #
66
+ # @api private
67
+ # @since 0.1.0
68
+ def build_interop(valid_op, validate_op, cast_op); end
69
+ end
70
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Initializer::TypeSystem::Interop::Aliasing
6
+ require_relative '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 included(base_klass)
15
+ base_klass.extend(ClassMethods)
16
+ base_klass.singleton_class.prepend(ClassInheritance)
17
+ end
18
+ end
19
+
20
+ # @api private
21
+ # @since 0.1.0
22
+ module ClassInheritance
23
+ # @param child_klass [Class<SmartCore::Initializer::TypeSystem::Interop>]
24
+ # @return [void]
25
+ #
26
+ # @api private
27
+ # @since 0.1.0
28
+ def inherited(child_klass)
29
+ child_klass.instance_variable_set(:@__type_aliases__, AliasList.new(child_klass))
30
+ super
31
+ end
32
+ end
33
+
34
+ # @api private
35
+ # @since 0.1.0
36
+ module ClassMethods
37
+ # @return [SmartCore::Initializer::TypeSystem::Interop::Aliasing::AliasList]
38
+ #
39
+ # @api private
40
+ # @since 0.1.0
41
+ def __type_aliases__
42
+ @__type_aliases__
43
+ end
44
+
45
+ # @return [Array<String>]
46
+ #
47
+ # @api public
48
+ # @since 0.1.0
49
+ def type_aliases
50
+ __type_aliases__.keys
51
+ end
52
+
53
+ # @param alias_name [String, Symbol]
54
+ # @param type [Any]
55
+ # @return [void]
56
+ #
57
+ # @api public
58
+ # @since 0.1.0
59
+ def type_alias(alias_name, type)
60
+ __type_aliases__.associate(alias_name, type)
61
+ end
62
+
63
+ # @param alias_name [String, Symbol]
64
+ # @return [Any]
65
+ #
66
+ # @api public
67
+ # @since 0.1.0
68
+ def type_from_alias(alias_name)
69
+ __type_aliases__.resolve(alias_name)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::TypeSystem::Interop::Aliasing::AliasList
6
+ # @param interop_klass [Class<SmartCore::Initializer::TypeSystem::Interop>]
7
+ # @return [void]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ def initialize(interop_klass)
12
+ @interop_klass = interop_klass
13
+ @list = {}
14
+ @lock = SmartCore::Engine::Lock.new
15
+ end
16
+
17
+ # @return [Array<String>]
18
+ #
19
+ # @api private
20
+ # @since 0.1.0
21
+ def keys
22
+ thread_safe { registered_aliases }
23
+ end
24
+
25
+ # @return [Hash<String,Any>]
26
+ #
27
+ # @api private
28
+ # @since 0.1.0
29
+ def to_h
30
+ thread_safe { transform_to_hash }
31
+ end
32
+ alias_method :to_hash, :to_h
33
+
34
+ # @param alias_name [String, Symbol]
35
+ # @param type [Any]
36
+ # @return [void]
37
+ #
38
+ # @api private
39
+ # @since 0.1.0
40
+ def associate(alias_name, type)
41
+ interop_klass.prevent_incompatible_type!(type)
42
+ thread_safe { set_alias(alias_name, type) }
43
+ end
44
+
45
+ # @param alias_name [String, Symbol]
46
+ # @return [Any]
47
+ #
48
+ # @api private
49
+ # @since 0.1.0
50
+ def resolve(alias_name)
51
+ thread_safe { get_alias(alias_name) }
52
+ end
53
+
54
+ private
55
+
56
+ # @return [Hash<String,Any>]
57
+ #
58
+ # @api private
59
+ # @since 0.1.0
60
+ attr_reader :list
61
+
62
+ # @return [Class<SmartCore::Initializer::TypeSystem::Interop>]
63
+ #
64
+ # @api private
65
+ # @since 0.1.0
66
+ attr_reader :interop_klass
67
+
68
+ # @param block [Block]
69
+ # @return [Any]
70
+ #
71
+ # @api private
72
+ # @since 0.1.0
73
+ def thread_safe(&block)
74
+ @lock.synchronize(&block)
75
+ end
76
+
77
+ # @param alias_name [String, Symbol]
78
+ # @param type [Any]
79
+ # @return [void]
80
+ #
81
+ # @api private
82
+ # @since 0.1.0
83
+ def set_alias(alias_name, type)
84
+ alias_name = normalized_alias(alias_name)
85
+
86
+ if list.key?(alias_name)
87
+ ::Warning.warn(
88
+ "[#{interop_klass.name}] Shadowing of the already existing \"#{alias_name}\" type alias."
89
+ )
90
+ end
91
+
92
+ list[alias_name] = type
93
+ end
94
+
95
+ # @param alias_name [String, Symbol]
96
+ # @return [Any]
97
+ #
98
+ # @api private
99
+ # @since 0.1.0
100
+ def get_alias(alias_name)
101
+ alias_name = normalized_alias(alias_name)
102
+
103
+ begin
104
+ list.fetch(alias_name)
105
+ rescue ::KeyError
106
+ raise(SmartCore::Initializer::TypeAliasNotFoundError, <<~ERROR_MESSAGE)
107
+ Alias with name "#{alias_name}" not found.
108
+ ERROR_MESSAGE
109
+ end
110
+ end
111
+
112
+ # @param alias_name [String, Symbol]
113
+ # @return [String]
114
+ #
115
+ # @api private
116
+ # @since 0.1.0
117
+ def normalized_alias(alias_name)
118
+ raise(
119
+ SmartCore::Initializer::ArgumentError,
120
+ 'Type alias should be a type of string or symbol'
121
+ ) unless alias_name.is_a?(String) || alias_name.is_a?(Symbol)
122
+
123
+ alias_name.to_s
124
+ end
125
+
126
+ # @return [Hash<String,Any>]
127
+ #
128
+ # @api private
129
+ # @since 0.1.0
130
+ def transform_to_hash
131
+ list.to_h
132
+ end
133
+
134
+ # @return [Array<String>]
135
+ #
136
+ # @api private
137
+ # @since 0.1.0
138
+ def registered_aliases
139
+ list.keys
140
+ end
141
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @abstract
4
+ # @api private
5
+ # @since 0.1.0
6
+ class SmartCore::Initializer::TypeSystem::Interop::Operation
7
+ # @param type [Any]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def initialize(type)
13
+ @type = type
14
+ end
15
+
16
+ # @param value [Any]
17
+ # @return [Any]
18
+ #
19
+ # @api private
20
+ # @since 0.1.0
21
+ def call(value); end
22
+
23
+ private
24
+
25
+ # @return [Any]
26
+ #
27
+ # @api private
28
+ # @since 0.1.0
29
+ attr_reader :type
30
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::TypeSystem::Registry
6
+ # @since 0.1.0
7
+ include Enumerable
8
+
9
+ # @return [void]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def initialize
14
+ @systems = {}
15
+ @lock = SmartCore::Engine::Lock.new
16
+ end
17
+
18
+ # @param system_identifier [String, Symbol]
19
+ # @param interop_klass [Class<SmartCore::Initializer::TypeSystem::Interop>]
20
+ # @return [void]
21
+ #
22
+ # @api private
23
+ # @since 0.1.0
24
+ def register(system_identifier, interop_klass)
25
+ thread_safe { apply(system_identifier, interop_klass) }
26
+ end
27
+
28
+ # @param system_identifier [String, Symbol]
29
+ # @return [Class<SmartCore::Initializer::TypeSystem::Interop>]
30
+ #
31
+ # @api private
32
+ # @since 0.1.0
33
+ def resolve(system_identifier)
34
+ thread_safe { fetch(system_identifier) }
35
+ end
36
+
37
+ # @return [Array<String>]
38
+ #
39
+ # @api private
40
+ # @since 0.1.0
41
+ def names
42
+ thread_safe { system_names }
43
+ end
44
+
45
+ # @return [Array<Class<SmartCore::Initializer::TypeSystem::Interop>>]
46
+ #
47
+ # @api private
48
+ # @since 0.1.0
49
+ def interops
50
+ thread_safe { system_interops }
51
+ end
52
+
53
+ # @param block [Block]
54
+ # @yield [system_name, system_interop]
55
+ # @yieldparam system_name [String]
56
+ # @yieldparam system_interop [Class<SmartCore::Initializer::TypeSystem::Interop>]
57
+ # @return [Enumerable]
58
+ #
59
+ # @api private
60
+ # @since 0.1.0
61
+ def each(&block)
62
+ thread_safe { iterate(&block) }
63
+ end
64
+
65
+ # @return [Hash<String,Class<SmartCore::Initializer::TypeSystem::Interop>]
66
+ #
67
+ # @api private
68
+ # @since 0.1.0
69
+ def to_h
70
+ thread_safe { systems.dup }
71
+ end
72
+ alias_method :to_hash, :to_h
73
+
74
+ private
75
+
76
+ # @return [Hash<String,Class<SmartCore::Initializer::TypeSystem::Interop>]
77
+ #
78
+ # @api private
79
+ # @since 0.1.0
80
+ attr_reader :systems
81
+
82
+ # @return [Array<String>]
83
+ #
84
+ # @pai private
85
+ # @since 0.1.0
86
+ def system_names
87
+ systems.keys
88
+ end
89
+
90
+ # @return [Array<Class<SmartCore::Initializer::TypeSystem::Interop>>]
91
+ #
92
+ # @api private
93
+ # @since 0.1.0
94
+ def system_interops
95
+ systems.values
96
+ end
97
+
98
+ # @param block [Block]
99
+ # @yield [system_name, system_interop]
100
+ # @yieldparam system_name [String]
101
+ # @yieldparam system_interop [Class<SmartCore::Initializer::TypeSystem::Interop>]
102
+ # @return [Enumerable]
103
+ #
104
+ # @api private
105
+ # @since 0.1.0
106
+ def iterate(&block)
107
+ block_given? ? systems.each_pair(&block) : systems.each_pair
108
+ end
109
+
110
+ # @param system_identifier [String, Symbol]
111
+ # @param interop_klass [Class<SmartCore::Initializer::TypeSystem::Interop>]
112
+ # @return [void]
113
+ #
114
+ # @api private
115
+ # @since 0.1.0
116
+ def apply(system_identifier, interop_klass)
117
+ prevent_incorrect_system_interop!(interop_klass)
118
+ identifier = indifferently_accessible_identifier(system_identifier)
119
+ systems[identifier] = interop_klass
120
+ end
121
+
122
+ # @param system_identifier [String, Symbol]
123
+ # @return [Class<SmartCore::Initializer::TypeSystem::Interop>]
124
+ #
125
+ # @raise [SmartCore::Initializer::UnsupportedTypeSystemError]
126
+ #
127
+ # @api private
128
+ # @since 0.1.0
129
+ def fetch(system_identifier)
130
+ identifier = indifferently_accessible_identifier(system_identifier)
131
+
132
+ begin
133
+ systems.fetch(identifier)
134
+ rescue ::KeyError
135
+ raise(SmartCore::Initializer::UnsupportedTypeSystemError, <<~ERROR_MESSAGE)
136
+ "#{identifier}" type system is not supported.
137
+ ERROR_MESSAGE
138
+ end
139
+ end
140
+
141
+ # @param interop_klass [Class<SMartCore::Initializer::TypeSystem::Interop>]
142
+ # @return [void]
143
+ #
144
+ # @raise [SmartCore::Initializer::IncorrectTypeSystemInteropError]
145
+ #
146
+ # @api private
147
+ # @since 0.1.0
148
+ def prevent_incorrect_system_interop!(interop_klass)
149
+ unless interop_klass.is_a?(Class) && interop_klass < SmartCore::Initializer::TypeSystem::Interop
150
+ raise(
151
+ SmartCore::Initializer::IncorrectTypeSystemInteropError,
152
+ 'Incorrect type system interop class.'
153
+ )
154
+ end
155
+ end
156
+
157
+ # @param system_identifier [String, Symbol]
158
+ # @return [String]
159
+ #
160
+ # @api private
161
+ # @since 0.1.0
162
+ def indifferently_accessible_identifier(system_identifier)
163
+ system_identifier.to_s.clone.tap(&:freeze)
164
+ end
165
+
166
+ # @param block [Block]
167
+ # @return [Any]
168
+ #
169
+ # @api private
170
+ # @since 0.1.0
171
+ def thread_safe(&block)
172
+ @lock.synchronize(&block)
173
+ end
174
+ end