<commit_before>= Hamster - Efficient, Immutable, Thread-Safe Collection classes for Ruby

  GitHub:     http://github.com/harukizaemon/bundler
  Gemcutter:  http://gemcutter/harukizaemon/hamster
  email:      <EMAIL>
  IRC:        #haruki_zaemon on freenode

== Intro

Hamster started out as an implementation of Hash Array Mapped Trees (HAMT) for Ruby (see http://lamp.epfl.ch/papers/idealhashtrees.pdf) and has since expanded to include implementations of other Persistent Data Structures (see http://en.wikipedia.org/wiki/Persistent_data_structure) including Set, List, and Stack.

Unlike Ruby's standard library, Hamster collections are immutable. Whenever you modify a Hamster collection, say a Hash for example, the original is preserved and a modified copy is returned, making them inherently thread-safe and sharable. (For an interesting perspective on why immutability itself is inherently a good thing, you might like to take a look at Matthias Felleisen's Function Objects presentation: http://www.ccs.neu.edu/home/matthias/Presentations/ecoop2004.pdf) By making use of some very well understood and very simple techniques, the returned copy is also very space efficient, sharing a much of the original's structure.

Hamster collections are almost always closed under a given operation. That is, whereas Ruby's collection class methods always return arrays, Hamster classes will return an instance of the same class wherever possible.

And lastly, Hamster lists are lazy -- where Ruby's language constructs permit -- making it possible to, among other things, process "infinitely large" lists. (Note: Ruby 1.9 supports a form of laziness using Enumerator however they're implemented using Fibers which unfortunately can't be shared across threads.)

== Installation

Hamster is distributed as a gem via gemcutter (http://gemcutter.org/gems/hamster) or as source via GitHub (http://github.com/harukizaemon/hamster).

Installation via the gem is easy:

  > gem install hamster

Once installed, all that remains is to make the collection classes available in your code:

  require 'hamster'

If you prefer, you can instead require individual classes as necessary:

  require 'hamster/hash'
  require 'hamster/set'
  require 'hamster/list'
  require 'hamster/stack'

== Examples

Most classes support an API that resembles their standard library counterparts with the caveat that any modification returns a new instance. What follows are some simple examples to help illustrate this point.

=== Hash

Constructing a Hamster Hash is almost as simple as a regular one:

  simon = Hamster.hash(:name => "Simon", :gender => :male)  # => {:name => "Simon", :gender => :male}

Accessing the contents will be familiar to you:<commit_msg>More doco.<commit_after>= Hamster - Efficient, Immutable, Thread-Safe Collection classes for Ruby

  GitHub:     http://github.com/harukizaemon/bundler
  Gemcutter:  http://gemcutter/harukizaemon/hamster
  email:      <EMAIL>
  IRC:        #haruki_zaemon on freenode

== Intro

Hamster started out as an implementation of Hash Array Mapped Trees (HAMT) for Ruby (see http://lamp.epfl.ch/papers/idealhashtrees.pdf) and has since expanded to include implementations of other Persistent Data Structures (see http://en.wikipedia.org/wiki/Persistent_data_structure) including Set, List, and Stack.

Unlike Ruby's standard library, Hamster collections are immutable. Whenever you modify a Hamster collection, say a Hash for example, the original is preserved and a modified copy is returned, making them inherently thread-safe and sharable. (For an interesting perspective on why immutability itself is inherently a good thing, you might like to take a look at <NAME>'s Function Objects presentation: http://www.ccs.neu.edu/home/matthias/Presentations/ecoop2004.pdf) By making use of some very well understood and very simple techniques, the returned copy is also very space efficient, sharing a much of the original's structure.

Hamster collections are almost always closed under a given operation. That is, whereas Ruby's collection class methods always return arrays, Hamster classes will return an instance of the same class wherever possible.

And lastly, Hamster lists are lazy -- where Ruby's language constructs permit -- making it possible to, among other things, process "infinitely large" lists. (Note: Ruby 1.9 supports a form of laziness using Enumerator however they're implemented using Fibers which unfortunately can't be shared across threads.)

== Installation

Hamster is distributed as a gem via gemcutter (http://gemcutter.org/gems/hamster) or as source via GitHub (http://github.com/harukizaemon/hamster).

Installation via the gem is easy:

  > gem install hamster

Once installed, all that remains is to make the collection classes available in your code:

  require 'hamster'

If you prefer, you can instead require individual classes as necessary:

  require 'hamster/hash'
  require 'hamster/set'
  require 'hamster/list'
  require 'hamster/stack'

== Examples

Most Hamster classes support an API that resembles their standard library counterpart with the caveat that any modification returns a new instance. What follows are some simple examples to help illustrate this point.

=== Hash

Constructing a Hamster Hash is almost as simple as a regular one:

  simon = Hamster.hash(:name => "Simon", :gender => :male)  # => {:name => "Simon", :gender => :male}

Accessing the contents will be familiar to you:
{'fraction_non_alphanumeric': 0.066410537870472, 'fraction_numerical': 0.0021953896816684962, 'mean_word_length': 4.6302780638517, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6287468', 'n_tokens_mistral': 1457, 'n_tokens_neox': 1381, 'n_words': 688}