[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8098":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":16,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":16,"starSnapshotCount":16,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},8098,"hamster","hamstergem\u002Fhamster","hamstergem","Efficient, Immutable, Thread-Safe Collection classes for Ruby","",null,"Ruby",1912,92,29,12,0,53.91,"Other",false,"core",[],"2026-06-12 04:00:37","Hamster\n=======\n\n  - [![Quality](http:\u002F\u002Fimg.shields.io\u002Fcodeclimate\u002Fgithub\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](https:\u002F\u002Fcodeclimate.com\u002Fgithub\u002Fhamstergem\u002Fhamster)\n  - [![Coverage](http:\u002F\u002Fimg.shields.io\u002Fcodeclimate\u002Fcoverage\u002Fgithub\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](https:\u002F\u002Fcodeclimate.com\u002Fgithub\u002Fhamstergem\u002Fhamster)\n  - [![Build](http:\u002F\u002Fimg.shields.io\u002Ftravis-ci\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](https:\u002F\u002Ftravis-ci.org\u002Fhamstergem\u002Fhamster)\n  - [![Dependencies](http:\u002F\u002Fimg.shields.io\u002Fgemnasium\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](https:\u002F\u002Fgemnasium.com\u002Fhamstergem\u002Fhamster)\n  - [![Downloads](http:\u002F\u002Fimg.shields.io\u002Fgem\u002Fdtv\u002Fhamster.svg?style=flat-square)](https:\u002F\u002Frubygems.org\u002Fgems\u002Fhamster)\n  - [![Tags](http:\u002F\u002Fimg.shields.io\u002Fgithub\u002Ftag\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](http:\u002F\u002Fgithub.com\u002Fhamstergem\u002Fhamster\u002Ftags)\n  - [![Releases](http:\u002F\u002Fimg.shields.io\u002Fgithub\u002Frelease\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](http:\u002F\u002Fgithub.com\u002Fhamstergem\u002Fhamster\u002Freleases)\n  - [![Issues](http:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fissues\u002Fhamstergem\u002Fhamster.svg?style=flat-square)](http:\u002F\u002Fgithub.com\u002Fhamstergem\u002Fhamster\u002Fissues)\n  - [![License](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-brightgreen.svg?style=flat-square)](http:\u002F\u002Fopensource.org\u002Flicenses\u002FMIT)\n  - [![Version](http:\u002F\u002Fimg.shields.io\u002Fgem\u002Fv\u002Fhamster.svg?style=flat-square)](https:\u002F\u002Frubygems.org\u002Fgems\u002Fhamster)\n  - [![Discuss](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fdiscuss-join%20gitter-brightgreen.svg?style=flat-square)](https:\u002F\u002Fgitter.im\u002Fhamstergem\u002Fhamster)\n\nEfficient, immutable, and thread-safe collection classes for Ruby.\n\nHamster provides 6 [Persistent Data\nStructures][PDS]: [`Hash`][HASH-DOC], [`Vector`][VECTOR-DOC], [`Set`][SET-DOC], [`SortedSet`][SORTED-SET-DOC], [`List`][LIST-DOC], and [`Deque`][DEQUE-DOC] (which works as an immutable queue or stack).\n\nHamster collections are **immutable**. Whenever you modify a Hamster\ncollection, the original is preserved and a modified copy is returned. This\nmakes them inherently thread-safe and shareable. At the same time, they remain\nCPU and memory-efficient by sharing between copies. \n\nWhile Hamster collections are immutable, you can still mutate objects stored\nin them. We recommend that  you don't do this, unless you are sure you know \nwhat you are doing. Hamster collections are thread-safe and can be freely \nshared between threads, but you are responsible for making sure that the \nobjects stored in them are used in a thread-safe manner.\n\nHamster collections are almost always closed under a given operation. That is,\nwhereas Ruby's collection methods always return arrays, Hamster collections\nwill return an instance of the same class wherever possible.\n\nWhere possible, Hamster collections offer an interface compatible with Ruby's\nbuilt-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.\n\nAnd lastly, Hamster lists are lazy, making it possible to (among other things)\nprocess \"infinitely large\" lists.\n\n[PDS]: http:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPersistent_data_structure\n[HASH-DOC]: http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FHash\n[SET-DOC]: http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FSet\n[VECTOR-DOC]: http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FVector\n[LIST-DOC]: http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FList\n[SORTED-SET-DOC]: http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FSortedSet\n[DEQUE-DOC]: http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FDeque\n\n\nUsing\n=====\n\nTo make the collection classes available in your code:\n\n``` ruby\nrequire \"hamster\"\n```\n\nOr if you prefer to only pull in certain collection types:\n\n``` ruby\nrequire \"hamster\u002Fhash\"\nrequire \"hamster\u002Fvector\"\nrequire \"hamster\u002Fset\"\nrequire \"hamster\u002Fsorted_set\"\nrequire \"hamster\u002Flist\"\nrequire \"hamster\u002Fdeque\"\n```\n\n\u003Ch2>Hash \u003Cspan style=\"font-size:0.7em\">(\u003Ca href=\"http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FHash\">API Documentation\u003C\u002Fa>)\u003C\u002Fspan>\u003C\u002Fh2>\n\nConstructing a Hamster `Hash` is almost as simple as a regular one:\n\n``` ruby\nperson = Hamster::Hash[name: \"Simon\", gender: :male]\n# => Hamster::Hash[:name => \"Simon\", :gender => :male]\n```\n\nAccessing the contents will be familiar to you:\n\n``` ruby\nperson[:name]                       # => \"Simon\"\nperson.get(:gender)                 # => :male\n```\n\nUpdating the contents is a little different than you are used to:\n\n``` ruby\nfriend = person.put(:name, \"James\") # => Hamster::Hash[:name => \"James\", :gender => :male]\nperson                              # => Hamster::Hash[:name => \"Simon\", :gender => :male]\nfriend[:name]                       # => \"James\"\nperson[:name]                       # => \"Simon\"\n```\n\nAs you can see, updating the hash returned a copy leaving\nthe original intact. Similarly, deleting a key returns\nyet another copy:\n\n``` ruby\nmale = person.delete(:name)         # => Hamster::Hash[:gender => :male]\nperson                              # => Hamster::Hash[:name => \"Simon\", :gender => :male]\nmale.key?(:name)                    # => false\nperson.key?(:name)                  # => true\n```\n\nSince it is immutable, Hamster's `Hash` doesn't provide an assignment\n(`Hash#[]=`) method. However, `Hash#put` can accept a block which\ntransforms the value associated with a given key:\n\n``` ruby\ncounters = Hamster::Hash[evens: 0, odds: 0]  # => Hamster::Hash[:evens => 0, :odds => 0]\ncounters.put(:odds) { |value| value + 1 }    # => Hamster::Hash[:odds => 1, :evens => 0]\n```\n\nOr more succinctly:\n\n``` ruby\ncounters.put(:odds, &:next)         # => {:odds => 1, :evens => 0}\n```\n\nThis is just the beginning; see the [API documentation][HASH-DOC] for details on all `Hash` methods.\n\n\n\u003Ch2>Vector \u003Cspan style=\"font-size:0.7em\">(\u003Ca href=\"http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FVector\">API Documentation\u003C\u002Fa>)\u003C\u002Fspan>\u003C\u002Fh2>\n\nA `Vector` is an integer-indexed collection much like an immutable `Array`. Examples:\n\n``` ruby\nvector = Hamster::Vector[1, 2, 3, 4] # => Hamster::Vector[1, 2, 3, 4]\nvector[0]                            # => 1\nvector[-1]                           # => 4\nvector.put(1, :a)                    # => Hamster::Vector[1, :a, 3, 4]\nvector.add(:b)                       # => Hamster::Vector[1, 2, 3, 4, :b]\nvector.insert(2, :a, :b)             # => Hamster::Vector[1, 2, :a, :b, 3, 4]\nvector.delete_at(0)                  # => Hamster::Vector[2, 3, 4]\n```\n\nOther `Array`-like methods like `#select`, `#map`, `#shuffle`, `#uniq`, `#reverse`,\n`#rotate`, `#flatten`, `#sort`, `#sort_by`, `#take`, `#drop`, `#take_while`,\n`#drop_while`, `#fill`, `#product`, and `#transpose` are also supported. See the\n[API documentation][VECTOR-DOC] for details on all `Vector` methods.\n\n\n\u003Ch2>Set \u003Cspan style=\"font-size:0.7em\">(\u003Ca href=\"http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FSet\">API Documentation\u003C\u002Fa>)\u003C\u002Fspan>\u003C\u002Fh2>\n\nA `Set` is an unordered collection of values with no duplicates. It is much like the Ruby standard library's `Set`, but immutable. Examples:\n\n``` ruby\nset = Hamster::Set[:red, :blue, :yellow] # => Hamster::Set[:red, :blue, :yellow]\nset.include? :red                        # => true\nset.add :green                           # => Hamster::Set[:red, :blue, :yellow, :green]\nset.delete :blue                         # => Hamster::Set[:red, :yellow]\nset.superset? Hamster::Set[:red, :blue]  # => true\nset.union([:red, :blue, :pink])          # => Hamster::Set[:red, :blue, :yellow, :pink]\nset.intersection([:red, :blue, :pink])   # => Hamster::Set[:red, :blue]\n```\n\nLike 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.\n\nSee the [API documentation][SET-DOC] for details on all `Set` methods.\n\n\n\u003Ch2>SortedSet \u003Cspan style=\"font-size:0.7em\">(\u003Ca href=\"http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FSortedSet\">API Documentation\u003C\u002Fa>)\u003C\u002Fspan>\u003C\u002Fh2>\n\nA `SortedSet` is like a `Set`, but ordered. You can do everything with it that you can\ndo with a `Set`. Additionally, you can get the `#first` and `#last` item, or retrieve\nan item using an integral index:\n\n``` ruby\nset = Hamster::SortedSet['toast', 'jam', 'bacon'] # => Hamster::SortedSet[\"bacon\", \"jam\", \"toast\"]\nset.first                                         # => \"bacon\"\nset.last                                          # => \"toast\"\nset[1]                                            # => \"jam\"\n```\n\nYou can also specify the sort order using a block:\n\n``` ruby\nHamster::SortedSet.new(['toast', 'jam', 'bacon']) { |a,b| b \u003C=> a }\nHamster::SortedSet.new(['toast', 'jam', 'bacon']) { |str| str.chars.last }\n```\n\nSee the [API documentation][SORTED-SET-DOC] for details on all `SortedSet` methods.\n\n\n\u003Ch2>List \u003Cspan style=\"font-size:0.7em\">(\u003Ca href=\"http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FList\">API Documentation\u003C\u002Fa>)\u003C\u002Fspan>\u003C\u002Fh2>\n\nHamster `List`s have a *head* (the value at the front of the list),\nand a *tail* (a list of the remaining items):\n\n``` ruby\nlist = Hamster::List[1, 2, 3]\nlist.head                    # => 1\nlist.tail                    # => Hamster::List[2, 3]\n```\n\nAdd to a list with `List#add`:\n\n``` ruby\noriginal = Hamster::List[1, 2, 3]\ncopy = original.add(0)      # => Hamster::List[0, 1, 2, 3]\n```\n\nNotice how modifying a list actually returns a new list.\nThat's because Hamster `List`s are immutable.\n\n### Laziness\n\n`List` is lazy where possible. It tries to defer processing items until\nabsolutely necessary. For example, the following code will only call\n`Prime.prime?` as many times as necessary to generate the first 3\nprime numbers between 10,000 and 1,000,000:\n\n``` ruby\nrequire 'prime'\n\nHamster.interval(10_000, 1_000_000).select do |number|\n  Prime.prime?(number)\nend.take(3)\n  # => 0.0009s\n```\n\nCompare that to the conventional equivalent which needs to\ncalculate all possible values in the range before taking the\nfirst three:\n\n``` ruby\n(10000..1000000).select do |number|\n  Prime.prime?(number)\nend.take(3)\n  # => 10s\n```\n\n### Construction\n\nBesides `Hamster::List[]` there are other ways to construct lists:\n\n  - `Hamster.interval(from, to)` creates a lazy list\n    equivalent to a list containing all the values between\n    `from` and `to` without actually creating a list that big.\n\n  - `Hamster.stream { ... }` allows you to creates infinite\n    lists. Each time a new value is required, the supplied\n    block is called. To generate a list of integers you\n    could do:\n\n    ``` ruby\n    count = 0\n    Hamster.stream { count += 1 }\n    ```\n\n  - `Hamster.repeat(x)` creates an infinite list with `x` the\n    value for every element.\n\n  - `Hamster.replicate(n, x)` creates a list of size `n` with\n    `x` the value for every element.\n\n  - `Hamster.iterate(x) { |x| ... }` creates an infinite\n    list where the first item is calculated by applying the\n    block on the initial argument, the second item by applying\n    the function on the previous result and so on. For\n    example, a simpler way to generate a list of integers\n    would be:\n\n    ``` ruby\n    Hamster.iterate(1) { |i| i + 1 }\n    ```\n\n    or even more succinctly:\n\n    ``` ruby\n    Hamster.iterate(1, &:next)\n    ```\n\n  - `Hamster::List.empty` returns an empty list, which you can\n    build up using repeated calls to `#add` or other `List` methods.\n\n### Core Extensions\n\n`Enumerable#to_list` will convert any existing `Enumerable` to a list, so you can\nslowly transition from built-in collection classes to Hamster.\n\n`IO#to_list` enables lazy processing of huge files. For example, imagine the\nfollowing code to process a 100MB file:\n\n``` ruby\nrequire 'hamster\u002Fcore_ext'\n\nFile.open(\"my_100_mb_file.txt\") do |file|\n  lines = []\n  file.each_line do |line|\n    break if lines.size == 10\n    lines \u003C\u003C line.chomp.downcase.reverse\n  end\nend\n```\n\nCompare to the following more functional version:\n\n``` ruby\nFile.open(\"my_100_mb_file.txt\") do |file|\n  file.map(&:chomp).map(&:downcase).map(&:reverse).take(10)\nend\n```\n\nUnfortunately, though the second example reads nicely it\ntakes many seconds to run (compared with milliseconds\nfor the first) even though we're only interested in the first\nten lines. Using `#to_list` we can get the running time back comparable to the\nimperative version.\n\n``` ruby\nFile.open(\"my_100_mb_file.txt\") do |file|\n  file.to_list.map(&:chomp).map(&:downcase).map(&:reverse).take(10)\nend\n```\n\nThis is possible because `IO#to_list` creates a lazy list whereby each line is\nonly ever read and processed as needed, in effect converting it to the first\nexample.\n\nSee the API documentation for details on all [`List`][LIST-DOC] methods.\n\n\n\u003Ch2>Deque \u003Cspan style=\"font-size:0.7em\">(\u003Ca href=\"http:\u002F\u002Frubydoc.info\u002Fgithub\u002Fhamstergem\u002Fhamster\u002Fmaster\u002FHamster\u002FDeque\">API Documentation\u003C\u002Fa>)\u003C\u002Fspan>\u003C\u002Fh2>\n\nA `Deque` (or \"double-ended queue\") is an ordered collection, which allows you to push and pop items from both front and back. This makes it perfect as an immutable stack *or* queue. Examples:\n\n``` ruby\ndeque = Hamster::Deque[1, 2, 3] # => Hamster::Deque[1, 2, 3]\ndeque.first                     # 1\ndeque.last                      # 3\ndeque.pop                       # => Hamster::Deque[1, 2]\ndeque.push(:a)                  # => Hamster::Deque[1, 2, 3, :a]\ndeque.shift                     # => Hamster::Deque[2, 3]\ndeque.unshift(:a)               # => Hamster::Deque[:a, 1, 2, 3]\n```\n\nOf course, you can do the same thing with a `Vector`, but a `Deque` is more efficient. See the API documentation for details on all [`Deque`][DEQUE-DOC] methods.\n\n\n\u003Ch2>Transformations\u003C\u002Fh2>\n\nHamster arrays, hashes, and nested structures of arrays and hashes may be transformed with the `update_in` method.\n\n``` ruby\nc = Hamster.from({\n  people: [{name: 'Chris', city: 'Lagos'}, {name: 'Pat', city: 'Madrid'}],\n  places: [{name: 'Lagos', population: 1}, {name: 'Madrid', population: 1}]})\nc2 = c.update_in(:people, 1, :city) { |old_city| 'Lagos' }\nc3 = c2.update_in(:places, 1, :population) { |old_population| old_population - 1 }\nc4 = c3.update_in(:places, 0, :population) { |old_population| old_population + 1 }\nHamster.to_ruby(c4)\n# => {:places=>[{:population=>2, :name=>\"Lagos\"}, {:population=>0, :name=>\"Madrid\"}], :people=>[{:name=>\"Chris\", :city=>\"Lagos\"}, {:name=>\"Pat\", :city=>\"Lagos\"}]}\n```\n\nNaturally, `update_in` never mutates your collections.\n\nSee `Hamster::Hash#update_in`, `Hamster::Vector#update_in`, and `Hamster::Associable#update_in` for details.\n\n\nInstalling\n==========\n\nAdd this line to your application's Gemfile:\n\n    gem \"hamster\"\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install hamster\n\n\nContributing\n============\n\n  1. Read the [Code of Conduct](\u002FCONDUCT.md)\n  2. Fork it\n  3. Create your feature branch (`git checkout -b my-new-feature`)\n  4. Commit your changes (`git commit -am \"Add some feature\"`)\n  5. Push to the branch (`git push origin my-new-feature`)\n  6. Create new Pull Request\n\n\nOther Reading\n=============\n\n- The structure which is used for Hamster's `Hash` and `Set`: [Hash Array Mapped Tries][HAMT]\n- An interesting perspective on why immutability itself is inherently a good thing: Matthias Felleisen's [Function Objects presentation][FO].\n- The Hamster [FAQ](FAQ.md)\n- [Changelog](CHANGELOG.md)\n\n[HAMT]: http:\u002F\u002Flampwww.epfl.ch\u002Fpapers\u002Fidealhashtrees.pdf\n[FO]: http:\u002F\u002Fwww.ccs.neu.edu\u002Fhome\u002Fmatthias\u002FPresentations\u002Fecoop2004.pdf\n\n\nLicensing\n=========\n\nCopyright (c) 2009-2015 Simon Harris\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and\u002For sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","Hamster 是一个为 Ruby 提供高效、不可变且线程安全集合类的库。它包含六种持久化数据结构：哈希表、向量、集合、有序集合、列表和双端队列，这些结构在修改时不会改变原对象而是返回新的副本，从而保证了线程安全性和可共享性。同时，通过内部共享机制，Hamster 保持了良好的性能表现。适用于需要高并发处理或数据不变性的场景，如多线程环境下的数据操作与共享。此外，Hamster 的接口设计尽量与 Ruby 内置的数据结构兼容，方便现有项目的迁移和集成。",2,"2026-06-11 03:16:05","top_language"]