foobara 0.2.3 → 0.2.5
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/CHANGELOG.md +14 -0
- data/README.md +96 -3
- data/projects/builtin_types/src/builtin_types.rb +3 -3
- data/projects/callback/src/registry/chained_multiple_action.rb +1 -1
- data/projects/callback/src/registry/conditioned.rb +1 -1
- data/projects/callback/src/registry/multiple_action.rb +1 -1
- data/projects/command_connectors/src/command_connector.rb +20 -3
- data/projects/command_connectors/src/serializers/errors_serializer.rb +1 -1
- data/projects/command_connectors/src/serializers/success_serializer.rb +1 -1
- data/projects/common/src/runtime_error.rb +1 -1
- data/projects/foobara/lib/foobara/all.rb +0 -1
- data/projects/foobara/src/foobara.rb +3 -0
- data/projects/namespace/src/namespace.rb +1 -1
- data/projects/persistence/src/entity_base/transaction/concerns/state_transitions.rb +1 -0
- data/projects/persistence/src/entity_base/transaction_table/concerns/record_tracking.rb +6 -1
- data/projects/persistence/src/entity_base/transaction_table.rb +1 -2
- data/projects/state_machine/src/state_machine.rb +4 -4
- data/projects/type_declarations/src/desugarizer.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/array_desugarizer.rb +2 -2
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/to_type_transformer.rb +2 -2
- data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration/to_type_transformer.rb +1 -4
- data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/dsl_desugarizer.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/element_type_declarations_desugarizer.rb +3 -3
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb +2 -2
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/to_type_transformer.rb +2 -2
- data/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +2 -2
- data/projects/type_declarations/src/handlers/extend_registered_type_declaration.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/array_desugarizer.rb +2 -2
- data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb +2 -2
- data/projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/handlers/registered_type_declaration.rb +1 -1
- data/projects/type_declarations/src/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/type_declaration_handler.rb +1 -1
- data/projects/type_declarations/src/type_declarations.rb +2 -2
- data/projects/types/src/type.rb +5 -0
- data/projects/value/lib/foobara/value.rb +1 -1
- data/projects/value/src/processor/casting.rb +1 -1
- data/projects/value/src/processor/pipeline.rb +1 -1
- data/projects/value/src/processor/selection.rb +2 -2
- data/projects/value/src/transformer.rb +1 -1
- data/version.rb +1 -1
- metadata +3 -6
- data/projects/weak_object_hash/lib/foobara/weak_object_hash.rb +0 -3
- data/projects/weak_object_hash/src/weak_object_hash.rb +0 -225
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e05617e8bea9b7a9ce861246a1a5c664ad3b525630dd1cd7362b80b4d6d809ea
|
|
4
|
+
data.tar.gz: 10bd954f202f83aef9a20f0dec859212766a81e9682f6526ece70e3cd457b6a7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26fa0c9be295542f963963ac892405a315d5b6f004fadcdf23336bab09ad973cdae843186134c20c1e173be816506c37f2ad34e825c6d84f2c2ef42845262011
|
|
7
|
+
data.tar.gz: efefbce7b11751d240a09ca34bc5e20a182c60daa00cc79399aceee55c74e33b8b1135aca706abd2a8d3e80c39414477a19d3fee05cc28bdd0e13b063d6fda77
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [0.2.5] - 2025-10-27
|
|
2
|
+
|
|
3
|
+
- Do not allow commands to be connected multiple times via symbol/string
|
|
4
|
+
- Add CommandConnector#all_exposed_command_names
|
|
5
|
+
- pry is again required by default in development/test mode but can be skipped with SKIP_PRY env var
|
|
6
|
+
|
|
7
|
+
# [0.2.4] -2025-10-26
|
|
8
|
+
|
|
9
|
+
- Remove all uses of .require_project_file and deprecate it
|
|
10
|
+
- Replace custom WeakObjectHash with similar standard library ObjectSpace::WeakMap
|
|
11
|
+
- Call #committed only after whole transaction has been fully committed
|
|
12
|
+
- Add/fire a :persisted event for callbacks when an entity receives a primary key and is committed
|
|
13
|
+
- Add Type#add_caster
|
|
14
|
+
|
|
1
15
|
# [0.2.3] - 2025-10-22
|
|
2
16
|
|
|
3
17
|
- Fix Persistence.register_base bug
|
data/README.md
CHANGED
|
@@ -2100,11 +2100,11 @@ TODO: give some code examples
|
|
|
2100
2100
|
# Additional learning materials/Documentation
|
|
2101
2101
|
|
|
2102
2102
|
* Overview and code demo videos:
|
|
2103
|
-
* https://foobara.
|
|
2103
|
+
* https://foobara.org/videos
|
|
2104
2104
|
* https://www.youtube.com/@FoobaraFlix
|
|
2105
2105
|
* YARD Docs
|
|
2106
2106
|
* All docs combined: https://docs.foobara.com/all/
|
|
2107
|
-
* Per-repository docs: https://foobara.
|
|
2107
|
+
* Per-repository docs: https://foobara.org/docs
|
|
2108
2108
|
|
|
2109
2109
|
# Help
|
|
2110
2110
|
|
|
@@ -2124,10 +2124,103 @@ the build will fail if test coverage is below 100%.
|
|
|
2124
2124
|
|
|
2125
2125
|
You should be able to do the typical stuff:
|
|
2126
2126
|
|
|
2127
|
+
### 1. Cloning repository:
|
|
2128
|
+
Fork the repository and run this(Only for SSH):
|
|
2129
|
+
|
|
2130
|
+
```
|
|
2131
|
+
git clone git@github.com:${your_github_username}/foobara.git
|
|
2132
|
+
```
|
|
2133
|
+
|
|
2134
|
+
Create a new branch for you to push into
|
|
2135
|
+
|
|
2136
|
+
```
|
|
2137
|
+
git checkout -b <branch-name>
|
|
2138
|
+
```
|
|
2139
|
+
|
|
2140
|
+
Now navigate to project directory
|
|
2141
|
+
|
|
2127
2142
|
```
|
|
2128
|
-
git clone git@github.com:foobara/foobara
|
|
2129
2143
|
cd foobara
|
|
2144
|
+
```
|
|
2145
|
+
|
|
2146
|
+
### 2. Installing mise (LINUX/WSL)
|
|
2147
|
+
Mise is a package manager and helps with managing different versions of ruby. It allows you to switch different versions of ruby.
|
|
2148
|
+
|
|
2149
|
+
The installation docs might be updated by mise so here's the reference to that: [Installation Docs](https://mise.jdx.dev/installing-mise.html)
|
|
2150
|
+
|
|
2151
|
+
***If you already installed by following mise's docs then, you can skip this section***
|
|
2152
|
+
|
|
2153
|
+
Else to setup mise follow the script given below:
|
|
2154
|
+
|
|
2155
|
+
```
|
|
2156
|
+
sudo apt update -y && sudo apt install -y gpg wget \
|
|
2157
|
+
build-essential \
|
|
2158
|
+
libssl-dev zlib1g-dev libreadline-dev libyaml-dev libxml2-dev \
|
|
2159
|
+
libxslt1-dev libffi-dev libgdbm-dev autoconf bison
|
|
2160
|
+
wget -qO - https://mise.jdx.dev/gpg-key.pub | gpg --dearmor | sudo tee /etc/apt/keyrings/mise-archive-keyring.gpg 1> /dev/null
|
|
2161
|
+
echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.gpg arch=amd64] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list
|
|
2162
|
+
sudo apt update
|
|
2163
|
+
sudo apt install -y mise
|
|
2164
|
+
```
|
|
2165
|
+
|
|
2166
|
+
Verify if it's installed or not by running:
|
|
2167
|
+
|
|
2168
|
+
```
|
|
2169
|
+
mise -v
|
|
2170
|
+
```
|
|
2171
|
+
|
|
2172
|
+
It should print out an ascii-art saying "mise-en-place"
|
|
2173
|
+
|
|
2174
|
+
### 3. Install required ruby version
|
|
2175
|
+
In this project, currently we require ruby version >=3.4 so we can install it manually using the command below
|
|
2176
|
+
|
|
2177
|
+
```
|
|
2178
|
+
mise use -g ruby@3.4
|
|
2179
|
+
```
|
|
2180
|
+
|
|
2181
|
+
In case, you want to automatically activate the ruby version whenever you navigate to the directory containing .ruby-version file
|
|
2182
|
+
|
|
2183
|
+
This helps a lot when you have lot of ruby projects with different versions and don't want to switch ruby versions each time manually
|
|
2184
|
+
|
|
2185
|
+
```
|
|
2186
|
+
mise settings add idiomatic_version_file_enable_tools ruby
|
|
2187
|
+
```
|
|
2188
|
+
|
|
2189
|
+
### 4. Activating mise
|
|
2190
|
+
We can activate mise so that it will update the environment variables such that we will use the correct version of ruby.
|
|
2191
|
+
|
|
2192
|
+
```
|
|
2193
|
+
echo 'eval "$(mise activate bash)"' >> ~/.bashrc
|
|
2194
|
+
```
|
|
2195
|
+
|
|
2196
|
+
Restart the terminal
|
|
2197
|
+
|
|
2198
|
+
Now environment variables are updated and you can verify it by running:
|
|
2199
|
+
|
|
2200
|
+
```
|
|
2201
|
+
ruby -v
|
|
2202
|
+
```
|
|
2203
|
+
|
|
2204
|
+
It will print out the ruby version, which is mentioned in .ruby-version file
|
|
2205
|
+
|
|
2206
|
+
You can list out your mise tools and its versions by running:
|
|
2207
|
+
|
|
2208
|
+
```
|
|
2209
|
+
mise list
|
|
2210
|
+
```
|
|
2211
|
+
|
|
2212
|
+
### 5. Running tests
|
|
2213
|
+
Before running test-suite, we need to install all the dependencies
|
|
2214
|
+
|
|
2215
|
+
Run this to install all the dependencies:
|
|
2216
|
+
|
|
2217
|
+
```
|
|
2130
2218
|
bundle
|
|
2219
|
+
```
|
|
2220
|
+
|
|
2221
|
+
Run the tests now:
|
|
2222
|
+
|
|
2223
|
+
```
|
|
2131
2224
|
rake
|
|
2132
2225
|
```
|
|
2133
2226
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Foobara
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
require_relative "duck"
|
|
3
|
+
require_relative "atomic_duck"
|
|
4
|
+
require_relative "duckture"
|
|
5
5
|
|
|
6
6
|
module BuiltinTypes
|
|
7
7
|
class << self
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Foobara
|
|
2
2
|
class CommandConnector
|
|
3
3
|
class UnexpectedSensitiveTypeInManifestError < StandardError; end
|
|
4
|
+
class AlreadyConnectedError < StandardError; end
|
|
4
5
|
|
|
5
6
|
include Concerns::Desugarizers
|
|
6
7
|
|
|
@@ -116,9 +117,10 @@ module Foobara
|
|
|
116
117
|
end
|
|
117
118
|
end
|
|
118
119
|
|
|
119
|
-
attr_accessor :command_registry, :authenticator, :capture_unknown_error
|
|
120
|
+
attr_accessor :command_registry, :authenticator, :capture_unknown_error, :name
|
|
120
121
|
|
|
121
|
-
def initialize(
|
|
122
|
+
def initialize(name: nil,
|
|
123
|
+
authenticator: nil,
|
|
122
124
|
capture_unknown_error: nil,
|
|
123
125
|
default_serializers: nil,
|
|
124
126
|
default_pre_commit_transformers: nil)
|
|
@@ -127,6 +129,7 @@ module Foobara
|
|
|
127
129
|
self.authenticator = authenticator
|
|
128
130
|
self.command_registry = CommandRegistry.new(authenticator:)
|
|
129
131
|
self.capture_unknown_error = capture_unknown_error
|
|
132
|
+
self.name = name
|
|
130
133
|
|
|
131
134
|
Util.array(default_serializers).each do |serializer|
|
|
132
135
|
add_default_serializer(serializer)
|
|
@@ -303,7 +306,15 @@ module Foobara
|
|
|
303
306
|
end
|
|
304
307
|
|
|
305
308
|
def connect_delayed(registerable_name, *args, **opts)
|
|
306
|
-
|
|
309
|
+
key = registerable_name.to_s
|
|
310
|
+
|
|
311
|
+
if delayed_connections.key?(key)
|
|
312
|
+
# :nocov:
|
|
313
|
+
raise AlreadyConnectedError, "Already connected #{key}"
|
|
314
|
+
# :nocov:
|
|
315
|
+
else
|
|
316
|
+
delayed_connections[key] = { args:, opts: }
|
|
317
|
+
end
|
|
307
318
|
end
|
|
308
319
|
|
|
309
320
|
def delayed_connections
|
|
@@ -311,6 +322,8 @@ module Foobara
|
|
|
311
322
|
end
|
|
312
323
|
|
|
313
324
|
def process_delayed_connections
|
|
325
|
+
return if delayed_connections.empty?
|
|
326
|
+
|
|
314
327
|
delayed_connections.each_pair do |registerable_name, arg_hash|
|
|
315
328
|
args = arg_hash[:args]
|
|
316
329
|
opts = arg_hash[:opts]
|
|
@@ -663,6 +676,10 @@ module Foobara
|
|
|
663
676
|
command_registry.foobara_all_command(mode: Namespace::LookupMode::ABSOLUTE_SINGLE_NAMESPACE)
|
|
664
677
|
end
|
|
665
678
|
|
|
679
|
+
def all_exposed_command_names
|
|
680
|
+
all_exposed_commands.map(&:full_command_name)
|
|
681
|
+
end
|
|
682
|
+
|
|
666
683
|
def all_exposed_type_names
|
|
667
684
|
# TODO: cache this or better yet cache #foobara_manifest
|
|
668
685
|
foobara_manifest[:type].keys.sort.map(&:to_s)
|
|
@@ -5,7 +5,10 @@ module Foobara
|
|
|
5
5
|
|
|
6
6
|
class << self
|
|
7
7
|
def require_project_file(project, path)
|
|
8
|
+
# :nocov:
|
|
9
|
+
warn "DEPRECATION WARNING: require_project_file is deprecated. Use require_relative instead."
|
|
8
10
|
require_relative("../../#{project}/src/#{path}")
|
|
11
|
+
# :nocov:
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
attr_accessor :is_installed
|
|
@@ -86,6 +86,10 @@ module Foobara
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def committed
|
|
89
|
+
marked_persisted.each do |record|
|
|
90
|
+
record.fire(:persisted)
|
|
91
|
+
end
|
|
92
|
+
|
|
89
93
|
closed
|
|
90
94
|
end
|
|
91
95
|
|
|
@@ -113,7 +117,8 @@ module Foobara
|
|
|
113
117
|
:updated,
|
|
114
118
|
:hard_deleted,
|
|
115
119
|
:created,
|
|
116
|
-
:loading
|
|
120
|
+
:loading,
|
|
121
|
+
:persisted
|
|
117
122
|
]
|
|
118
123
|
|
|
119
124
|
interesting_record_states.each do |state|
|
|
@@ -656,6 +656,7 @@ module Foobara
|
|
|
656
656
|
record.is_persisted = record.is_loaded = true
|
|
657
657
|
record.is_created = false
|
|
658
658
|
record.save_persisted_attributes
|
|
659
|
+
mark_persisted(record)
|
|
659
660
|
end
|
|
660
661
|
|
|
661
662
|
marked_created.clear
|
|
@@ -695,8 +696,6 @@ module Foobara
|
|
|
695
696
|
validate!
|
|
696
697
|
flush_created!
|
|
697
698
|
flush_updated_and_hard_deleted!
|
|
698
|
-
|
|
699
|
-
committed
|
|
700
699
|
end
|
|
701
700
|
|
|
702
701
|
def revert!
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module Foobara
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
require_relative "sugar"
|
|
3
|
+
require_relative "callbacks"
|
|
4
|
+
require_relative "validations"
|
|
5
|
+
require_relative "transitions"
|
|
6
6
|
|
|
7
7
|
# TODO: allow quick creation of a statemachine either through better options to #initialize or a
|
|
8
8
|
# .for method.
|
data/projects/type_declarations/src/handlers/extend_array_type_declaration/array_desugarizer.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../../desugarizer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
data/projects/type_declarations/src/handlers/extend_array_type_declaration/to_type_transformer.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../registered_type_declaration/to_type_transformer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
require_relative "../../desugarizer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
|
+
require_relative "hash_desugarizer"
|
|
4
4
|
|
|
5
5
|
module Foobara
|
|
6
6
|
module TypeDeclarations
|
data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/hash_desugarizer.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../../desugarizer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../registered_type_declaration/to_type_transformer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../registered_type_declaration/to_type_transformer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/array_desugarizer.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../../desugarizer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative "../registered_type_declaration/to_type_transformer"
|
|
2
|
+
require_relative "../extend_associative_array_type_declaration"
|
|
3
3
|
|
|
4
4
|
module Foobara
|
|
5
5
|
module TypeDeclarations
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require "inheritable_thread_vars"
|
|
2
2
|
|
|
3
3
|
module Foobara
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
require_relative "type_builder"
|
|
5
|
+
require_relative "error_extension"
|
|
6
6
|
|
|
7
7
|
module TypeDeclarations
|
|
8
8
|
module Mode
|
data/projects/types/src/type.rb
CHANGED
data/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foobara
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Miles Georgi
|
|
@@ -491,16 +491,14 @@ files:
|
|
|
491
491
|
- projects/value/src/processor/selection.rb
|
|
492
492
|
- projects/value/src/transformer.rb
|
|
493
493
|
- projects/value/src/validator.rb
|
|
494
|
-
- projects/weak_object_hash/lib/foobara/weak_object_hash.rb
|
|
495
|
-
- projects/weak_object_hash/src/weak_object_hash.rb
|
|
496
494
|
- projects/weak_object_set/lib/foobara/weak_object_set.rb
|
|
497
495
|
- projects/weak_object_set/src/weak_object_set.rb
|
|
498
496
|
- version.rb
|
|
499
|
-
homepage: https://foobara.
|
|
497
|
+
homepage: https://foobara.org
|
|
500
498
|
licenses:
|
|
501
499
|
- MPL-2.0
|
|
502
500
|
metadata:
|
|
503
|
-
homepage_uri: https://foobara.
|
|
501
|
+
homepage_uri: https://foobara.org
|
|
504
502
|
source_code_uri: https://github.com/foobara/foobara
|
|
505
503
|
changelog_uri: https://github.com/foobara/foobara/blob/main/CHANGELOG.md
|
|
506
504
|
rubygems_mfa_required: 'true'
|
|
@@ -531,7 +529,6 @@ require_paths:
|
|
|
531
529
|
- "./projects/type_declarations/lib"
|
|
532
530
|
- "./projects/types/lib"
|
|
533
531
|
- "./projects/value/lib"
|
|
534
|
-
- "./projects/weak_object_hash/lib"
|
|
535
532
|
- "./projects/weak_object_set/lib"
|
|
536
533
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
537
534
|
requirements:
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
require "monitor"
|
|
2
|
-
|
|
3
|
-
module Foobara
|
|
4
|
-
# TODO: a possible optimization: have a certain number of records before the Weakref approach kicks in
|
|
5
|
-
# that way we don't just immediately clear out useful information without any actual memory burden
|
|
6
|
-
class WeakObjectHash
|
|
7
|
-
class ClosedError < StandardError; end
|
|
8
|
-
|
|
9
|
-
def initialize(skip_finalizer: false)
|
|
10
|
-
if skip_finalizer
|
|
11
|
-
self.skip_finalizer = true
|
|
12
|
-
end
|
|
13
|
-
self.monitor = Monitor.new
|
|
14
|
-
self.object_ids_to_weak_refs_and_values = {}
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def []=(object, value)
|
|
18
|
-
object_id = object.object_id
|
|
19
|
-
weak_ref = WeakRef.new(object)
|
|
20
|
-
|
|
21
|
-
if closed?
|
|
22
|
-
raise ClosedError, "Cannot add objects to a closed WeakObjectHash"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
monitor.synchronize do
|
|
26
|
-
delete(object)
|
|
27
|
-
|
|
28
|
-
object_ids_to_weak_refs_and_values[object_id] = [weak_ref, value]
|
|
29
|
-
|
|
30
|
-
unless skip_finalizer?
|
|
31
|
-
ObjectSpace.define_finalizer(object, finalizer_proc)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
value
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def [](object)
|
|
39
|
-
object_id = object.object_id
|
|
40
|
-
|
|
41
|
-
if closed?
|
|
42
|
-
raise ClosedError, "Cannot retrieve objects from a closed WeakObjectHash"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
monitor.synchronize do
|
|
46
|
-
pair = object_ids_to_weak_refs_and_values[object_id]
|
|
47
|
-
|
|
48
|
-
return nil unless pair
|
|
49
|
-
|
|
50
|
-
weak_ref, value = pair
|
|
51
|
-
|
|
52
|
-
if weak_ref.weakref_alive?
|
|
53
|
-
if skip_finalizer?
|
|
54
|
-
if weak_ref.__getobj__ == object
|
|
55
|
-
value
|
|
56
|
-
else
|
|
57
|
-
# :nocov:
|
|
58
|
-
object_ids_to_weak_refs_and_values.delete(object_id)
|
|
59
|
-
nil
|
|
60
|
-
# :nocov:
|
|
61
|
-
end
|
|
62
|
-
else
|
|
63
|
-
value
|
|
64
|
-
end
|
|
65
|
-
else
|
|
66
|
-
# Seems unreachable... if it's been garbage collected how could we have a reference to the object
|
|
67
|
-
# to pass it in?
|
|
68
|
-
# :nocov:
|
|
69
|
-
object_ids_to_weak_refs_and_values.delete(object_id)
|
|
70
|
-
nil
|
|
71
|
-
# :nocov:
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def delete(object)
|
|
77
|
-
object_id = object.object_id
|
|
78
|
-
|
|
79
|
-
monitor.synchronize do
|
|
80
|
-
pair = object_ids_to_weak_refs_and_values.delete(object_id)
|
|
81
|
-
|
|
82
|
-
return nil unless pair
|
|
83
|
-
|
|
84
|
-
weak_ref, value = pair
|
|
85
|
-
|
|
86
|
-
if weak_ref.weakref_alive?
|
|
87
|
-
|
|
88
|
-
if skip_finalizer?
|
|
89
|
-
if weak_ref.__getobj__ == object
|
|
90
|
-
value
|
|
91
|
-
end
|
|
92
|
-
else
|
|
93
|
-
# Hmmm, there's seemingly no safe way to remove the finalizer for the previous entry
|
|
94
|
-
# if it exists. This is because we can only remove all finalizers on object. Not only
|
|
95
|
-
# the ones we've created.
|
|
96
|
-
# We will just do this anyway with that caveat and maybe make this configuratble in the future.
|
|
97
|
-
unless skip_finalizer?
|
|
98
|
-
ObjectSpace.undefine_finalizer(object)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
value
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def each_pair
|
|
108
|
-
monitor.synchronize do
|
|
109
|
-
object_ids_to_weak_refs_and_values.each_pair do |object_id, pair|
|
|
110
|
-
weak_ref, value = pair
|
|
111
|
-
|
|
112
|
-
if weak_ref.weakref_alive?
|
|
113
|
-
yield weak_ref.__getobj__, value
|
|
114
|
-
else
|
|
115
|
-
object_ids_to_weak_refs_and_values.delete(object_id)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
self
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def values
|
|
124
|
-
values = []
|
|
125
|
-
|
|
126
|
-
monitor.synchronize do
|
|
127
|
-
each_pair do |_key, value|
|
|
128
|
-
values << value
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
values
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def keys
|
|
136
|
-
keys = []
|
|
137
|
-
|
|
138
|
-
monitor.synchronize do
|
|
139
|
-
each_pair do |key, _value|
|
|
140
|
-
keys << key
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
keys
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def size
|
|
148
|
-
size = 0
|
|
149
|
-
to_delete = nil
|
|
150
|
-
|
|
151
|
-
monitor.synchronize do
|
|
152
|
-
object_ids_to_weak_refs_and_values.each_pair do |object_id, pair|
|
|
153
|
-
weak_ref = pair.first
|
|
154
|
-
|
|
155
|
-
if weak_ref.weakref_alive?
|
|
156
|
-
size += 1
|
|
157
|
-
else
|
|
158
|
-
to_delete ||= []
|
|
159
|
-
to_delete << object_id
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
to_delete&.each do |object_id|
|
|
164
|
-
object_ids_to_weak_refs_and_values.delete(object_id)
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
size
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def empty?
|
|
172
|
-
size == 0
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def close!
|
|
176
|
-
if closed?
|
|
177
|
-
raise ClosedError, "Already closed"
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
monitor.synchronize do
|
|
181
|
-
self.closed = true
|
|
182
|
-
clear
|
|
183
|
-
@finalizer_proc = nil
|
|
184
|
-
self.object_ids_to_weak_refs_and_values = nil
|
|
185
|
-
self.monitor = nil
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def clear
|
|
190
|
-
monitor.synchronize do
|
|
191
|
-
unless skip_finalizer?
|
|
192
|
-
object_ids_to_weak_refs_and_values.each_value do |pair|
|
|
193
|
-
weak_ref = pair.first
|
|
194
|
-
|
|
195
|
-
if weak_ref.weakref_alive?
|
|
196
|
-
ObjectSpace.undefine_finalizer(weak_ref.__getobj__)
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
object_ids_to_weak_refs_and_values.clear
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def closed?
|
|
206
|
-
closed
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def skip_finalizer?
|
|
210
|
-
@skip_finalizer
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
private
|
|
214
|
-
|
|
215
|
-
attr_accessor :object_ids_to_weak_refs_and_values, :monitor, :closed, :skip_finalizer
|
|
216
|
-
|
|
217
|
-
def finalizer_proc
|
|
218
|
-
@finalizer_proc ||= ->(object_id) do
|
|
219
|
-
unless closed?
|
|
220
|
-
object_ids_to_weak_refs_and_values.delete(object_id)
|
|
221
|
-
end
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
end
|