smart_initializer 0.1.0.alpha2 → 0.3.0

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.
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