core-state 0.1.8 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc77a1d51f01d64addaf2f51e786ebd3fb34e3b872a93b77784b7b37d4ae215e
4
- data.tar.gz: 6bdf81604e1630610ba65165b555f297f51b2939babadd7758048a40cce60771
3
+ metadata.gz: 477f7141fabe96eb7a23f595f9577e672e371e985dd986120ed3310d302ed95a
4
+ data.tar.gz: 032c9fdaa012fb0f5fed35817d23aa693944005f1254deeb3a87e10e73c130e0
5
5
  SHA512:
6
- metadata.gz: 4ccc3ca6537fb926e2dd91471911299ed279bc6e9d675d1792afe5ec8abdbffeff768c6f4ec938658b262a33e90737ce371b2a59d62f56a2ea5411dafd355c38
7
- data.tar.gz: b10328010f5089ab9d38491b3231301d62ea1e87788d730ae67b1e4fb3ff9523c1829c214c2a7911bbd466845e72d3d073cc7c2649d403549c529b19e0211e35
6
+ metadata.gz: 3e44fde7c140c8268b51ee49d182f4240ab231ec8129fa57e9c11d97a3f915aca5ba376074eeb56ae11942293bda67007efb379501d0ab28c810aea658efe6ad
7
+ data.tar.gz: 931bf990e70cfb5e28975229ed0d8168e6efc324c786fa7d572b75a07a82fd7ee21e747ca7c46e3e166cd8e6b402775470261e82a22a7323b72f1e3412cfec28
data/CHANGELOG.md CHANGED
@@ -1,57 +1,64 @@
1
- ## [v0.1.8](https://github.com/metabahn/corerb/releases/tag/2023-05-07)
1
+ ## [v0.2.0](https://github.com/bryanp/corerb/releases/tag/2023-12-24)
2
+
3
+ *released on 2023-12-24*
4
+
5
+ * `dep` [#143](https://github.com/bryanp/corerb/pull/143) Deprecate `Is::*` and `Refine::*` namespaces ([bryanp](https://github.com/bryanp))
6
+ * `dep` [#135](https://github.com/bryanp/corerb/pull/135) Remove Ruby 2 support ([bryanp](https://github.com/bryanp))
7
+
8
+ ## [v0.1.8](https://github.com/bryanp/corerb/releases/tag/2023-05-07)
2
9
 
3
10
  *released on 2023-05-07*
4
11
 
5
12
  * `fix` [#132](https://github.com/bryanp/corerb/pull/132) Fix state inheritence ([bryanp](https://github.com/bryanp))
6
13
 
7
- ## [v0.1.7](https://github.com/metabahn/corerb/releases/tag/2021-11-23.1)
14
+ ## [v0.1.7](https://github.com/bryanp/corerb/releases/tag/2021-11-23.1)
8
15
 
9
16
  *released on 2021-11-23*
10
17
 
11
- * `chg` [#109](https://github.com/metabahn/corerb/pull/109) Prefer `__send__` to `send` ([bryanp](https://github.com/bryanp))
18
+ * `chg` [#109](https://github.com/bryanp/corerb/pull/109) Prefer `__send__` to `send` ([bryanp](https://github.com/bryanp))
12
19
 
13
- ## [v0.1.6](https://github.com/metabahn/corerb/releases/tag/2021-11-02)
20
+ ## [v0.1.6](https://github.com/bryanp/corerb/releases/tag/2021-11-02)
14
21
 
15
22
  *released on 2021-11-02*
16
23
 
17
- * `chg` [#97](https://github.com/metabahn/corerb/pull/97) Designate internal state with leading and trailing double underscores ([bryanp](https://github.com/bryanp))
24
+ * `chg` [#97](https://github.com/bryanp/corerb/pull/97) Designate internal state with leading and trailing double underscores ([bryanp](https://github.com/bryanp))
18
25
 
19
- ## [v0.1.5](https://github.com/metabahn/corerb/releases/tag/2021-10-22)
26
+ ## [v0.1.5](https://github.com/bryanp/corerb/releases/tag/2021-10-22)
20
27
 
21
28
  *released on 2021-10-22*
22
29
 
23
- * `fix` [#88](https://github.com/metabahn/corerb/pull/88) Fix an issue causing state to be shared between sibling subclasses ([bryanp](https://github.com/bryanp))
30
+ * `fix` [#88](https://github.com/bryanp/corerb/pull/88) Fix an issue causing state to be shared between sibling subclasses ([bryanp](https://github.com/bryanp))
24
31
 
25
- ## [v0.1.4](https://github.com/metabahn/corerb/releases/tag/2021-09-30)
32
+ ## [v0.1.4](https://github.com/bryanp/corerb/releases/tag/2021-09-30)
26
33
 
27
34
  *released on 2021-09-30*
28
35
 
29
- * `fix` [#85](https://github.com/metabahn/corerb/pull/85) Initialize with class-level state when available ([bryanp](https://github.com/bryanp))
36
+ * `fix` [#85](https://github.com/bryanp/corerb/pull/85) Initialize with class-level state when available ([bryanp](https://github.com/bryanp))
30
37
 
31
- ## [v0.1.3](https://github.com/metabahn/corerb/releases/tag/2021-09-28)
38
+ ## [v0.1.3](https://github.com/bryanp/corerb/releases/tag/2021-09-28)
32
39
 
33
40
  *released on 2021-09-28*
34
41
 
35
- * `fix` [#84](https://github.com/metabahn/corerb/pull/84) Define core-local as a dependency of core-state ([bryanp](https://github.com/bryanp))
42
+ * `fix` [#84](https://github.com/bryanp/corerb/pull/84) Define core-local as a dependency of core-state ([bryanp](https://github.com/bryanp))
36
43
 
37
- ## [v0.1.1](https://github.com/metabahn/corerb/releases/tag/2021-07-15)
44
+ ## [v0.1.1](https://github.com/bryanp/corerb/releases/tag/2021-07-15)
38
45
 
39
46
  *released on 2021-07-15*
40
47
 
41
- * `fix` [#62](https://github.com/metabahn/corerb/pull/62) Correctly isolate class-level state on access ([bryanp](https://github.com/bryanp))
42
- * `fix` [#55](https://github.com/metabahn/corerb/pull/55) Correctly forward arguments to super initialize ([bryanp](https://github.com/bryanp))
48
+ * `fix` [#62](https://github.com/bryanp/corerb/pull/62) Correctly isolate class-level state on access ([bryanp](https://github.com/bryanp))
49
+ * `fix` [#55](https://github.com/bryanp/corerb/pull/55) Correctly forward arguments to super initialize ([bryanp](https://github.com/bryanp))
43
50
 
44
- ## [v0.1.0](https://github.com/metabahn/corerb/releases/tag/2021-07-07)
51
+ ## [v0.1.0](https://github.com/bryanp/corerb/releases/tag/2021-07-07)
45
52
 
46
53
  *released on 2021-07-07*
47
54
 
48
- * `fix` [#48](https://github.com/metabahn/corerb/pull/48) Correctly copy defined state when a stateful object is copied ([bryanp](https://github.com/bryanp))
49
- * `chg` [#44](https://github.com/metabahn/corerb/pull/44) Drop Ruby 2.6 support from core-state ([bryanp](https://github.com/bryanp))
55
+ * `fix` [#48](https://github.com/bryanp/corerb/pull/48) Correctly copy defined state when a stateful object is copied ([bryanp](https://github.com/bryanp))
56
+ * `chg` [#44](https://github.com/bryanp/corerb/pull/44) Drop Ruby 2.6 support from core-state ([bryanp](https://github.com/bryanp))
50
57
 
51
- ## [v0.0.0](https://github.com/metabahn/corerb/releases/tag/2021-05-22)
58
+ ## [v0.0.0](https://github.com/bryanp/corerb/releases/tag/2021-05-22)
52
59
 
53
60
  *released on 2021-05-22*
54
61
 
55
- * `add` [#31](https://github.com/metabahn/corerb/pull/31) Initial implementation of core-state ([bryanp](https://github.com/bryanp))
62
+ * `add` [#31](https://github.com/bryanp/corerb/pull/31) Initial implementation of core-state ([bryanp](https://github.com/bryanp))
56
63
 
57
64
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Core
4
4
  module State
5
- VERSION = "0.1.8"
5
+ VERSION = "0.2.0"
6
6
 
7
7
  def self.version
8
8
  VERSION
data/lib/core/state.rb CHANGED
@@ -1,9 +1,233 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "core/copy"
4
+ require "core/extension"
5
+ require "core/local"
6
+
3
7
  module Core
8
+ # [public] Make objects stateful.
9
+ #
4
10
  module State
5
11
  require_relative "state/version"
12
+
13
+ extend Core::Extension
14
+
15
+ using Core::Copy
16
+
17
+ ALLOWED_FLAGS = %i[class instance].freeze
18
+
19
+ applies do
20
+ prepend_defined_state_modules
21
+ end
22
+
23
+ extends :definition do
24
+ # [public] Defines state by name.
25
+ #
26
+ # flags - Changes how the state is defined. Possible values include:
27
+ #
28
+ # * `:class` - Defines state at the class level.
29
+ #
30
+ # * `:instance` - Defines state at the instance level.
31
+ #
32
+ # Dependencies are applied with both the `:class` and `:instance` flags by default.
33
+ #
34
+ # default - The default value for the defined state.
35
+ #
36
+ # private - If `true`, the reader/writer will be defined as private.
37
+ #
38
+ # reader - If `true`, defines a reader for the state.
39
+ #
40
+ # writer - If `true`, defines a reader for the state.
41
+ #
42
+ def state(name, *flags, default: nil, private: false, reader: true, writer: true)
43
+ flags = flags.map(&:to_sym)
44
+ enforce_allowed_flags(flags)
45
+
46
+ state = {
47
+ value: default,
48
+ class: define_class_state?(flags),
49
+ instance: define_instance_state?(flags)
50
+ }
51
+
52
+ method_name = name.to_sym
53
+ ivar_name = "@#{method_name}"
54
+ defined_state[ivar_name] = state
55
+ defined_state_isolations << ivar_name
56
+
57
+ if state[:class]
58
+ instance_variable_set(ivar_name, default)
59
+ end
60
+
61
+ prefix = if private
62
+ "private "
63
+ else
64
+ ""
65
+ end
66
+
67
+ if reader
68
+ if state[:class]
69
+ defined_state_class_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
70
+ #{prefix}def #{method_name}
71
+ unless defined_state_isolations.include?(#{ivar_name.inspect})
72
+ #{ivar_name} = #{ivar_name}.copy
73
+ defined_state_isolations << #{ivar_name.inspect}
74
+ end
75
+
76
+ #{ivar_name}
77
+ end
78
+ CODE
79
+ end
80
+
81
+ if state[:instance]
82
+ defined_state_instance_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
83
+ #{prefix}def #{method_name}
84
+ unless defined_state_isolations.include?(#{ivar_name.inspect})
85
+ #{ivar_name} = #{ivar_name}.copy
86
+ defined_state_isolations << #{ivar_name.inspect}
87
+ end
88
+
89
+ #{ivar_name}
90
+ end
91
+ CODE
92
+ end
93
+ end
94
+
95
+ if writer
96
+ if state[:class]
97
+ defined_state_class_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
98
+ #{prefix}def #{method_name}=(value)
99
+ defined_state[#{ivar_name.inspect}][:value] = value
100
+ #{ivar_name} = value
101
+ end
102
+ CODE
103
+ end
104
+
105
+ if state[:instance]
106
+ defined_state_instance_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
107
+ #{prefix}def #{method_name}=(value)
108
+ #{ivar_name} = value
109
+ end
110
+ CODE
111
+ end
112
+ end
113
+
114
+ if state[:class]
115
+ instance_variable_set(ivar_name, default)
116
+ end
117
+ end
118
+
119
+ def inherited(subclass)
120
+ defined_state.each_pair do |name, state|
121
+ if state[:class]
122
+ subclass.instance_variable_set(name, instance_variable_get(name))
123
+ end
124
+ end
125
+
126
+ subclass.__send__(:prepend_defined_state_modules)
127
+ subclass.instance_variable_set(:@__defined_state__, @__defined_state__.each_with_object({}) { |(key, value), state|
128
+ state[key] = value.dup
129
+ })
130
+
131
+ super
132
+ end
133
+
134
+ private def defined_state
135
+ @__defined_state__ ||= {}
136
+ end
137
+
138
+ private def defined_state_class_module
139
+ @__defined_state_class_module__ ||= Module.new
140
+ end
141
+
142
+ private def defined_state_instance_module
143
+ @__defined_state_instance_module__ ||= Module.new
144
+ end
145
+
146
+ private def prepend_defined_state_modules
147
+ prepend(defined_state_instance_module)
148
+ singleton_class.prepend(defined_state_class_module)
149
+ end
150
+
151
+ private def enforce_allowed_flags(flags)
152
+ flags.each do |flag|
153
+ unless allowed_flag?(flag)
154
+ raise ArgumentError, "Expected flag `#{flag.inspect}' to be one of: #{allowed_flags_string}"
155
+ end
156
+ end
157
+ end
158
+
159
+ private def allowed_flag?(flag)
160
+ ALLOWED_FLAGS.include?(flag)
161
+ end
162
+
163
+ private def allowed_flags_string
164
+ ALLOWED_FLAGS.map { |allowed_flag|
165
+ "`#{allowed_flag.inspect}'"
166
+ }.join(", ")
167
+ end
168
+
169
+ private def define_class_state?(flags)
170
+ flags.empty? || flags.include?(:class)
171
+ end
172
+
173
+ private def define_instance_state?(flags)
174
+ flags.empty? || flags.include?(:instance)
175
+ end
176
+ end
177
+
178
+ extends :implementation, prepend: true do
179
+ def initialize(...)
180
+ self_class = self.class
181
+ self_class.__send__(:defined_state).each_pair do |name, state|
182
+ if state[:instance]
183
+ if state[:class]
184
+ instance_variable_set(name, self_class.instance_variable_get(name))
185
+ else
186
+ instance_variable_set(name, state[:value])
187
+ end
188
+ end
189
+ end
190
+
191
+ super
192
+ end
193
+
194
+ def initialize_copy(...)
195
+ @__defined_state_isolations__ = []
196
+
197
+ super
198
+ end
199
+ end
200
+
201
+ extends :definition, :implementation do
202
+ # [public] Safely mutates state by name, yielding a copy of the current value to the block.
203
+ #
204
+ def mutate_state(name, &block)
205
+ __send__("#{name}=", block.call(__send__(name)))
206
+ end
207
+
208
+ private def defined_state_isolations
209
+ @__defined_state_isolations__ ||= []
210
+ end
211
+ end
212
+
213
+ class << self
214
+ include Core::Local
215
+
216
+ def prevent_recursion(object)
217
+ object_id = object.object_id
218
+ copied_objects[object_id] = true
219
+ yield
220
+ ensure
221
+ copied_objects.delete(object_id)
222
+ end
223
+
224
+ def copying?(object)
225
+ copied_objects[object.object_id]
226
+ end
227
+
228
+ def copied_objects
229
+ localized(:__corerb_copied_objects) || localize(:__corerb_copied_objects, {})
230
+ end
231
+ end
6
232
  end
7
233
  end
8
-
9
- require_relative "../is/stateful"
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: core-state
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan Powell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-08 00:00:00.000000000 Z
11
+ date: 2023-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: core-extension
14
+ name: core-copy
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
@@ -24,22 +24,36 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: core-extension
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.5'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: core-local
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '0.1'
47
+ version: '0.2'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '0.1'
54
+ version: '0.2'
41
55
  description: Easily manage object state.
42
- email: bryan@metabahn.com
56
+ email: bryan@bryanp.org
43
57
  executables: []
44
58
  extensions: []
45
59
  extra_rdoc_files: []
@@ -48,8 +62,7 @@ files:
48
62
  - LICENSE
49
63
  - lib/core/state.rb
50
64
  - lib/core/state/version.rb
51
- - lib/is/stateful.rb
52
- homepage: https://github.com/metabahn/corerb/
65
+ homepage: https://github.com/bryanp/corerb/
53
66
  licenses:
54
67
  - MPL-2.0
55
68
  metadata: {}
@@ -61,14 +74,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
61
74
  requirements:
62
75
  - - ">="
63
76
  - !ruby/object:Gem::Version
64
- version: '2.7'
77
+ version: '3.0'
65
78
  required_rubygems_version: !ruby/object:Gem::Requirement
66
79
  requirements:
67
80
  - - ">="
68
81
  - !ruby/object:Gem::Version
69
82
  version: '0'
70
83
  requirements: []
71
- rubygems_version: 3.4.12
84
+ rubygems_version: 3.5.1
72
85
  signing_key:
73
86
  specification_version: 4
74
87
  summary: Easily manage object state.
data/lib/is/stateful.rb DELETED
@@ -1,295 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "core/extension"
4
- require "core/local"
5
-
6
- module Is
7
- # [public] Makes objects stateful.
8
- #
9
- module Stateful
10
- # Adding core-copy as a dependency creates a recursive dependency, so just bundle it.
11
- #
12
- module Copy
13
- DEFAULT = ::Object.new
14
-
15
- refine ::Object do
16
- if RbConfig::CONFIG["RUBY_PROGRAM_VERSION"] < "3"
17
- def copy(freeze: DEFAULT)
18
- should_freeze = resolve_freeze_argument(freeze)
19
-
20
- value = clone(freeze: should_freeze)
21
- value.freeze if should_freeze
22
- value
23
- end
24
- else
25
- def copy(freeze: DEFAULT)
26
- clone(freeze: resolve_freeze_argument(freeze))
27
- end
28
- end
29
-
30
- private def resolve_freeze_argument(value)
31
- case value
32
- when DEFAULT
33
- frozen?
34
- else
35
- !!value
36
- end
37
- end
38
- end
39
-
40
- refine Array do
41
- def copy(freeze: DEFAULT)
42
- unless Stateful.copying?(self)
43
- Stateful.prevent_recursion(self) do
44
- array = map { |value|
45
- value.copy(freeze: freeze)
46
- }
47
-
48
- array.freeze if resolve_freeze_argument(freeze)
49
-
50
- array
51
- end
52
- end
53
- end
54
- end
55
-
56
- refine Hash do
57
- def copy(freeze: DEFAULT)
58
- unless Stateful.copying?(self)
59
- Stateful.prevent_recursion(self) do
60
- hash = {}
61
-
62
- each_pair do |key, value|
63
- hash[key.copy(freeze: freeze)] = value.copy(freeze: freeze)
64
- end
65
-
66
- hash.freeze if resolve_freeze_argument(freeze)
67
-
68
- hash
69
- end
70
- end
71
- end
72
- end
73
- end
74
-
75
- extend Is::Extension
76
-
77
- using Copy
78
-
79
- ALLOWED_FLAGS = %i[class instance].freeze
80
-
81
- applies do
82
- prepend_defined_state_modules
83
- end
84
-
85
- extends :definition do
86
- # [public] Defines state by name.
87
- #
88
- # flags - Changes how the state is defined. Possible values include:
89
- #
90
- # * `:class` - Defines state at the class level.
91
- #
92
- # * `:instance` - Defines state at the instance level.
93
- #
94
- # Dependencies are applied with both the `:class` and `:instance` flags by default.
95
- #
96
- # default - The default value for the defined state.
97
- #
98
- # private - If `true`, the reader/writer will be defined as private.
99
- #
100
- # reader - If `true`, defines a reader for the state.
101
- #
102
- # writer - If `true`, defines a reader for the state.
103
- #
104
- def state(name, *flags, default: nil, private: false, reader: true, writer: true)
105
- flags = flags.map(&:to_sym)
106
- enforce_allowed_flags(flags)
107
-
108
- state = {
109
- value: default,
110
- class: define_class_state?(flags),
111
- instance: define_instance_state?(flags)
112
- }
113
-
114
- method_name = name.to_sym
115
- ivar_name = "@#{method_name}"
116
- defined_state[ivar_name] = state
117
- defined_state_isolations << ivar_name
118
-
119
- if state[:class]
120
- instance_variable_set(ivar_name, default)
121
- end
122
-
123
- prefix = if private
124
- "private "
125
- else
126
- ""
127
- end
128
-
129
- if reader
130
- if state[:class]
131
- defined_state_class_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
132
- #{prefix}def #{method_name}
133
- unless defined_state_isolations.include?(#{ivar_name.inspect})
134
- #{ivar_name} = #{ivar_name}.copy
135
- defined_state_isolations << #{ivar_name.inspect}
136
- end
137
-
138
- #{ivar_name}
139
- end
140
- CODE
141
- end
142
-
143
- if state[:instance]
144
- defined_state_instance_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
145
- #{prefix}def #{method_name}
146
- unless defined_state_isolations.include?(#{ivar_name.inspect})
147
- #{ivar_name} = #{ivar_name}.copy
148
- defined_state_isolations << #{ivar_name.inspect}
149
- end
150
-
151
- #{ivar_name}
152
- end
153
- CODE
154
- end
155
- end
156
-
157
- if writer
158
- if state[:class]
159
- defined_state_class_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
160
- #{prefix}def #{method_name}=(value)
161
- defined_state[#{ivar_name.inspect}][:value] = value
162
- #{ivar_name} = value
163
- end
164
- CODE
165
- end
166
-
167
- if state[:instance]
168
- defined_state_instance_module.module_eval <<~CODE, __FILE__, __LINE__ + 1
169
- #{prefix}def #{method_name}=(value)
170
- #{ivar_name} = value
171
- end
172
- CODE
173
- end
174
- end
175
-
176
- if state[:class]
177
- instance_variable_set(ivar_name, default)
178
- end
179
- end
180
-
181
- def inherited(subclass)
182
- defined_state.each_pair do |name, state|
183
- if state[:class]
184
- subclass.instance_variable_set(name, instance_variable_get(name))
185
- end
186
- end
187
-
188
- subclass.__send__(:prepend_defined_state_modules)
189
- subclass.instance_variable_set(:@__defined_state__, @__defined_state__.each_with_object({}) { |(key, value), state|
190
- state[key] = value.dup
191
- })
192
-
193
- super
194
- end
195
-
196
- private def defined_state
197
- @__defined_state__ ||= {}
198
- end
199
-
200
- private def defined_state_class_module
201
- @__defined_state_class_module__ ||= Module.new
202
- end
203
-
204
- private def defined_state_instance_module
205
- @__defined_state_instance_module__ ||= Module.new
206
- end
207
-
208
- private def prepend_defined_state_modules
209
- prepend(defined_state_instance_module)
210
- singleton_class.prepend(defined_state_class_module)
211
- end
212
-
213
- private def enforce_allowed_flags(flags)
214
- flags.each do |flag|
215
- unless allowed_flag?(flag)
216
- raise ArgumentError, "Expected flag `#{flag.inspect}' to be one of: #{allowed_flags_string}"
217
- end
218
- end
219
- end
220
-
221
- private def allowed_flag?(flag)
222
- ALLOWED_FLAGS.include?(flag)
223
- end
224
-
225
- private def allowed_flags_string
226
- ALLOWED_FLAGS.map { |allowed_flag|
227
- "`#{allowed_flag.inspect}'"
228
- }.join(", ")
229
- end
230
-
231
- private def define_class_state?(flags)
232
- flags.empty? || flags.include?(:class)
233
- end
234
-
235
- private def define_instance_state?(flags)
236
- flags.empty? || flags.include?(:instance)
237
- end
238
- end
239
-
240
- extends :implementation, prepend: true do
241
- def initialize(...)
242
- self_class = self.class
243
- self_class.__send__(:defined_state).each_pair do |name, state|
244
- if state[:instance]
245
- if state[:class]
246
- instance_variable_set(name, self_class.instance_variable_get(name))
247
- else
248
- instance_variable_set(name, state[:value])
249
- end
250
- end
251
- end
252
-
253
- super
254
- end
255
-
256
- def initialize_copy(...)
257
- @__defined_state_isolations__ = []
258
-
259
- super
260
- end
261
- end
262
-
263
- extends :definition, :implementation do
264
- # [public] Safely mutates state by name, yielding a copy of the current value to the block.
265
- #
266
- def mutate_state(name, &block)
267
- __send__("#{name}=", block.call(__send__(name)))
268
- end
269
-
270
- private def defined_state_isolations
271
- @__defined_state_isolations__ ||= []
272
- end
273
- end
274
-
275
- class << self
276
- include Is::Localized
277
-
278
- def prevent_recursion(object)
279
- object_id = object.object_id
280
- copied_objects[object_id] = true
281
- yield
282
- ensure
283
- copied_objects.delete(object_id)
284
- end
285
-
286
- def copying?(object)
287
- copied_objects[object.object_id]
288
- end
289
-
290
- def copied_objects
291
- localized(:__corerb_copied_objects) || localize(:__corerb_copied_objects, {})
292
- end
293
- end
294
- end
295
- end