Thread-local state bag for implicit context propagation
gem install philiprehberger-state_bagThread-local state bag for implicit context propagation
Add to your Gemfile:
gem "philiprehberger-state_bag"
Or install directly:
gem install philiprehberger-state_bag
require "philiprehberger/state_bag"
Philiprehberger::StateBag.set(:user_id, 42)
Philiprehberger::StateBag.get(:user_id)
# => 42
Philiprehberger::StateBag.get(:missing, 'fallback')
# => "fallback"
Philiprehberger::StateBag.set(:locale, 'en')
Philiprehberger::StateBag.with(locale: 'de') do
Philiprehberger::StateBag.get(:locale)
# => "de"
end
Philiprehberger::StateBag.get(:locale)
# => "en"
require "philiprehberger/state_bag"
Philiprehberger::StateBag.set(:user, "Alice")
Philiprehberger::StateBag.fetch(:user) # => "Alice"
Philiprehberger::StateBag.fetch(:missing, "default") # => "default"
Philiprehberger::StateBag.fetch(:missing) { |k| "no #{k}" } # => "no missing"
Philiprehberger::StateBag.delete(:user) # => "Alice"
Philiprehberger::StateBag.key?(:user) # => false
Philiprehberger::StateBag.set(:a, 1)
Philiprehberger::StateBag.key?(:a) # => true
Philiprehberger::StateBag.size # => 1
Philiprehberger::StateBag.empty? # => false
Philiprehberger::StateBag.keys # => [:a]
Philiprehberger::StateBag.values # => [1]
Philiprehberger::StateBag.to_h # => {:a=>1}
Philiprehberger::StateBag.clear
Philiprehberger::StateBag.set(:request, { id: "abc", user: { email: "x@y.com" } })
Philiprehberger::StateBag.dig(:request, :user, :email) # => "x@y.com"
Philiprehberger::StateBag.dig(:request, :missing) # => nil
Philiprehberger::StateBag.merge(user_id: 42, locale: 'en', request_id: 'req-1')
# => {:user_id=>42, :locale=>"en", :request_id=>"req-1"}
Philiprehberger::StateBag.slice(:user_id, :locale)
# => {:user_id=>42, :locale=>"en"}
Philiprehberger::StateBag.each { |k, v| puts "#{k}=#{v}" }
Philiprehberger::StateBag.replace(user_id: 99)
Philiprehberger::StateBag.to_h
# => {:user_id=>99}
Atomically read-modify-write a single key. The block receives the current
value (or nil if the key is missing) and its return value is stored back.
Philiprehberger::StateBag.set(:counter, 0)
Philiprehberger::StateBag.update(:counter) { |v| v + 1 }
Philiprehberger::StateBag.get(:counter) # => 1
Philiprehberger::StateBag.update(:visited) { |v| (v || []) + ['/home'] }
Philiprehberger::StateBag.get(:visited) # => ["/home"]
Philiprehberger::StateBag.set(:user_id, 42)
Philiprehberger::StateBag.set(:locale, 'en')
snapshot = Philiprehberger::StateBag.snapshot
# => {:user_id=>42, :locale=>"en"} (frozen)
Philiprehberger::StateBag.set(:user_id, 99)
Philiprehberger::StateBag.restore(snapshot)
Philiprehberger::StateBag.get(:user_id)
# => 42
| Method | Description |
|---|---|
.set(key, val) | Store a value in the thread-local state bag |
.get(key, default = nil) | Retrieve a value or return the default |
.with(**overrides, &block) | Execute block with temporary state, restoring after |
.fetch(key, default = UNSET, &block) | Retrieve a value; raises KeyError if missing with no default/block |
.dig(*keys) | Dig into nested hash-valued entries; returns nil on any miss |
.delete(key) | Remove a key and return its value |
.clear | Remove all entries from the state bag |
.to_h | Return a snapshot of the current state |
.key?(key) | Check if a key exists in the state bag |
.size | Number of entries in the state bag |
.empty? | True if the state bag has no entries |
.keys | Array of all keys in the state bag |
.values | Array of all values in the state bag |
.merge(**entries) | Bulk-set multiple keys; returns a snapshot |
.replace(hash) | Replace the entire state with the given hash; returns a snapshot |
.slice(*keys) | Return a hash containing only the given keys |
.each(&block) | Iterate key-value pairs; returns an Enumerator without a block |
.update(key, &block) | Atomic read-modify-write; yields current value (or nil), stores block result |
.snapshot | Return a frozen copy of the current state |
.restore(snapshot) | Replace the state with a copy of the given snapshot; raises ArgumentError for non-Hash |
bundle install
bundle exec rspec
bundle exec rubocop
If you find this project useful: