Hamster
Efficient, Immutable, Thread-Safe Collection classes for Ruby
Install / Use
/learn @hamstergem/HamsterREADME
Hamster
Efficient, immutable, and thread-safe collection classes for Ruby.
Hamster provides 6 Persistent Data
Structures: Hash, Vector, Set, SortedSet, List, and Deque (which works as an immutable queue or stack).
Hamster collections are immutable. Whenever you modify a Hamster collection, the original is preserved and a modified copy is returned. This makes them inherently thread-safe and shareable. At the same time, they remain CPU and memory-efficient by sharing between copies.
While Hamster collections are immutable, you can still mutate objects stored in them. We recommend that you don't do this, unless you are sure you know what you are doing. Hamster collections are thread-safe and can be freely shared between threads, but you are responsible for making sure that the objects stored in them are used in a thread-safe manner.
Hamster collections are almost always closed under a given operation. That is, whereas Ruby's collection methods always return arrays, Hamster collections will return an instance of the same class wherever possible.
Where possible, Hamster collections offer an interface compatible with Ruby's
built-in Hash, Array, and Enumerable, to ease code migration. Also, Hamster methods accept regular Ruby collections as arguments, so code which uses Hamster can easily interoperate with your other Ruby code.
And lastly, Hamster lists are lazy, making it possible to (among other things) process "infinitely large" lists.
Using
To make the collection classes available in your code:
require "hamster"
Or if you prefer to only pull in certain collection types:
require "hamster/hash"
require "hamster/vector"
require "hamster/set"
require "hamster/sorted_set"
require "hamster/list"
require "hamster/deque"
<h2>Hash <span style="font-size:0.7em">(<a href="http://rubydoc.info/github/hamstergem/hamster/master/Hamster/Hash">API Documentation</a>)</span></h2>
Constructing a Hamster Hash is almost as simple as a regular one:
person = Hamster::Hash[name: "Simon", gender: :male]
# => Hamster::Hash[:name => "Simon", :gender => :male]
Accessing the contents will be familiar to you:
person[:name] # => "Simon"
person.get(:gender) # => :male
Updating the contents is a little different than you are used to:
friend = person.put(:name, "James") # => Hamster::Hash[:name => "James", :gender => :male]
person # => Hamster::Hash[:name => "Simon", :gender => :male]
friend[:name] # => "James"
person[:name] # => "Simon"
As you can see, updating the hash returned a copy leaving the original intact. Similarly, deleting a key returns yet another copy:
male = person.delete(:name) # => Hamster::Hash[:gender => :male]
person # => Hamster::Hash[:name => "Simon", :gender => :male]
male.key?(:name) # => false
person.key?(:name) # => true
Since it is immutable, Hamster's Hash doesn't provide an assignment
(Hash#[]=) method. However, Hash#put can accept a block which
transforms the value associated with a given key:
counters = Hamster::Hash[evens: 0, odds: 0] # => Hamster::Hash[:evens => 0, :odds => 0]
counters.put(:odds) { |value| value + 1 } # => Hamster::Hash[:odds => 1, :evens => 0]
Or more succinctly:
counters.put(:odds, &:next) # => {:odds => 1, :evens => 0}
This is just the beginning; see the API documentation for details on all Hash methods.
A Vector is an integer-indexed collection much like an immutable Array. Examples:
vector = Hamster::Vector[1, 2, 3, 4] # => Hamster::Vector[1, 2, 3, 4]
vector[0] # => 1
vector[-1] # => 4
vector.put(1, :a) # => Hamster::Vector[1, :a, 3, 4]
vector.add(:b) # => Hamster::Vector[1, 2, 3, 4, :b]
vector.insert(2, :a, :b) # => Hamster::Vector[1, 2, :a, :b, 3, 4]
vector.delete_at(0) # => Hamster::Vector[2, 3, 4]
Other Array-like methods like #select, #map, #shuffle, #uniq, #reverse,
#rotate, #flatten, #sort, #sort_by, #take, #drop, #take_while,
#drop_while, #fill, #product, and #transpose are also supported. See the
API documentation for details on all Vector methods.
A Set is an unordered collection of values with no duplicates. It is much like the Ruby standard library's Set, but immutable. Examples:
set = Hamster::Set[:red, :blue, :yellow] # => Hamster::Set[:red, :blue, :yellow]
set.include? :red # => true
set.add :green # => Hamster::Set[:red, :blue, :yellow, :green]
set.delete :blue # => Hamster::Set[:red, :yellow]
set.superset? Hamster::Set[:red, :blue] # => true
set.union([:red, :blue, :pink]) # => Hamster::Set[:red, :blue, :yellow, :pink]
set.intersection([:red, :blue, :pink]) # => Hamster::Set[:red, :blue]
Like most Hamster methods, the set-theoretic methods #union, #intersection, #difference, and #exclusion (aliased as #|, #&, #-, and #^) all work with regular Ruby collections, or indeed any Enumerable object. So just like all the other Hamster collections, Hamster::Set can easily be used in combination with "ordinary" Ruby code.
See the API documentation for details on all Set methods.
A SortedSet is like a Set, but ordered. You can do everything with it that you can
do with a Set. Additionally, you can get the #first and #last item, or retrieve
an item using an integral index:
set = Hamster::SortedSet['toast', 'jam', 'bacon'] # => Hamster::SortedSet["bacon", "jam", "toast"]
set.first # => "bacon"
set.last # => "toast"
set[1] # => "jam"
You can also specify the sort order using a block:
Hamster::SortedSet.new(['toast', 'jam', 'bacon']) { |a,b| b <=> a }
Hamster::SortedSet.new(['toast', 'jam', 'bacon']) { |str| str.chars.last }
See the API documentation for details on all SortedSet methods.
Hamster Lists have a head (the value at the front of the list),
and a tail (a list of the remaining items):
list = Hamster::List[1, 2, 3]
list.head # => 1
list.tail # => Hamster::List[2, 3]
Add to a list with List#add:
original = Hamster::List[1, 2, 3]
copy = original.add(0) # => Hamster::List[0, 1, 2, 3]
Notice how modifying a list actually returns a new list.
That's because Hamster Lists are immutable.
Laziness
List is lazy where possible. It tries to defer processing items until
absolutely necessary. For example, the following code will only call
Prime.prime? as many times as necessary to generate the first 3
prime numbers between 10,000 and 1,000,000:
require 'prime'
Hamster.interval(10_000, 1_000_000).select do |
Related Skills
node-connect
340.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.1kCommit, push, and open a PR
