immutable-ruby-master/ 0000755 0001750 0001750 00000000000 14201005456 014660 5 ustar boutil boutil immutable-ruby-master/README.md 0000644 0001750 0001750 00000033023 14201005456 016140 0 ustar boutil boutil Immutable Ruby
==============
[](https://rubygems.org/gems/immutable-ruby)
[](http://github.com/immutable-ruby/immutable-ruby/issues)
[](http://opensource.org/licenses/MIT)
[](https://rubygems.org/gems/immutable-ruby)
Efficient, immutable, and thread-safe collection classes for Ruby.
The `immutable-ruby` gem provides 6 [Persistent Data Structures][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).
Whenever you "modify" an `Immutable` 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. (However, you *can* still mutate objects stored in these collections. We don't recommend that you do this, unless you are sure you know what you are doing.)
`Immutable` collections are almost always closed under a given operation. That is, whereas Ruby's collection methods always return arrays, `Immutable` collections will return an instance of the same class wherever possible.
Where possible, `Immutable` collections offer an interface compatible with Ruby's built-in `Hash`, `Array`, and `Enumerable`, to ease code migration. Also, `Immutable` methods accept regular Ruby collections as arguments, so code which uses `Immutable` can easily interoperate with your other Ruby code.
And lastly, `Immutable` lists are lazy, making it possible to (among other things) process "infinitely large" lists.
[PDS]: http://en.wikipedia.org/wiki/Persistent_data_structure
[HASH-DOC]: http://rubydoc.info/github/immutable-ruby/immutable-ruby/master/Immutable/Hash
[SET-DOC]: http://rubydoc.info/github/immutable-ruby/immutable-ruby/master/Immutable/Set
[VECTOR-DOC]: http://rubydoc.info/github/immutable-ruby/immutable-ruby/master/Immutable/Vector
[LIST-DOC]: http://rubydoc.info/github/immutable-ruby/immutable-ruby/master/Immutable/List
[SORTED-SET-DOC]: http://rubydoc.info/github/immutable-ruby/immutable-ruby/master/Immutable/SortedSet
[DEQUE-DOC]: http://rubydoc.info/github/immutable-ruby/immutable-ruby/master/Immutable/Deque
History
=======
`Immutable` was forked from Simon Harris' `Hamster` library, which is no longer maintained. It features some bug fixes and performance optimizations which are not included in `Hamster`. Aside from the name of the top-level module, the public API is virtually identical.
Using
=====
To make the collection classes available in your code:
``` ruby
require "immutable"
```
Or if you prefer to only pull in certain collection types:
``` ruby
require "immutable/hash"
require "immutable/vector"
require "immutable/set"
require "immutable/sorted_set"
require "immutable/list"
require "immutable/deque"
```
Constructing an `Immutable::Hash` is almost as simple as a regular one:
``` ruby
person = Immutable::Hash[name: "Simon", gender: :male]
# => Immutable::Hash[:name => "Simon", :gender => :male]
```
Accessing the contents will be familiar to you:
``` ruby
person[:name] # => "Simon"
person.get(:gender) # => :male
```
Updating the contents is a little different than you are used to:
``` ruby
friend = person.put(:name, "James") # => Immutable::Hash[:name => "James", :gender => :male]
person # => Immutable::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:
``` ruby
male = person.delete(:name) # => Immutable::Hash[:gender => :male]
person # => Immutable::Hash[:name => "Simon", :gender => :male]
male.key?(:name) # => false
person.key?(:name) # => true
```
Since it is immutable, `Immutable::Hash` doesn't provide an assignment (`Hash#[]=`) method. However, `Hash#put` can accept a block which transforms the value associated with a given key:
``` ruby
counters = Immutable::Hash[evens: 0, odds: 0]
counters.put(:odds) { |n| n + 1 } # => Immutable::Hash[:odds => 1, :evens => 0]
```
Or more succinctly:
``` ruby
counters.put(:odds, &:next) # => {:odds => 1, :evens => 0}
```
This is just the beginning; see the [API documentation][HASH-DOC] for details on all `Hash` 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:
``` ruby
set = Immutable::Set[:red, :blue, :yellow] # => Immutable::Set[:red, :blue, :yellow]
set.include? :red # => true
set.add :green # => Immutable::Set[:red, :blue, :yellow, :green]
set.delete :blue # => Immutable::Set[:red, :yellow]
set.superset? Immutable::Set[:red, :blue] # => true
set.union([:red, :blue, :pink]) # => Immutable::Set[:red, :blue, :yellow, :pink]
set.intersection([:red, :blue, :pink]) # => Immutable::Set[:red, :blue]
```
Like most `Immutable` 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 `Immutable` collections, `Immutable::Set` can easily be used in combination with "ordinary" Ruby code.
See the [API documentation][SET-DOC] 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:
``` ruby
set = Immutable::SortedSet['toast', 'jam', 'bacon'] # => Immutable::SortedSet["bacon", "jam", "toast"]
set.first # => "bacon"
set.last # => "toast"
set[1] # => "jam"
```
You can also specify the sort order using a block:
``` ruby
Immutable::SortedSet.new(['toast', 'jam', 'bacon']) { |a,b| b <=> a }
Immutable::SortedSet.new(['toast', 'jam', 'bacon']) { |str| str.chars.last }
```
See the [API documentation][SORTED-SET-DOC] for details on all `SortedSet` methods.
`Immutable::List`s have a *head* (the value at the front of the list),
and a *tail* (a list of the remaining items):
``` ruby
list = Immutable::List[1, 2, 3]
list.head # => 1
list.tail # => Immutable::List[2, 3]
```
Add to a list with `List#add`:
``` ruby
original = Immutable::List[1, 2, 3]
copy = original.add(0) # => Immutable::List[0, 1, 2, 3]
```
Notice how modifying a list actually returns a new list.
### Laziness
`Immutable::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:
``` ruby
require 'prime'
Immutable.interval(10_000, 1_000_000).select do |number|
Prime.prime?(number)
end.take(3)
# => 0.0009s
```
Compare that to the conventional equivalent which needs to
calculate all possible values in the range before taking the
first three:
``` ruby
(10000..1000000).select do |number|
Prime.prime?(number)
end.take(3)
# => 10s
```
### Construction
Besides `Immutable::List[]` there are other ways to construct lists:
- `Immutable.interval(from, to)` creates a lazy list
equivalent to a list containing all the values between
`from` and `to` without actually creating a list that big.
- `Immutable.stream { ... }` allows you to creates infinite
lists. Each time a new value is required, the supplied
block is called. To generate a list of integers you
could do:
``` ruby
count = 0
Immutable.stream { count += 1 }
```
- `Immutable.repeat(x)` creates an infinite list with `x` as the
value for every element.
- `Immutable.replicate(n, x)` creates a list of size `n` with
`x` as the value for every element.
- `Immutable.iterate(x) { |x| ... }` creates an infinite
list where the first item is calculated by applying the
block on the initial argument, the second item by applying
the function on the previous result and so on. For
example, a simpler way to generate a list of integers
would be:
``` ruby
Immutable.iterate(1) { |i| i + 1 }
```
or even more succinctly:
``` ruby
Immutable.iterate(1, &:next)
```
- `Immutable::List.empty` returns an empty list, which you can
build up using repeated calls to `#add` or other `List` methods.
### Core Extensions
`Enumerable#to_list` will convert any existing `Enumerable` to a list, so you can
slowly transition from built-in collection classes to `Immutable`.
`IO#to_list` enables lazy processing of huge files. For example, imagine the
following code to process a 100MB file:
``` ruby
require 'immutable/core_ext'
File.open("my_100_mb_file.txt") do |file|
lines = []
file.each_line do |line|
break if lines.size == 10
lines << line.chomp.downcase.reverse
end
end
```
Compare to the following more functional version:
``` ruby
File.open("my_100_mb_file.txt") do |file|
file.map(&:chomp).map(&:downcase).map(&:reverse).take(10)
end
```
Unfortunately, though the second example reads nicely, it takes many seconds to run (compared with milliseconds for the first) even though we're only interested in the first ten lines. Using `#to_list` we can get the running time back comparable to the imperative version.
``` ruby
File.open("my_100_mb_file.txt") do |file|
file.to_list.map(&:chomp).map(&:downcase).map(&:reverse).take(10)
end
```
This is possible because `IO#to_list` creates a lazy list whereby each line is
only ever read and processed as needed, in effect converting it to the first
example.
See the API documentation for details on all [`List`][LIST-DOC] methods.
A `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:
``` ruby
deque = Immutable::Deque[1, 2, 3] # => Immutable::Deque[1, 2, 3]
deque.first # 1
deque.last # 3
deque.pop # => Immutable::Deque[1, 2]
deque.push(:a) # => Immutable::Deque[1, 2, 3, :a]
deque.shift # => Immutable::Deque[2, 3]
deque.unshift(:a) # => Immutable::Deque[:a, 1, 2, 3]
```
Of 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.
Installing
==========
Add this line to your application's Gemfile:
gem "immutable-ruby"
And then execute:
$ bundle
Or install it yourself as:
$ gem install immutable-ruby
Other Reading
=============
- The structure which is used for `Immutable::Hash` and `Immutable::Set`: [Hash Array Mapped Tries][HAMT]
- An interesting perspective on why immutability itself is inherently a good thing: Matthias Felleisen's [Function Objects presentation][FO].
- The `immutable-ruby` [FAQ](FAQ.md)
- [Code of Conduct](CONDUCT.md)
- [License](LICENSE)
[HAMT]: http://lampwww.epfl.ch/papers/idealhashtrees.pdf
[FO]: https://web.archive.org/web/20200113172704/http://www.ccs.neu.edu/home/matthias/Presentations/ecoop2004.pdf
immutable-ruby-master/.yardopts 0000644 0001750 0001750 00000000123 14201005456 016522 0 ustar boutil boutil --no-private
--markup=markdown
--readme=YARD-README.md
-
LICENSE
FAQ.md
CONDUCT.md
immutable-ruby-master/YARD-README.md 0000644 0001750 0001750 00000027500 14201005456 016700 0 ustar boutil boutil Immutable Ruby
==============
Efficient, immutable, and thread-safe collection classes for Ruby.
The `immutable-ruby` gem provides 6 [Persistent Data Structures][PDS]: {Immutable::Hash Hash}, {Immutable::Vector Vector}, {Immutable::Set Set}, {Immutable::SortedSet SortedSet}, {Immutable::List List}, and {Immutable::Deque Deque} (which works as an immutable queue or stack).
Whenever you modify an `Immutable` 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. (However, you *can* still mutate objects stored in these collections. We don't recommend that you do this, unless you are sure you know what you are doing.)
`Immutable` collections are almost always closed under a given operation. That is, whereas Ruby's collection methods always return arrays, `Immutable` collections will return an instance of the same class wherever possible.
Where possible, `Immutable` collections offer an interface compatible with Ruby's built-in `Hash`, `Array`, `Set`, and `Enumerable`, to ease code migration. Also, `Immutable` methods accept regular Ruby collections as arguments, so code which uses `Immutable` can easily interoperate with your other Ruby code.
And lastly, `Immutable` lists are lazy, making it possible to (among other things)
process "infinitely large" lists.
[PDS]: http://en.wikipedia.org/wiki/Persistent_data_structure
Using
=====
To make the collection classes available in your code:
``` ruby
require "immutable"
```
Or if you prefer to only pull in certain collection types:
``` ruby
require "immutable/hash"
require "immutable/vector"
require "immutable/set"
require "immutable/sorted_set"
require "immutable/list"
require "immutable/deque"
```
Hash ({Immutable::Hash API Documentation})
Constructing an `Immutable::Hash` is almost as simple as a regular one:
``` ruby
person = Immutable::Hash[name: "Simon", gender: :male]
# => Immutable::Hash[:name => "Simon", :gender => :male]
```
Accessing the contents will be familiar to you:
``` ruby
person[:name] # => "Simon"
person.get(:gender) # => :male
```
Updating the contents is a little different than you are used to:
``` ruby
friend = person.put(:name, "James") # => Immutable::Hash[:name => "James", :gender => :male]
person # => Immutable::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:
``` ruby
male = person.delete(:name) # => Immutable::Hash[:gender => :male]
person # => Immutable::Hash[:name => "Simon", :gender => :male]
male.key?(:name) # => false
person.key?(:name) # => true
```
Since it is immutable, `Immutable::Hash` doesn't provide an assignment (`Hash#[]=`) method. However, `Hash#put` can accept a block which transforms the value associated with a given key:
``` ruby
counters = Immutable::Hash[evens: 0, odds: 0]
counters.put(:odds) { |n| n + 1 } # => Immutable::Hash[:odds => 1, :evens => 0]
```
Or more succinctly:
``` ruby
counters.put(:odds, &:next) # => {:odds => 1, :evens => 0}
```
This is just the beginning; see the {Immutable::Hash API documentation} for details on all `Hash` methods.
Vector ({Immutable::Vector API Documentation})
A `Vector` is an integer-indexed collection much like an immutable `Array`. Examples:
``` ruby
vector = Immutable::Vector[1, 2, 3, 4] # => Immutable::Vector[1, 2, 3, 4]
vector[0] # => 1
vector[-1] # => 4
vector.set(1, :a) # => Immutable::Vector[1, :a, 3, 4]
vector.add(:b) # => Immutable::Vector[1, 2, 3, 4, :b]
vector.insert(2, :a, :b) # => Immutable::Vector[1, 2, :a, :b, 3, 4]
vector.delete_at(0) # => Immutable::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
{Immutable::Vector API documentation} for details on all `Vector` methods.
Set ({Immutable::Set API Documentation})
A `Set` is an unordered collection of values with no duplicates. It is much like the Ruby standard library's `Set`, but immutable. Examples:
``` ruby
set = Immutable::Set[:red, :blue, :yellow] # => Immutable::Set[:red, :blue, :yellow]
set.include? :red # => true
set.add :green # => Immutable::Set[:red, :blue, :yellow, :green]
set.delete :blue # => Immutable::Set[:red, :yellow]
set.superset? Immutable::Set[:red, :blue] # => true
set.union([:red, :blue, :pink]) # => Immutable::Set[:red, :blue, :yellow, :pink]
set.intersection([:red, :blue, :pink]) # => Immutable::Set[:red, :blue]
```
Like most immutable 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 immutable collections, `Immutable::Set` can easily be used in combination with "ordinary" Ruby code.
See the {Immutable::Set API documentation} for details on all `Set` methods.
SortedSet ({Immutable::SortedSet API Documentation})
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:
``` ruby
set = Immutable::SortedSet['toast', 'jam', 'bacon'] # => Immutable::SortedSet["bacon", "jam", "toast"]
set.first # => "bacon"
set.last # => "toast"
set[1] # => "jam"
```
You can also specify the sort order using a block:
``` ruby
Immutable::SortedSet.new(['toast', 'jam', 'bacon']) { |a,b| b <=> a }
Immutable::SortedSet.new(['toast', 'jam', 'bacon']) { |str| str.chars.last }
```
See the {Immutable::SortedSet API documentation} for details on all `SortedSet` methods.
List ({Immutable::List API Documentation})
`Immutable::List`s have a *head* (the value at the front of the list), and a *tail* (a list of the remaining items):
``` ruby
list = Immutable::List[1, 2, 3]
list.head # => 1
list.tail # => Immutable::List[2, 3]
```
Add to a list with {Immutable::List#add}:
``` ruby
original = Immutable::List[1, 2, 3]
copy = original.add(0) # => Immutable::List[0, 1, 2, 3]
```
Notice how modifying a list actually returns a new list.
### Laziness
`Immutable::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:
``` ruby
require 'prime'
Immutable.interval(10_000, 1_000_000).select do |number|
Prime.prime?(number)
end.take(3)
# => 0.0009s
```
Compare that to the conventional equivalent which needs to
calculate all possible values in the range before taking the
first three:
``` ruby
(10000..1000000).select do |number|
Prime.prime?(number)
end.take(3)
# => 10s
```
### Construction
Besides `Immutable::List[]` there are other ways to construct lists:
- {Immutable.interval Immutable.interval(from, to)} creates a lazy list
equivalent to a list containing all the values between
`from` and `to` without actually creating a list that big.
- {Immutable.stream Immutable.stream { ... }} allows you to creates infinite
lists. Each time a new value is required, the supplied
block is called. To generate a list of integers you could do:
``` ruby
count = 0
Immutable.stream { count += 1 }
```
- {Immutable.repeat Immutable.repeat(x)} creates an infinite list with `x` as the
value for every element.
- {Immutable.replicate Immutable.replicate(n, x)} creates a list of size `n` with
`x` as the value for every element.
- {Immutable.iterate Immutable.iterate(x) { |x| ... }} creates an infinite
list where the first item is calculated by applying the
block on the initial argument, the second item by applying
the function on the previous result and so on. For
example, a simpler way to generate a list of integers
would be:
``` ruby
Immutable.iterate(1) { |i| i + 1 }
```
or even more succinctly:
``` ruby
Immutable.iterate(1, &:next)
```
- {Immutable::List.empty} returns an empty list, which you can
build up using repeated calls to {Immutable::List#add #add} or other `List` methods.
### Core Extensions
{Enumerable#to_list} will convert any existing `Enumerable` to a list, so you can
slowly transition from built-in collection classes to immutable.
{IO#to_list} enables lazy processing of huge files. For example, imagine the
following code to process a 100MB file:
``` ruby
require 'immutable/core_ext'
File.open("my_100_mb_file.txt") do |file|
lines = []
file.each_line do |line|
break if lines.size == 10
lines << line.chomp.downcase.reverse
end
end
```
Compare to the following more functional version:
``` ruby
File.open("my_100_mb_file.txt") do |file|
file.map(&:chomp).map(&:downcase).map(&:reverse).take(10)
end
```
Unfortunately, though the second example reads nicely it takes many seconds to run (compared with milliseconds for the first) even though we're only interested in the first ten lines. Using `#to_list` we can get the running time back comparable to the imperative version.
``` ruby
File.open("my_100_mb_file.txt") do |file|
file.to_list.map(&:chomp).map(&:downcase).map(&:reverse).take(10)
end
```
This is possible because `IO#to_list` creates a lazy list whereby each line is
only ever read and processed as needed, in effect converting it to the first
example.
See the {Immutable::List API documentation} for details on all List methods.
Deque ({Immutable::Deque API Documentation})
A `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:
``` ruby
deque = Immutable::Deque[1, 2, 3] # => Immutable::Deque[1, 2, 3]
deque.first # 1
deque.last # 3
deque.pop # => Immutable::Deque[1, 2]
deque.push(:a) # => Immutable::Deque[1, 2, 3, :a]
deque.shift # => Immutable::Deque[2, 3]
deque.unshift(:a) # => Immutable::Deque[:a, 1, 2, 3]
```
Of course, you can do the same thing with a `Vector`, but a `Deque` is more efficient. See the {Immutable::Deque API documentation} for details on all Deque methods.
Other Reading
=============
- The structure which is used for `Immutable::Hash` and `Immutable::Set`: [Hash Array Mapped Tries][HAMT]
- An interesting perspective on why immutability itself is inherently a good thing: Matthias Felleisen's [Function Objects presentation][FO].
- The `immutable-ruby` {file:FAQ.md FAQ}
- {file:CONDUCT.md Contributor's Code of Conduct}
- {file:LICENSE License}
[HAMT]: http://lampwww.epfl.ch/papers/idealhashtrees.pdf
[FO]: https://web.archive.org/web/20200113172704/http://www.ccs.neu.edu/home/matthias/Presentations/ecoop2004.pdf
immutable-ruby-master/.ruby-version 0000644 0001750 0001750 00000000006 14201005456 017321 0 ustar boutil boutil 3.0.1
immutable-ruby-master/LICENSE 0000644 0001750 0001750 00000002072 14201005456 015666 0 ustar boutil boutil Licensing
=========
Copyright (c) 2009-2014 Simon Harris
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
immutable-ruby-master/.gitignore 0000644 0001750 0001750 00000001123 14201005456 016645 0 ustar boutil boutil # See http://help.github.com/ignore-files/ for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore
# Ignore all of the generated gem stuff
/pkg
/*.gem
# Ignore bundler config
/.bundle
/Gemfile.lock
# Ignore all bundler caching
/vendor/cache
/vendor/ruby
# Ignore all tempfiles
/tmp
# Ignores that should be in the global gitignore
/coverage
/doc
.yardoc
# Sublime Text
*.sublime-project
*.sublime-workspace immutable-ruby-master/immutable-ruby.gemspec 0000644 0001750 0001750 00000002465 14201005456 021172 0 ustar boutil boutil # coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'immutable/version'
Gem::Specification.new do |spec|
spec.name = 'immutable-ruby'
spec.version = Immutable::VERSION
spec.authors = ['Alex Dowad', 'Dov Murik', 'Xavier Shay', 'Simon Harris']
spec.email = ['alexinbeijing@gmail.com']
spec.summary = %q{Efficient, immutable, thread-safe collection classes for Ruby}
spec.description = spec.summary
spec.homepage = 'https://github.com/immutable-ruby/immutable-ruby'
spec.license = 'MIT'
spec.date = Time.now.strftime('%Y-%m-%d')
spec.platform = Gem::Platform::RUBY
spec.required_ruby_version = '>= 2.4.0'
spec.files = Dir['lib/**/*']
spec.require_paths = ['lib']
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.1'
spec.add_runtime_dependency 'sorted_set', '~> 1.0'
spec.add_development_dependency 'bundler', '>= 2.2.10'
spec.add_development_dependency 'rspec', '~> 3.9'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'yard', '~> 0.9'
spec.add_development_dependency 'pry', '~> 0.13'
spec.add_development_dependency 'pry-doc', '~> 1.0.0'
spec.add_development_dependency 'benchmark-ips', '~> 2.7'
end
immutable-ruby-master/bench/ 0000755 0001750 0001750 00000000000 14201005456 015737 5 ustar boutil boutil immutable-ruby-master/bench/set/ 0000755 0001750 0001750 00000000000 14201005456 016532 5 ustar boutil boutil immutable-ruby-master/bench/set/union_bench.rb 0000644 0001750 0001750 00000000474 14201005456 021353 0 ustar boutil boutil require 'benchmark/ips'
require 'immutable/set'
Benchmark.ips do |b|
small_set = Immutable::Set.new((1..10).to_a)
large_set = Immutable::Set.new((1..1000).to_a)
b.report 'small.union(large)' do
small_set.union(large_set)
end
b.report 'large.union(small)' do
large_set.union(small_set)
end
end
immutable-ruby-master/bench/hash/ 0000755 0001750 0001750 00000000000 14201005456 016662 5 ustar boutil boutil immutable-ruby-master/bench/hash/get_bench.rb 0000644 0001750 0001750 00000002063 14201005456 021126 0 ustar boutil boutil require 'benchmark/ips'
require 'immutable/hash'
Benchmark.ips do |b|
sml_hash = Immutable::Hash[1 => 1]
med_hash = Immutable::Hash.empty
1_000.times { |i| med_hash = med_hash.put(i, i) }
lrg_hash = Immutable::Hash.empty
1_000_000.times { |i| lrg_hash = lrg_hash.put(i, i) }
b.report 'get existing small' do |n|
a = 0
x = 0
while a < n
x = sml_hash.get(a)
a += 1
end
end
b.report 'get existing medium' do |n|
a = 0
x = nil
while a < n
x = med_hash.get(a)
a += 1
end
end
b.report 'get existing large' do |n|
a = 0
x = nil
while a < n
x = lrg_hash.get(a)
a += 1
end
end
b.report 'get missing small' do |n|
a = 0
x = 0
while a < n
x = sml_hash.get(-1)
a += 1
end
end
b.report 'get missing medium' do |n|
a = 0
x = nil
while a < n
x = med_hash.get(-1)
a += 1
end
end
b.report 'get missing large' do |n|
a = 0
x = nil
while a < n
x = lrg_hash.get(-1)
a += 1
end
end
end
immutable-ruby-master/bench/hash/each_bench.rb 0000644 0001750 0001750 00000001246 14201005456 021251 0 ustar boutil boutil require 'benchmark/ips'
require 'immutable/hash'
Benchmark.ips do |b|
sml_hash = Immutable::Hash[1 => 1]
med_hash = Immutable::Hash.empty
1_000.times { |i| med_hash = med_hash.put(i, i) }
lrg_hash = Immutable::Hash.empty
1_000_000.times { |i| lrg_hash = lrg_hash.put(i, i) }
b.report 'each small' do |n|
a = 0
x = 0
while a < n
sml_hash.each { |y| x = y }
a += 1
end
end
b.report 'each medium' do |n|
a = 0
x = 0
while a < n
med_hash.each { |y| x = y }
a += 1
end
end
b.report 'each large' do |n|
a = 0
x = 0
while a < n
lrg_hash.each { |y| x = y }
a += 1
end
end
end
immutable-ruby-master/bench/hash/put_bench.rb 0000644 0001750 0001750 00000001262 14201005456 021157 0 ustar boutil boutil require 'benchmark/ips'
require 'immutable/hash'
Benchmark.ips do |b|
sml_hash = Immutable::Hash[1 => 1]
med_hash = Immutable::Hash.empty
1_000.times { |i| med_hash = med_hash.put(i, i) }
lrg_hash = Immutable::Hash.empty
1_000_000.times { |i| lrg_hash = lrg_hash.put(i, i) }
b.report 'put value' do |n|
a = 0
sml = sml_hash
while a < n
sml = sml.put(a, a)
a += 1
end
end
b.report 'put value medium' do |n|
a = 0
med = med_hash
while a < n
med = med.put(a, a)
a += 1
end
end
b.report 'put value large' do |n|
a = 0
lrg = lrg_hash
while a < n
lrg = lrg.put(a, a)
a += 1
end
end
end
immutable-ruby-master/bench/list/ 0000755 0001750 0001750 00000000000 14201005456 016712 5 ustar boutil boutil immutable-ruby-master/bench/list/at_bench.rb 0000644 0001750 0001750 00000001350 14201005456 021001 0 ustar boutil boutil require 'benchmark/ips'
require 'immutable/list'
Benchmark.ips do |b|
sml_list = Immutable::List[1]
# med_list = Immutable.iterate(1, &:next).take(100)
# lrg_list = Immutable.iterate(1, &:next).take(10000)
med_list = Immutable::List.empty
100.times { |i| med_list = med_list.cons(i) }
lrg_list = Immutable::List.empty
10000.times { |i| lrg_list = lrg_list.cons(i) }
b.report 'at small' do |n|
a = 0
x = 0
while a < n
x = sml_list.at(0)
a += 1
end
end
b.report 'at medium' do |n|
a = 0
x = 0
while a < n
x = med_list.at(99)
a += 1
end
end
b.report 'at large' do |n|
a = 0
x = 0
while a < n
x = lrg_list.at(9999)
a += 1
end
end
end
immutable-ruby-master/bench/list/cons_bench.rb 0000644 0001750 0001750 00000001224 14201005456 021337 0 ustar boutil boutil require 'benchmark/ips'
require 'immutable/list'
Benchmark.ips do |b|
sml_list = Immutable::List[1]
med_list = Immutable::List.empty
100.times { |i| med_list = med_list.cons(i) }
lrg_list = Immutable::List.empty
10000.times { |i| lrg_list = lrg_list.cons(i) }
b.report 'cons small' do |n|
a = 0
sml = sml_list
while a < n
sml = sml.cons(a)
a += 1
end
end
b.report 'cons medium' do |n|
a = 0
med = med_list
while a < n
med = med.cons(a)
a += 1
end
end
b.report 'cons large' do |n|
a = 0
lrg = lrg_list
while a < n
lrg = lrg.cons(a)
a += 1
end
end
end
immutable-ruby-master/spec/ 0000755 0001750 0001750 00000000000 14201005456 015612 5 ustar boutil boutil immutable-ruby-master/spec/spec_helper.rb 0000644 0001750 0001750 00000003306 14201005456 020432 0 ustar boutil boutil require 'pry'
require 'rspec'
require 'immutable/hash'
require 'immutable/set'
require 'immutable/vector'
require 'immutable/sorted_set'
require 'immutable/list'
require 'immutable/deque'
require 'immutable/core_ext'
require 'immutable/nested'
# Suppress warnings from use of old RSpec expectation and mock syntax
# If all tests are eventually updated to use the new syntax, this can be removed
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
config.mock_with :rspec do |c|
c.syntax = [:should, :expect]
end
end
V = Immutable::Vector
L = Immutable::List
H = Immutable::Hash
S = Immutable::Set
SS = Immutable::SortedSet
D = Immutable::Deque
EmptyList = Immutable::EmptyList
Struct.new('Customer', :name, :address)
def fixture(name)
File.read(fixture_path(name))
end
def fixture_path(name)
File.join('spec', 'fixtures', name)
end
if RUBY_ENGINE == 'ruby'
def calculate_stack_overflow_depth(n)
calculate_stack_overflow_depth(n + 1)
rescue SystemStackError
n
end
STACK_OVERFLOW_DEPTH = calculate_stack_overflow_depth(2)
else
STACK_OVERFLOW_DEPTH = 16_384
end
BigList = Immutable.interval(0, STACK_OVERFLOW_DEPTH)
class DeterministicHash
attr_reader :hash, :value
def initialize(value, hash)
@value = value
@hash = hash
end
def to_s
@value.to_s
end
def inspect
@value.inspect
end
def ==(other)
other.is_a?(DeterministicHash) && value == other.value
end
alias eql? ==
def <=>(other)
value <=> other.value
end
end
class EqualNotEql
def ==(other)
true
end
def eql?(other)
false
end
end
class EqlNotEqual
def ==(other)
false
end
def eql?(other)
true
end
end
immutable-ruby-master/spec/fixtures/ 0000755 0001750 0001750 00000000000 14201005456 017463 5 ustar boutil boutil immutable-ruby-master/spec/fixtures/io_spec.txt 0000644 0001750 0001750 00000000006 14201005456 021641 0 ustar boutil boutil A
B
C
immutable-ruby-master/spec/lib/ 0000755 0001750 0001750 00000000000 14201005456 016360 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/ 0000755 0001750 0001750 00000000000 14201005456 020337 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/sorted_set/ 0000755 0001750 0001750 00000000000 14201005456 022512 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/sorted_set/intersect_spec.rb 0000644 0001750 0001750 00000001224 14201005456 026050 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#intersect?' do
[
[[], [], false],
[['A'], [], false],
[[], ['A'], false],
[['A'], ['A'], true],
[%w[A B C], ['B'], true],
[['B'], %w[A B C], true],
[%w[A B C], %w[D E], false],
[%w[F G H I], %w[A B C], false],
[%w[A B C], %w[A B C], true],
[%w[A B C], %w[A B C D], true],
[%w[D E F G], %w[A B C], false],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
SS[*a].intersect?(SS[*b]).should be(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/new_spec.rb 0000644 0001750 0001750 00000010166 14201005456 024646 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '.new' do
it 'accepts a single enumerable argument and creates a new sorted set' do
sorted_set = SS.new([1,2,3])
sorted_set.size.should be(3)
sorted_set[0].should be(1)
sorted_set[1].should be(2)
sorted_set[2].should be(3)
end
it 'also works with a Range' do
sorted_set = SS.new(1..3)
sorted_set.size.should be(3)
sorted_set[0].should be(1)
sorted_set[1].should be(2)
sorted_set[2].should be(3)
end
it "doesn't mutate the initializer" do
array = [3,2,1,3,2,1] # this will need to be sorted and duplicates filtered out
sorted_set = SS.new(array)
expect(array).to eq([3,2,1,3,2,1])
end
it "doesn't change if the initializer is later mutated" do
array = [3,2,1,3,2,1]
sorted_set = SS.new(array)
array.clear
expect(sorted_set.to_a).to eq([1,2,3])
end
it 'is amenable to overriding of #initialize' do
class SnazzySortedSet < Immutable::SortedSet
def initialize
super(['SNAZZY!!!'])
end
end
sorted_set = SnazzySortedSet.new
sorted_set.size.should be(1)
sorted_set.to_a.should == ['SNAZZY!!!']
end
it 'accepts a block with arity 1' do
sorted_set = SS.new(1..3, &:-@)
sorted_set[0].should be(3)
sorted_set[1].should be(2)
sorted_set[2].should be(1)
end
it 'accepts a block with arity 2' do
sorted_set = SS.new(1..3) { |a,b| b <=> a }
sorted_set[0].should be(3)
sorted_set[1].should be(2)
sorted_set[2].should be(1)
end
it 'can use a block produced by Symbol#to_proc' do
sorted_set = SS.new([Object, BasicObject], &:name.to_proc)
sorted_set[0].should be(BasicObject)
sorted_set[1].should be(Object)
end
it 'filters out duplicates' do
sorted_set = SS.new(['a', 'b', 'a', 'c', 'b', 'a', 'c', 'c'])
expect(sorted_set.size).to be(3)
end
context 'when passed a comparator with arity 2' do
it 'still filters out duplicates' do
sorted_set = SS.new([1,2,7,8,9,10]) { |x,y| (x%7) <=> (y%7) }
expect(sorted_set.to_a).to eq([7,1,2,10])
end
it "still doesn't mutate the initializer" do
array = [3,2,1,3,2,1] # this will need to be sorted and duplicates filtered out
sorted_set = SS.new(array) { |x,y| y <=> x }
expect(array).to eq([3,2,1,3,2,1])
end
it "still doesn't change if the initializer is later mutated" do
array = [3,2,1,3,2,1]
sorted_set = SS.new(array) { |x,y| y <=> x }
array.clear
expect(sorted_set.to_a).to eq([3,2,1])
end
end
context 'when passed a block with arity 1' do
it 'still filters out duplicates' do
sorted_set = SS.new([1,2,7,8,9,10]) { |x| x % 7 }
expect(sorted_set.to_a).to eq([7,1,2,10])
end
it "still doesn't mutate the initializer" do
array = [3,2,1,3,2,1] # this will need to be sorted and duplicates filtered out
sorted_set = SS.new(array) { |x| x % 7 }
expect(array).to eq([3,2,1,3,2,1])
end
it "still doesn't change if the initializer is later mutated" do
array = [3,2,1,3,2,1]
sorted_set = SS.new(array) { |x| x % 7 }
array.clear
expect(sorted_set.to_a).to eq([1,2,3])
end
end
context 'from a subclass' do
it 'returns a frozen instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
instance = subclass.new(['some', 'values'])
instance.class.should be subclass
instance.frozen?.should be true
end
end
end
describe '.[]' do
it 'accepts a variable number of items and creates a new sorted set' do
sorted_set = SS['a', 'b']
sorted_set.size.should be(2)
sorted_set[0].should == 'a'
sorted_set[1].should == 'b'
end
it 'filters out duplicate items' do
sorted_set = SS['a', 'b', 'a', 'c', 'b', 'a', 'c', 'c']
expect(sorted_set.size).to be(3)
sorted_set[0].should == 'a'
sorted_set[1].should == 'b'
sorted_set[2].should == 'c'
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/at_spec.rb 0000644 0001750 0001750 00000001100 14201005456 024445 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#at' do
[
[[], 10, nil],
[['A'], 10, nil],
[%w[A B C], 0, 'A'],
[%w[A B C], 1, 'B'],
[%w[A B C], 2, 'C'],
[%w[A B C], 3, nil],
[%w[A B C], -1, 'C'],
[%w[A B C], -2, 'B'],
[%w[A B C], -3, 'A'],
[%w[A B C], -4, nil]
].each do |values, number, expected|
describe "#{values.inspect} with #{number}" do
it "returns #{expected.inspect}" do
SS[*values].at(number).should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/delete_at_spec.rb 0000644 0001750 0001750 00000001034 14201005456 025775 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#delete_at' do
let(:sorted_set) { SS[1,2,3,4,5] }
it 'removes the element at the specified index' do
sorted_set.delete_at(0).should eql(SS[2,3,4,5])
sorted_set.delete_at(2).should eql(SS[1,2,4,5])
sorted_set.delete_at(-1).should eql(SS[1,2,3,4])
end
it 'makes no modification if the index is out of range' do
sorted_set.delete_at(5).should eql(sorted_set)
sorted_set.delete_at(-6).should eql(sorted_set)
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/size_spec.rb 0000644 0001750 0001750 00000000563 14201005456 025027 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:size, :length].each do |method|
describe "##{method}" do
[
[[], 0],
[['A'], 1],
[%w[A B C], 3],
].each do |values, result|
it "returns #{result} for #{values.inspect}" do
SS[*values].send(method).should == result
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/above_spec.rb 0000644 0001750 0001750 00000003112 14201005456 025142 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#above' do
context 'when called without a block' do
it 'returns a sorted set of all items higher than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = set.above(threshold)
array = items.select { |x| x > threshold }.sort
result.class.should be(Immutable::SortedSet)
result.size.should == array.size
result.to_a.should == array
end
end
end
context 'when called with a block' do
it 'yields all the items higher than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = []
set.above(threshold) { |x| result << x }
array = items.select { |x| x > threshold }.sort
result.size.should == array.size
result.should == array
end
end
end
context 'on an empty set' do
it 'returns an empty set' do
SS.empty.above(1).should be_empty
SS.empty.above('abc').should be_empty
SS.empty.above(:symbol).should be_empty
end
end
context 'with an argument higher than all the values in the set' do
it 'returns an empty set' do
result = SS.new(1..100).above(100)
result.class.should be(Immutable::SortedSet)
result.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/drop_spec.rb 0000644 0001750 0001750 00000002727 14201005456 025025 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#drop' do
[
[[], 0, []],
[[], 10, []],
[['A'], 10, []],
[%w[A B C], 0, %w[A B C]],
[%w[A B C], 1, %w[B C]],
[%w[A B C], 2, ['C']],
[%w[A B C], 3, []]
].each do |values, number, expected|
context "#{number} from #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it 'preserves the original' do
sorted_set.drop(number)
sorted_set.should eql(SS[*values])
end
it "returns #{expected.inspect}" do
sorted_set.drop(number).should eql(SS[*expected])
end
end
end
context 'when argument is zero' do
let(:sorted_set) { SS[6, 7, 8, 9] }
it 'returns self' do
sorted_set.drop(0).should be(sorted_set)
end
end
context 'when the set has a custom order' do
let(:sorted_set) { SS.new([1, 2, 3], &:-@)}
it 'maintains the custom order' do
sorted_set.drop(1).to_a.should == [2, 1]
sorted_set.drop(2).to_a.should == [1]
end
it 'keeps the comparator even when set is cleared' do
s = sorted_set.drop(3)
s.add(4).add(5).add(6).to_a.should == [6, 5, 4]
end
end
context 'when called on a subclass' do
it 'should return an instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
subclass.new([1,2,3]).drop(1).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/take_while_spec.rb 0000644 0001750 0001750 00000001603 14201005456 026165 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#take_while' do
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
sorted_set.take_while { |item| item < 'C' }.should eql(SS[*expected])
end
it 'preserves the original' do
sorted_set.take_while { |item| item < 'C' }
sorted_set.should eql(SS[*values])
end
end
context 'without a block' do
it 'returns an Enumerator' do
sorted_set.take_while.class.should be(Enumerator)
sorted_set.take_while.each { |item| item < 'C' }.should eql(SS[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/sample_spec.rb 0000644 0001750 0001750 00000000606 14201005456 025334 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#sample' do
let(:sorted_set) { Immutable::SortedSet.new(1..10) }
it 'returns a randomly chosen item' do
chosen = 100.times.map { sorted_set.sample }
chosen.each { |item| sorted_set.include?(item).should == true }
sorted_set.each { |item| chosen.include?(item).should == true }
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/subset_spec.rb 0000644 0001750 0001750 00000002346 14201005456 025363 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#subset?' do
[
[[], [], true],
[['A'], [], false],
[[], ['A'], true],
[['A'], ['A'], true],
[%w[A B C], ['B'], false],
[['B'], %w[A B C], true],
[%w[A B C], %w[A C], false],
[%w[A C], %w[A B C], true],
[%w[A B C], %w[A B C], true],
[%w[A B C], %w[A B C D], true],
[%w[A B C D], %w[A B C], false],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
SS[*a].subset?(SS[*b]).should == expected
end
end
end
end
describe '#proper_subset?' do
[
[[], [], false],
[['A'], [], false],
[[], ['A'], true],
[['A'], ['A'], false],
[%w[A B C], ['B'], false],
[['B'], %w[A B C], true],
[%w[A B C], %w[A C], false],
[%w[A C], %w[A B C], true],
[%w[A B C], %w[A B C], false],
[%w[A B C], %w[A B C D], true],
[%w[A B C D], %w[A B C], false],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
SS[*a].proper_subset?(SS[*b]).should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/minimum_spec.rb 0000644 0001750 0001750 00000000643 14201005456 025527 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#min' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
[[1,2,3,4,5], 1],
[[0, -0.0, 2.2, -4, -4.2], -4.2],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
SS[*values].min.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/inspect_spec.rb 0000644 0001750 0001750 00000002040 14201005456 025512 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#inspect' do
[
[[], 'Immutable::SortedSet[]'],
[['A'], 'Immutable::SortedSet["A"]'],
[['C', 'B', 'A'], 'Immutable::SortedSet["A", "B", "C"]']
].each do |values, expected|
context "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it "returns #{expected.inspect}" do
sorted_set.inspect.should == expected
end
it "returns a string which can be eval'd to get an equivalent set" do
eval(sorted_set.inspect).should eql(sorted_set)
end
end
end
MySortedSet = Class.new(Immutable::SortedSet)
context 'from a subclass' do
let(:sorted_set) { MySortedSet[1, 2] }
it 'returns a programmer-readable representation of the set contents' do
sorted_set.inspect.should == 'MySortedSet[1, 2]'
end
it "returns a string which can be eval'd to get an equivalent set" do
eval(sorted_set.inspect).should eql(sorted_set)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/marshal_spec.rb 0000644 0001750 0001750 00000002123 14201005456 025476 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#marshal_dump/#marshal_load' do
let(:ruby) do
File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
end
let(:child_cmd) do
%Q|#{ruby} -I lib -r immutable -e 'set = Immutable::SortedSet[5, 10, 15]; $stdout.write(Marshal.dump(set))'|
end
let(:reloaded_set) do
IO.popen(child_cmd, 'r+') do |child|
reloaded_set = Marshal.load(child)
child.close
reloaded_set
end
end
it 'can survive dumping and loading into a new process' do
expect(reloaded_set).to eql(SS[5, 10, 15])
end
it 'is still possible to find items by index after loading' do
expect(reloaded_set[0]).to eq(5)
expect(reloaded_set[1]).to eq(10)
expect(reloaded_set[2]).to eq(15)
expect(reloaded_set.size).to eq(3)
end
it 'raises a TypeError if set has a custom sort order' do
# this is because comparator block can't be serialized
-> { Marshal.dump(SS.new([1, 2, 3], &:-@)) }.should raise_error(TypeError)
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/empty_spec.rb 0000644 0001750 0001750 00000001457 14201005456 025216 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#empty?' do
[
[[], true],
[['A'], false],
[%w[A B C], false],
].each do |values, expected|
context "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it "returns #{expected.inspect}" do
sorted_set.empty?.should == expected
end
end
end
end
describe '.empty' do
it 'returns the canonical empty set' do
SS.empty.size.should be(0)
SS.empty.object_id.should be(SS.empty.object_id)
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
subclass.empty.class.should be(subclass)
subclass.empty.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/fetch_spec.rb 0000644 0001750 0001750 00000004132 14201005456 025142 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#fetch' do
let(:sorted_set) { SS['a', 'b', 'c'] }
context 'with no default provided' do
context 'when the index exists' do
it 'returns the value at the index' do
sorted_set.fetch(0).should == 'a'
sorted_set.fetch(1).should == 'b'
sorted_set.fetch(2).should == 'c'
end
end
context 'when the key does not exist' do
it 'raises an IndexError' do
-> { sorted_set.fetch(3) }.should raise_error(IndexError)
-> { sorted_set.fetch(-4) }.should raise_error(IndexError)
end
end
end
context 'with a default value' do
context 'when the index exists' do
it 'returns the value at the index' do
sorted_set.fetch(0, 'default').should == 'a'
sorted_set.fetch(1, 'default').should == 'b'
sorted_set.fetch(2, 'default').should == 'c'
end
end
context 'when the index does not exist' do
it 'returns the default value' do
sorted_set.fetch(3, 'default').should == 'default'
sorted_set.fetch(-4, 'default').should == 'default'
end
end
end
context 'with a default block' do
context 'when the index exists' do
it 'returns the value at the index' do
sorted_set.fetch(0) { 'default'.upcase }.should == 'a'
sorted_set.fetch(1) { 'default'.upcase }.should == 'b'
sorted_set.fetch(2) { 'default'.upcase }.should == 'c'
end
end
context 'when the index does not exist' do
it 'invokes the block with the missing index as parameter' do
sorted_set.fetch(3) { |index| index.should == 3 }
sorted_set.fetch(-4) { |index| index.should == -4 }
sorted_set.fetch(3) { 'default'.upcase }.should == 'DEFAULT'
sorted_set.fetch(-4) { 'default'.upcase }.should == 'DEFAULT'
end
end
end
it 'gives precedence to default block over default argument if passed both' do
sorted_set.fetch(3, 'one') { 'two' }.should == 'two'
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/each_spec.rb 0000644 0001750 0001750 00000001245 14201005456 024753 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#each' do
context 'with no block' do
let(:sorted_set) { SS['A', 'B', 'C'] }
it 'returns an Enumerator' do
sorted_set.each.class.should be(Enumerator)
sorted_set.each.to_a.should eql(sorted_set.to_a)
end
end
context 'with a block' do
let(:sorted_set) { SS.new((1..1025).to_a.reverse) }
it 'returns self' do
sorted_set.each {}.should be(sorted_set)
end
it 'iterates over the items in order' do
items = []
sorted_set.each { |item| items << item }
items.should == (1..1025).to_a
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/last_spec.rb 0000644 0001750 0001750 00000001340 14201005456 025012 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
let(:sorted_set) { SS[*values] }
describe '#last' do
let(:last) { sorted_set.last }
shared_examples 'checking values' do
it 'returns the last item' do
expect(last).to eq(last_item)
end
end
context 'with an empty set' do
let(:last_item) { nil }
let(:values) { [] }
include_examples 'checking values'
end
context 'with a single item set' do
let(:last_item) { 'A' }
let(:values) { %w[A] }
include_examples 'checking values'
end
context 'with a multi-item set' do
let(:last_item) { 'B' }
let(:values) { %w[B A] }
include_examples 'checking values'
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/delete_spec.rb 0000644 0001750 0001750 00000005001 14201005456 025307 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
let(:sorted_set) { SS['A', 'B', 'C'] }
describe '#delete' do
context 'on an empty set' do
it 'returns an empty set' do
SS.empty.delete(0).should be(SS.empty)
end
end
context 'with an existing value' do
it 'preserves the original' do
sorted_set.delete('B')
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns a copy with the remaining of values' do
sorted_set.delete('B').should eql(SS['A', 'C'])
end
end
context 'with a non-existing value' do
it 'preserves the original values' do
sorted_set.delete('D')
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns self' do
sorted_set.delete('D').should equal(sorted_set)
end
end
context 'when removing the last value in a sorted set' do
it 'maintains the set order' do
ss = SS.new(['peanuts', 'jam', 'milk'], &:length)
ss = ss.delete('jam').delete('peanuts').delete('milk')
ss = ss.add('banana').add('sugar').add('spam')
ss.to_a.should == ['spam', 'sugar', 'banana']
end
context 'when the set is in natural order' do
it 'returns the canonical empty set' do
sorted_set.delete('B').delete('C').delete('A').should be(Immutable::EmptySortedSet)
end
end
end
1.upto(10) do |n|
values = (1..n).to_a
values.combination(3) do |to_delete|
expected = to_delete.reduce(values.dup) { |ary,val| ary.delete(val); ary }
describe "on #{values.inspect}, when deleting #{to_delete.inspect}" do
it "returns #{expected.inspect}" do
set = SS.new(values)
result = to_delete.reduce(set) { |s,val| s.delete(val) }
result.should eql(SS.new(expected))
result.to_a.should eql(expected)
end
end
end
end
end
describe '#delete?' do
context 'with an existing value' do
it 'preserves the original' do
sorted_set.delete?('B')
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns a copy with the remaining values' do
sorted_set.delete?('B').should eql(SS['A', 'C'])
end
end
context 'with a non-existing value' do
it 'preserves the original values' do
sorted_set.delete?('D')
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns false' do
sorted_set.delete?('D').should be(false)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/slice_spec.rb 0000644 0001750 0001750 00000030363 14201005456 025155 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
let(:sorted_set) { SS[1,2,3,4] }
let(:big) { SS.new(1..10000) }
[:slice, :[]].each do |method|
describe "##{method}" do
context 'when passed a positive integral index' do
it 'returns the element at that index' do
sorted_set.send(method, 0).should be(1)
sorted_set.send(method, 1).should be(2)
sorted_set.send(method, 2).should be(3)
sorted_set.send(method, 3).should be(4)
sorted_set.send(method, 4).should be(nil)
sorted_set.send(method, 10).should be(nil)
big.send(method, 0).should be(1)
big.send(method, 9999).should be(10000)
end
it 'leaves the original unchanged' do
sorted_set.should eql(SS[1,2,3,4])
end
end
context 'when passed a negative integral index' do
it 'returns the element which is number (index.abs) counting from the end of the sorted_set' do
sorted_set.send(method, -1).should be(4)
sorted_set.send(method, -2).should be(3)
sorted_set.send(method, -3).should be(2)
sorted_set.send(method, -4).should be(1)
sorted_set.send(method, -5).should be(nil)
sorted_set.send(method, -10).should be(nil)
big.send(method, -1).should be(10000)
big.send(method, -10000).should be(1)
end
end
context 'when passed a positive integral index and count' do
it "returns 'count' elements starting from 'index'" do
sorted_set.send(method, 0, 0).should eql(SS.empty)
sorted_set.send(method, 0, 1).should eql(SS[1])
sorted_set.send(method, 0, 2).should eql(SS[1,2])
sorted_set.send(method, 0, 4).should eql(SS[1,2,3,4])
sorted_set.send(method, 0, 6).should eql(SS[1,2,3,4])
sorted_set.send(method, 0, -1).should be_nil
sorted_set.send(method, 0, -2).should be_nil
sorted_set.send(method, 0, -4).should be_nil
sorted_set.send(method, 2, 0).should eql(SS.empty)
sorted_set.send(method, 2, 1).should eql(SS[3])
sorted_set.send(method, 2, 2).should eql(SS[3,4])
sorted_set.send(method, 2, 4).should eql(SS[3,4])
sorted_set.send(method, 2, -1).should be_nil
sorted_set.send(method, 4, 0).should eql(SS.empty)
sorted_set.send(method, 4, 2).should eql(SS.empty)
sorted_set.send(method, 4, -1).should be_nil
sorted_set.send(method, 5, 0).should be_nil
sorted_set.send(method, 5, 2).should be_nil
sorted_set.send(method, 5, -1).should be_nil
sorted_set.send(method, 6, 0).should be_nil
sorted_set.send(method, 6, 2).should be_nil
sorted_set.send(method, 6, -1).should be_nil
big.send(method, 0, 3).should eql(SS[1,2,3])
big.send(method, 1023, 4).should eql(SS[1024,1025,1026,1027])
big.send(method, 1024, 4).should eql(SS[1025,1026,1027,1028])
end
it 'leaves the original unchanged' do
sorted_set.should eql(SS[1,2,3,4])
end
end
context 'when passed a negative integral index and count' do
it "returns 'count' elements, starting from index which is number 'index.abs' counting from the end of the array" do
sorted_set.send(method, -1, 0).should eql(SS.empty)
sorted_set.send(method, -1, 1).should eql(SS[4])
sorted_set.send(method, -1, 2).should eql(SS[4])
sorted_set.send(method, -1, -1).should be_nil
sorted_set.send(method, -2, 0).should eql(SS.empty)
sorted_set.send(method, -2, 1).should eql(SS[3])
sorted_set.send(method, -2, 2).should eql(SS[3,4])
sorted_set.send(method, -2, 4).should eql(SS[3,4])
sorted_set.send(method, -2, -1).should be_nil
sorted_set.send(method, -4, 0).should eql(SS.empty)
sorted_set.send(method, -4, 1).should eql(SS[1])
sorted_set.send(method, -4, 2).should eql(SS[1,2])
sorted_set.send(method, -4, 4).should eql(SS[1,2,3,4])
sorted_set.send(method, -4, 6).should eql(SS[1,2,3,4])
sorted_set.send(method, -4, -1).should be_nil
sorted_set.send(method, -5, 0).should be_nil
sorted_set.send(method, -5, 1).should be_nil
sorted_set.send(method, -5, 10).should be_nil
sorted_set.send(method, -5, -1).should be_nil
big.send(method, -1, 1).should eql(SS[10000])
big.send(method, -1, 2).should eql(SS[10000])
big.send(method, -6, 2).should eql(SS[9995,9996])
end
end
context 'when passed a Range' do
it 'returns the elements whose indexes are within the given Range' do
sorted_set.send(method, 0..-1).should eql(SS[1,2,3,4])
sorted_set.send(method, 0..-10).should eql(SS.empty)
sorted_set.send(method, 0..0).should eql(SS[1])
sorted_set.send(method, 0..1).should eql(SS[1,2])
sorted_set.send(method, 0..2).should eql(SS[1,2,3])
sorted_set.send(method, 0..3).should eql(SS[1,2,3,4])
sorted_set.send(method, 0..4).should eql(SS[1,2,3,4])
sorted_set.send(method, 0..10).should eql(SS[1,2,3,4])
sorted_set.send(method, 2..-10).should eql(SS.empty)
sorted_set.send(method, 2..0).should eql(SS.empty)
sorted_set.send(method, 2..2).should eql(SS[3])
sorted_set.send(method, 2..3).should eql(SS[3,4])
sorted_set.send(method, 2..4).should eql(SS[3,4])
sorted_set.send(method, 3..0).should eql(SS.empty)
sorted_set.send(method, 3..3).should eql(SS[4])
sorted_set.send(method, 3..4).should eql(SS[4])
sorted_set.send(method, 4..0).should eql(SS.empty)
sorted_set.send(method, 4..4).should eql(SS.empty)
sorted_set.send(method, 4..5).should eql(SS.empty)
sorted_set.send(method, 5..0).should be_nil
sorted_set.send(method, 5..5).should be_nil
sorted_set.send(method, 5..6).should be_nil
big.send(method, 159..162).should eql(SS[160,161,162,163])
big.send(method, 160..162).should eql(SS[161,162,163])
big.send(method, 161..162).should eql(SS[162,163])
big.send(method, 9999..10100).should eql(SS[10000])
big.send(method, 10000..10100).should eql(SS.empty)
big.send(method, 10001..10100).should be_nil
sorted_set.send(method, 0...-1).should eql(SS[1,2,3])
sorted_set.send(method, 0...-10).should eql(SS.empty)
sorted_set.send(method, 0...0).should eql(SS.empty)
sorted_set.send(method, 0...1).should eql(SS[1])
sorted_set.send(method, 0...2).should eql(SS[1,2])
sorted_set.send(method, 0...3).should eql(SS[1,2,3])
sorted_set.send(method, 0...4).should eql(SS[1,2,3,4])
sorted_set.send(method, 0...10).should eql(SS[1,2,3,4])
sorted_set.send(method, 2...-10).should eql(SS.empty)
sorted_set.send(method, 2...0).should eql(SS.empty)
sorted_set.send(method, 2...2).should eql(SS.empty)
sorted_set.send(method, 2...3).should eql(SS[3])
sorted_set.send(method, 2...4).should eql(SS[3,4])
sorted_set.send(method, 3...0).should eql(SS.empty)
sorted_set.send(method, 3...3).should eql(SS.empty)
sorted_set.send(method, 3...4).should eql(SS[4])
sorted_set.send(method, 4...0).should eql(SS.empty)
sorted_set.send(method, 4...4).should eql(SS.empty)
sorted_set.send(method, 4...5).should eql(SS.empty)
sorted_set.send(method, 5...0).should be_nil
sorted_set.send(method, 5...5).should be_nil
sorted_set.send(method, 5...6).should be_nil
big.send(method, 159...162).should eql(SS[160,161,162])
big.send(method, 160...162).should eql(SS[161,162])
big.send(method, 161...162).should eql(SS[162])
big.send(method, 9999...10100).should eql(SS[10000])
big.send(method, 10000...10100).should eql(SS.empty)
big.send(method, 10001...10100).should be_nil
sorted_set.send(method, -1..-1).should eql(SS[4])
sorted_set.send(method, -1...-1).should eql(SS.empty)
sorted_set.send(method, -1..3).should eql(SS[4])
sorted_set.send(method, -1...3).should eql(SS.empty)
sorted_set.send(method, -1..4).should eql(SS[4])
sorted_set.send(method, -1...4).should eql(SS[4])
sorted_set.send(method, -1..10).should eql(SS[4])
sorted_set.send(method, -1...10).should eql(SS[4])
sorted_set.send(method, -1..0).should eql(SS.empty)
sorted_set.send(method, -1..-4).should eql(SS.empty)
sorted_set.send(method, -1...-4).should eql(SS.empty)
sorted_set.send(method, -1..-6).should eql(SS.empty)
sorted_set.send(method, -1...-6).should eql(SS.empty)
sorted_set.send(method, -2..-2).should eql(SS[3])
sorted_set.send(method, -2...-2).should eql(SS.empty)
sorted_set.send(method, -2..-1).should eql(SS[3,4])
sorted_set.send(method, -2...-1).should eql(SS[3])
sorted_set.send(method, -2..10).should eql(SS[3,4])
sorted_set.send(method, -2...10).should eql(SS[3,4])
big.send(method, -1..-1).should eql(SS[10000])
big.send(method, -1..9999).should eql(SS[10000])
big.send(method, -1...9999).should eql(SS.empty)
big.send(method, -2...9999).should eql(SS[9999])
big.send(method, -2..-1).should eql(SS[9999,10000])
sorted_set.send(method, -4..-4).should eql(SS[1])
sorted_set.send(method, -4..-2).should eql(SS[1,2,3])
sorted_set.send(method, -4...-2).should eql(SS[1,2])
sorted_set.send(method, -4..-1).should eql(SS[1,2,3,4])
sorted_set.send(method, -4...-1).should eql(SS[1,2,3])
sorted_set.send(method, -4..3).should eql(SS[1,2,3,4])
sorted_set.send(method, -4...3).should eql(SS[1,2,3])
sorted_set.send(method, -4..4).should eql(SS[1,2,3,4])
sorted_set.send(method, -4...4).should eql(SS[1,2,3,4])
sorted_set.send(method, -4..0).should eql(SS[1])
sorted_set.send(method, -4...0).should eql(SS.empty)
sorted_set.send(method, -4..1).should eql(SS[1,2])
sorted_set.send(method, -4...1).should eql(SS[1])
sorted_set.send(method, -5..-5).should be_nil
sorted_set.send(method, -5...-5).should be_nil
sorted_set.send(method, -5..-4).should be_nil
sorted_set.send(method, -5..-1).should be_nil
sorted_set.send(method, -5..10).should be_nil
big.send(method, -10001..-1).should be_nil
end
it 'leaves the original unchanged' do
sorted_set.should eql(SS[1,2,3,4])
end
end
end
context 'when passed an empty Range' do
it 'does not lose custom sort order' do
ss = SS.new(['yogurt', 'cake', 'pistachios'], &:length)
ss = ss.send(method, 1...1).add('tea').add('fruitcake').add('toast')
ss.to_a.should == ['tea', 'toast', 'fruitcake']
end
end
context 'when passed a length of zero' do
it 'does not lose custom sort order' do
ss = SS.new(['yogurt', 'cake', 'pistachios'], &:length)
ss = ss.send(method, 0, 0).add('tea').add('fruitcake').add('toast')
ss.to_a.should == ['tea', 'toast', 'fruitcake']
end
end
context 'when passed a subclass of Range' do
it 'works the same as with a Range' do
subclass = Class.new(Range)
sorted_set.send(method, subclass.new(1,2)).should eql(SS[2,3])
sorted_set.send(method, subclass.new(-3,-1,true)).should eql(SS[2,3])
end
end
context 'on a subclass of SortedSet' do
it 'with index and count or a range, returns an instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
instance = subclass.new([1,2,3])
instance.send(method, 0, 0).class.should be(subclass)
instance.send(method, 0, 2).class.should be(subclass)
instance.send(method, 0..0).class.should be(subclass)
instance.send(method, 1..-1).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/add_spec.rb 0000644 0001750 0001750 00000003260 14201005456 024602 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
let(:sorted_set) { SS['B', 'C', 'D'] }
[:add, :<<].each do |method|
describe "##{method}" do
context 'with a unique value' do
it 'preserves the original' do
sorted_set.send(method, 'A')
sorted_set.should eql(SS['B', 'C', 'D'])
end
it 'returns a copy with the superset of values (in order)' do
sorted_set.send(method, 'A').should eql(SS['A', 'B', 'C', 'D'])
end
end
context 'with a duplicate value' do
it 'preserves the original values' do
sorted_set.send(method, 'C')
sorted_set.should eql(SS['B', 'C', 'D'])
end
it 'returns self' do
sorted_set.send(method, 'C').should equal(sorted_set)
end
end
context 'on a set ordered by a comparator' do
it 'inserts the new item in the correct place' do
s = SS.new(['tick', 'pig', 'hippopotamus'], &:length)
s.add('giraffe').to_a.should == ['pig', 'tick', 'giraffe', 'hippopotamus']
end
end
end
end
describe '#add?' do
context 'with a unique value' do
it 'preserves the original' do
sorted_set.add?('A')
sorted_set.should eql(SS['B', 'C', 'D'])
end
it 'returns a copy with the superset of values' do
sorted_set.add?('A').should eql(SS['A', 'B', 'C', 'D'])
end
end
context 'with a duplicate value' do
it 'preserves the original values' do
sorted_set.add?('C')
sorted_set.should eql(SS['B', 'C', 'D'])
end
it 'returns false' do
sorted_set.add?('C').should equal(false)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/from_spec.rb 0000644 0001750 0001750 00000003144 14201005456 025016 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#from' do
context 'when called without a block' do
it 'returns a sorted set of all items equal to or greater than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = set.from(threshold)
array = items.select { |x| x >= threshold }.sort
result.class.should be(Immutable::SortedSet)
result.size.should == array.size
result.to_a.should == array
end
end
end
context 'when called with a block' do
it 'yields all the items equal to or greater than than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = []
set.from(threshold) { |x| result << x }
array = items.select { |x| x >= threshold }.sort
result.size.should == array.size
result.should == array
end
end
end
context 'on an empty set' do
it 'returns an empty set' do
SS.empty.from(1).should be_empty
SS.empty.from('abc').should be_empty
SS.empty.from(:symbol).should be_empty
end
end
context 'with an argument higher than all the values in the set' do
it 'returns an empty set' do
result = SS.new(1..100).from(101)
result.class.should be(Immutable::SortedSet)
result.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/take_spec.rb 0000644 0001750 0001750 00000003044 14201005456 024776 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#take' do
[
[[], 10, []],
[['A'], 10, ['A']],
[%w[A B C], 0, []],
[%w[A B C], 2, %w[A B]],
].each do |values, number, expected|
context "#{number} from #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it 'preserves the original' do
sorted_set.take(number)
sorted_set.should eql(SS[*values])
end
it "returns #{expected.inspect}" do
sorted_set.take(number).should eql(SS[*expected])
end
end
end
context 'when argument is at least size of receiver' do
let(:sorted_set) { SS[6, 7, 8, 9] }
it 'returns self' do
sorted_set.take(sorted_set.size).should be(sorted_set)
sorted_set.take(sorted_set.size + 1).should be(sorted_set)
end
end
context 'when the set has a custom order' do
let(:sorted_set) { SS.new([1, 2, 3], &:-@)}
it 'maintains the custom order' do
sorted_set.take(1).to_a.should == [3]
sorted_set.take(2).to_a.should == [3, 2]
sorted_set.take(3).to_a.should == [3, 2, 1]
end
it 'keeps the comparator even when set is cleared' do
s = sorted_set.take(0)
s.add(4).add(5).add(6).to_a.should == [6, 5, 4]
end
end
context 'when called on a subclass' do
it 'should return an instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
subclass.new([1,2,3]).take(1).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/values_at_spec.rb 0000644 0001750 0001750 00000001710 14201005456 026033 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#values_at' do
let(:sorted_set) { SS['a', 'b', 'c'] }
it 'accepts any number of indices, and returns a sorted_set of items at those indices' do
sorted_set.values_at(0).should eql(SS['a'])
sorted_set.values_at(1,2).should eql(SS['b', 'c'])
end
context 'when passed invalid indices' do
it 'filters them out' do
sorted_set.values_at(1,2,3).should eql(SS['b', 'c'])
sorted_set.values_at(-10,10).should eql(SS.empty)
end
end
context 'when passed no arguments' do
it 'returns an empty sorted_set' do
sorted_set.values_at.should eql(SS.empty)
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
instance = subclass.new([1,2,3])
instance.values_at(1,2).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/find_index_spec.rb 0000644 0001750 0001750 00000002177 14201005456 026167 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:find_index, :index].each do |method|
describe "##{method}" do
[
[[], 'A', nil],
[[], nil, nil],
[['A'], 'A', 0],
[['A'], 'B', nil],
[['A'], nil, nil],
[['A', 'B', 'C'], 'A', 0],
[['A', 'B', 'C'], 'B', 1],
[['A', 'B', 'C'], 'C', 2],
[['A', 'B', 'C'], 'D', nil],
[0..1, 1, 1],
[0..10, 5, 5],
[0..10, 10, 10],
[[2], 2, 0],
[[2], 2.0, 0],
[[2.0], 2.0, 0],
[[2.0], 2, 0],
].each do |values, item, expected|
unless item.nil? # test breaks otherwise
context "looking for #{item.inspect} in #{values.inspect} without block" do
it "returns #{expected.inspect}" do
SS[*values].send(method, item).should == expected
end
end
end
context "looking for #{item.inspect} in #{values.inspect} with block" do
it "returns #{expected.inspect}" do
SS[*values].send(method) { |x| x == item }.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/select_spec.rb 0000644 0001750 0001750 00000003646 14201005456 025341 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:select, :find_all].each do |method|
describe "##{method}" do
let(:sorted_set) { SS['A', 'B', 'C'] }
context 'when everything matches' do
it 'preserves the original' do
sorted_set.send(method) { true }
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns self' do
sorted_set.send(method) { |item| true }.should equal(sorted_set)
end
end
context 'when only some things match' do
context 'with a block' do
it 'preserves the original' do
sorted_set.send(method) { |item| item == 'A' }
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns a set with the matching values' do
sorted_set.send(method) { |item| item == 'A' }.should eql(SS['A'])
end
end
context 'with no block' do
it 'returns an Enumerator' do
sorted_set.send(method).class.should be(Enumerator)
sorted_set.send(method).each { |item| item == 'A' }.should eql(SS['A'])
end
end
end
context 'when nothing matches' do
it 'preserves the original' do
sorted_set.send(method) { |item| false }
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns the canonical empty set' do
sorted_set.send(method) { |item| false }.should equal(Immutable::EmptySortedSet)
end
end
context 'from a subclass' do
it 'returns an instance of the same class' do
subclass = Class.new(Immutable::SortedSet)
instance = subclass.new(['A', 'B', 'C'])
instance.send(method) { true }.class.should be(subclass)
instance.send(method) { false }.class.should be(subclass)
instance.send(method) { rand(2) == 0 }.class.should be(subclass)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/sorting_spec.rb 0000644 0001750 0001750 00000003305 14201005456 025537 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[
[:sort, ->(left, right) { left.length <=> right.length }],
[:sort_by, ->(item) { item.length }],
].each do |method, comparator|
describe "##{method}" do
[
[[], []],
[['A'], ['A']],
[%w[Ichi Ni San], %w[Ni San Ichi]],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:sorted_set) { SS.new(values, &:reverse)}
context 'with a block' do
it 'preserves the original' do
sorted_set.send(method, &comparator)
sorted_set.to_a.should == SS.new(values, &:reverse)
end
it "returns #{expected.inspect}" do
sorted_set.send(method, &comparator).class.should be(Immutable::SortedSet)
sorted_set.send(method, &comparator).to_a.should == expected
end
end
context 'without a block' do
it 'preserves the original' do
sorted_set.send(method)
sorted_set.to_a.should == SS.new(values, &:reverse)
end
it "returns #{expected.sort.inspect}" do
sorted_set.send(method).class.should be(Immutable::SortedSet)
sorted_set.send(method).to_a.should == expected.sort
end
end
end
end
end
end
describe :sort do
context 'on a SortedSet with custom sort order' do
let(:sorted_set) { SS.new([1,2,3,4]) { |x,y| y <=> x }}
it 'returns a SortedSet with the natural sort order' do
result = sorted_set.sort
expect(sorted_set.to_a).to eq([4,3,2,1])
expect(result.to_a).to eq([1,2,3,4])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/difference_spec.rb 0000644 0001750 0001750 00000001132 14201005456 026140 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:difference, :subtract, :-].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], ['A']],
[['A'], ['A'], []],
[%w[A B C], ['B'], %w[A C]],
[%w[A B C], %w[A C], ['B']],
[%w[A B C D E F], %w[B E F G M X], %w[A C D]]
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected.inspect}" do
SS[*a].send(method, SS[*b]).should eql(SS[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/eql_spec.rb 0000644 0001750 0001750 00000005725 14201005456 024643 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable::SortedSet do
let(:set) { SS[*values] }
let(:comparison) { SS[*comparison_values] }
describe '#eql?' do
let(:eql?) { set.eql?(comparison) }
shared_examples 'comparing something which is not a sorted set' do
let(:values) { %w[A B C] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'when comparing to a standard set' do
let(:comparison) { ::Set.new(%w[A B C]) }
include_examples 'comparing something which is not a sorted set'
end
context 'when comparing to a arbitrary object' do
let(:comparison) { Object.new }
include_examples 'comparing something which is not a sorted set'
end
context 'when comparing to an Immutable::Set' do
let(:comparison) { Immutable::Set.new(%w[A B C]) }
include_examples 'comparing something which is not a sorted set'
end
context 'when comparing with a subclass of Immutable::SortedSet' do
let(:comparison) { Class.new(Immutable::SortedSet).new(%w[A B C]) }
include_examples 'comparing something which is not a sorted set'
end
context 'with an empty set for each comparison' do
let(:values) { [] }
let(:comparison_values) { [] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with an empty set and a set with nil' do
let(:values) { [] }
let(:comparison_values) { [nil] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with a single item array and empty array' do
let(:values) { ['A'] }
let(:comparison_values) { [] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with matching single item array' do
let(:values) { ['A'] }
let(:comparison_values) { ['A'] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with mismatching single item array' do
let(:values) { ['A'] }
let(:comparison_values) { ['B'] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with a multi-item array and single item array' do
let(:values) { %w[A B] }
let(:comparison_values) { ['A'] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with matching multi-item array' do
let(:values) { %w[A B] }
let(:comparison_values) { %w[A B] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with a mismatching multi-item array' do
let(:values) { %w[A B] }
let(:comparison_values) { %w[B A] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with the same values, but a different sort order' do
let(:set) { SS[1, 2, 3] }
let(:comparison) { SS.new([1, 2, 3], &:-@)}
it 'returns false' do
expect(eql?).to eq(false)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/include_spec.rb 0000644 0001750 0001750 00000001113 14201005456 025470 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:include?, :member?].each do |method|
describe "##{method}" do
let(:sorted_set) { SS[1, 2, 3, 4.0] }
[1, 2, 3, 4.0].each do |value|
it "returns true for an existing value (#{value.inspect})" do
sorted_set.send(method, value).should == true
end
end
it 'returns false for a non-existing value' do
sorted_set.send(method, 5).should == false
end
it 'uses #<=> for equality' do
sorted_set.send(method, 4).should == true
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/group_by_spec.rb 0000644 0001750 0001750 00000003250 14201005456 025677 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:group_by, :group, :classify].each do |method|
describe "##{method}" do
context 'with a block' do
[
[[], []],
[[1], [true => SS[1]]],
[[1, 2, 3, 4], [true => SS[3, 1], false => SS[4, 2]]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it 'preserves the original' do
sorted_set.send(method, &:odd?)
sorted_set.should eql(SS[*values])
end
it "returns #{expected.inspect}" do
sorted_set.send(method, &:odd?).should eql(H[*expected])
end
end
end
end
context 'without a block' do
[
[[], []],
[[1], [1 => SS[1]]],
[[1, 2, 3, 4], [1 => SS[1], 2 => SS[2], 3 => SS[3], 4 => SS[4]]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it 'preserves the original' do
sorted_set.group_by
sorted_set.should eql(SS[*values])
end
it "returns #{expected.inspect}" do
sorted_set.group_by.should eql(H[*expected])
end
end
end
end
context 'from a subclass' do
it 'returns an Hash whose values are instances of the subclass' do
subclass = Class.new(Immutable::SortedSet)
instance = subclass.new(['some', 'strings', 'here'])
instance.group_by { |x| x }.values.each { |v| v.class.should be(subclass) }
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/clear_spec.rb 0000644 0001750 0001750 00000002123 14201005456 025135 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#clear' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values}" do
let(:sorted_set) { SS[*values] }
it 'preserves the original' do
sorted_set.clear
sorted_set.should eql(SS[*values])
end
it 'returns an empty set' do
sorted_set.clear.should equal(Immutable::EmptySortedSet)
sorted_set.clear.should be_empty
end
end
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::SortedSet)
instance = subclass.new([:a, :b, :c, :d])
instance.clear.class.should be(subclass)
instance.clear.should be_empty
end
end
context 'with a comparator' do
let(:sorted_set) { SS.new([1, 2, 3], &:-@) }
it 'returns an empty instance with same comparator' do
e = sorted_set.clear
e.should be_empty
e.add(4).add(5).add(6).to_a.should == [6, 5, 4]
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/superset_spec.rb 0000644 0001750 0001750 00000002356 14201005456 025731 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#superset?' do
[
[[], [], true],
[['A'], [], true],
[[], ['A'], false],
[['A'], ['A'], true],
[%w[A B C], ['B'], true],
[['B'], %w[A B C], false],
[%w[A B C], %w[A C], true],
[%w[A C], %w[A B C], false],
[%w[A B C], %w[A B C], true],
[%w[A B C], %w[A B C D], false],
[%w[A B C D], %w[A B C], true],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
SS[*a].superset?(SS[*b]).should == expected
end
end
end
end
describe '#proper_superset?' do
[
[[], [], false],
[['A'], [], true],
[[], ['A'], false],
[['A'], ['A'], false],
[%w[A B C], ['B'], true],
[['B'], %w[A B C], false],
[%w[A B C], %w[A C], true],
[%w[A C], %w[A B C], false],
[%w[A B C], %w[A B C], false],
[%w[A B C], %w[A B C D], false],
[%w[A B C D], %w[A B C], true],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
SS[*a].proper_superset?(SS[*b]).should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/disjoint_spec.rb 0000644 0001750 0001750 00000001221 14201005456 025670 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#disjoint?' do
[
[[], [], true],
[['A'], [], true],
[[], ['A'], true],
[['A'], ['A'], false],
[%w[A B C], ['B'], false],
[['B'], %w[A B C], false],
[%w[A B C], %w[D E], true],
[%w[F G H I], %w[A B C], true],
[%w[A B C], %w[A B C], false],
[%w[A B C], %w[A B C D], false],
[%w[D E F G], %w[A B C], true],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
SS[*a].disjoint?(SS[*b]).should be(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/intersection_spec.rb 0000644 0001750 0001750 00000001432 14201005456 026557 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:intersection, :&].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], []],
[['A'], ['A'], ['A']],
[%w[A B C], ['B'], ['B']],
[%w[A B C], %w[A C], %w[A C]],
[%w[A M T X], %w[B C D E F G H I M P Q T U], %w[M T]]
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected.inspect}" do
SS[*a].send(method, SS[*b]).should eql(SS[*expected])
end
end
context "for #{b.inspect} and #{a.inspect}" do
it "returns #{expected.inspect}" do
SS[*b].send(method, SS[*a]).should eql(SS[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/union_spec.rb 0000644 0001750 0001750 00000003477 14201005456 025214 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:union, :|, :+, :merge].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], ['A']],
[['A'], ['A'], ['A']],
[%w[A B C], [], %w[A B C]],
[%w[A C E G X], %w[B C D E H M], %w[A B C D E G H M X]]
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected.inspect}" do
SS[*a].send(method, SS[*b]).should eql(SS[*expected])
end
end
context "for #{b.inspect} and #{a.inspect}" do
it "returns #{expected.inspect}" do
SS[*b].send(method, SS[*a]).should eql(SS[*expected])
end
end
end
end
end
describe :union do
it 'filters out duplicates when passed an Array' do
sorted_set = SS['A', 'B', 'C', 'D'].union(['A', 'A', 'A', 'C', 'A', 'B', 'E'])
expect(sorted_set.to_a).to eq(['A', 'B', 'C', 'D', 'E'])
end
it "doesn't mutate an Array which is passed in" do
array = [3,2,1,3]
sorted_set = SS[1,2,5].union(array)
expect(array).to eq([3,2,1,3])
end
context 'on a set ordered by a comparator' do
# Completely different code is executed when #union is called on a SS
# with a comparator block, so we should repeat all the same tests
it 'still filters out duplicates when passed an Array' do
sorted_set = SS.new([1,2,3]) { |x,y| (x%7) <=> (y%7) }
sorted_set = sorted_set.union([7,8,9])
expect(sorted_set.to_a).to eq([7,1,2,3])
end
it "still doesn't mutate an Array which is passed in" do
array = [3,2,1,3]
sorted_set = SS.new([1,2,5]) { |x,y| y <=> x }
sorted_set = sorted_set.union(array)
expect(array).to eq([3,2,1,3])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/drop_while_spec.rb 0000644 0001750 0001750 00000001647 14201005456 026215 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#drop_while' do
[
[[], []],
[['A'], []],
[%w[A B C], ['C']],
[%w[A B C D E F G], %w[C D E F G]]
].each do |values, expected|
context "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
context 'with a block' do
it 'preserves the original' do
sorted_set.drop_while { |item| item < 'C' }
sorted_set.should eql(SS[*values])
end
it "returns #{expected.inspect}" do
sorted_set.drop_while { |item| item < 'C' }.should eql(SS[*expected])
end
end
context 'without a block' do
it 'returns an Enumerator' do
sorted_set.drop_while.class.should be(Enumerator)
sorted_set.drop_while.each { |item| item < 'C' }.should eql(SS[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/maximum_spec.rb 0000644 0001750 0001750 00000001535 14201005456 025532 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#max' do
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { SS[*values] }
let(:result) { set.max { |maximum, item| maximum.length <=> item.length }}
it "returns #{expected.inspect}" do
result.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'San'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
SS[*values].max.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/first_spec.rb 0000644 0001750 0001750 00000000567 14201005456 025210 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#first' do
[
[[], nil],
[['A'], 'A'],
[%w[A B C], 'A'],
[%w[Z Y X], 'X']
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
SS[*values].first.should eql(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/util_spec.rb 0000644 0001750 0001750 00000002674 14201005456 025037 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
# Utility method used for filtering out duplicate objects, with equality
# determined by comparator
describe '.uniq_by_comparator!' do
it 'can handle empty arrays' do
array = []
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
expect(array).to be_empty
end
it 'can handle arrays with 1 element' do
array = [1]
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
expect(array).to eq([1])
end
it 'can handle arrays with 2 elements and no dupes' do
array = [1, 2]
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
expect(array).to eq([1, 2])
end
it 'can handle arrays with 2 elements and dupes' do
array = [1, 1]
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
expect(array).to eq([1])
end
it 'can handle arrays with lots of elements' do
100.times do
array1 = rand(100).times.collect { rand(100) }.sort
array2 = array1.dup.uniq
SS.uniq_by_comparator!(array1, ->(x,y) { x <=> y })
expect(array1).to eq(array2)
end
end
it 'works with funny comparators' do
# let's work in modulo arithmetic
comparator = ->(x,y) { (x % 7) <=> (y % 7) }
array = [21, 1, 8, 1, 9, 10, 3, 5, 6, 20] # this is "sorted" (modulo 7)
SS.uniq_by_comparator!(array, comparator)
expect(array).to eq([21, 1, 9, 10, 5, 6])
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/exclusion_spec.rb 0000644 0001750 0001750 00000001115 14201005456 026060 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:exclusion, :^].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], ['A']],
[['A'], ['A'], []],
[%w[A B C], ['B'], %w[A C]],
[%w[A B C], %w[B C D], %w[A D]],
[%w[A B C], %w[D E F], %w[A B C D E F]],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected.inspect}" do
SS[*a].send(method, SS[*b]).should eql(SS[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/map_spec.rb 0000644 0001750 0001750 00000002732 14201005456 024632 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:map, :collect].each do |method|
describe "##{method}" do
context 'when empty' do
it 'returns self' do
SS.empty.send(method) {}.should equal(SS.empty)
end
end
context 'when not empty' do
let(:sorted_set) { SS['A', 'B', 'C'] }
context 'with a block' do
it 'preserves the original values' do
sorted_set.send(method, &:downcase)
sorted_set.should eql(SS['A', 'B', 'C'])
end
it 'returns a new set with the mapped values' do
sorted_set.send(method, &:downcase).should eql(SS['a', 'b', 'c'])
end
it 'filters out duplicates' do
sorted_set.send(method) { 'blah' }.should eq(SS['blah'])
end
end
context 'with no block' do
it 'returns an Enumerator' do
sorted_set.send(method).class.should be(Enumerator)
sorted_set.send(method).each(&:downcase).should == SS['a', 'b', 'c']
end
end
end
context 'on a set ordered by a comparator' do
let(:sorted_set) { SS.new(['A', 'B', 'C']) { |a,b| b <=> a }}
it 'returns a new set with the mapped values' do
sorted_set.send(method, &:downcase).should == ['c', 'b', 'a']
end
it 'filters out duplicates' do
sorted_set.send(method) { 'blah' }.should eq(SS['blah'])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/reverse_each_spec.rb 0000644 0001750 0001750 00000001316 14201005456 026505 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#reverse_each' do
context 'with no block' do
let(:sorted_set) { SS['A', 'B', 'C'] }
it 'returns an Enumerator' do
sorted_set.reverse_each.class.should be(Enumerator)
sorted_set.reverse_each.to_a.should eql(sorted_set.to_a.reverse)
end
end
context 'with a block' do
let(:sorted_set) { SS.new(1..1025) }
it 'returns self' do
sorted_set.reverse_each {}.should be(sorted_set)
end
it 'iterates over the items in order' do
items = []
sorted_set.reverse_each { |item| items << item }
items.should == (1..1025).to_a.reverse
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/between_spec.rb 0000644 0001750 0001750 00000003224 14201005456 025503 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#between' do
context 'when called without a block' do
it 'returns a sorted set of all items from the first argument to the second' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
from,to = [rand(1000),rand(1000)].sort
result = set.between(from, to)
array = items.select { |x| x >= from && x <= to }.sort
result.class.should be(Immutable::SortedSet)
result.size.should == array.size
result.to_a.should == array
end
end
end
context 'when called with a block' do
it 'yields all the items lower than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
from,to = [rand(1000),rand(1000)].sort
result = []
set.between(from, to) { |x| result << x }
array = items.select { |x| x >= from && x <= to }.sort
result.size.should == array.size
result.should == array
end
end
end
context 'on an empty set' do
it 'returns an empty set' do
SS.empty.between(1, 2).should be_empty
SS.empty.between('abc', 'def').should be_empty
SS.empty.between(:symbol, :another).should be_empty
end
end
context "with a 'to' argument lower than the 'from' argument" do
it 'returns an empty set' do
result = SS.new(1..100).between(6, 5)
result.class.should be(Immutable::SortedSet)
result.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/copying_spec.rb 0000644 0001750 0001750 00000000601 14201005456 025516 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
[:dup, :clone].each do |method|
[
[],
['A'],
%w[A B C],
(1..32),
].each do |values|
describe "on #{values.inspect}" do
let(:sorted_set) { SS[*values] }
it 'returns self' do
sorted_set.send(method).should equal(sorted_set)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/below_spec.rb 0000644 0001750 0001750 00000003105 14201005456 025160 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#below' do
context 'when called without a block' do
it 'returns a sorted set of all items lower than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = set.below(threshold)
array = items.select { |x| x < threshold }.sort
result.class.should be(Immutable::SortedSet)
result.size.should == array.size
result.to_a.should == array
end
end
end
context 'when called with a block' do
it 'yields all the items lower than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = []
set.below(threshold) { |x| result << x }
array = items.select { |x| x < threshold }.sort
result.size.should == array.size
result.should == array
end
end
end
context 'on an empty set' do
it 'returns an empty set' do
SS.empty.below(1).should be_empty
SS.empty.below('abc').should be_empty
SS.empty.below(:symbol).should be_empty
end
end
context 'with an argument lower than all the values in the set' do
it 'returns an empty set' do
result = SS.new(1..100).below(1)
result.class.should be(Immutable::SortedSet)
result.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/up_to_spec.rb 0000644 0001750 0001750 00000003215 14201005456 025200 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#up_to' do
context 'when called without a block' do
it 'returns a sorted set of all items equal to or less than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = set.up_to(threshold)
array = items.select { |x| x <= threshold }.sort
result.class.should be(Immutable::SortedSet)
result.size.should == array.size
result.to_a.should == array
end
end
end
context 'when called with a block' do
it 'yields all the items equal to or less than than the argument' do
100.times do
items = rand(100).times.collect { rand(1000) }.uniq
set = SS.new(items)
threshold = rand(1000)
result = []
set.up_to(threshold) { |x| result << x }
array = items.select { |x| x <= threshold }.sort
result.size.should == array.size
result.should == array
end
end
end
context 'on an empty set' do
it 'returns an empty set' do
SS.empty.up_to(1).should be_empty
SS.empty.up_to('abc').should be_empty
SS.empty.up_to(:symbol).should be_empty
SS.empty.up_to(nil).should be_empty
end
end
context 'with an argument less than all the values in the set' do
it 'returns an empty set' do
result = SS.new(1..100).up_to(0)
result.class.should be(Immutable::SortedSet)
result.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/sorted_set/to_set_spec.rb 0000644 0001750 0001750 00000000514 14201005456 025346 0 ustar boutil boutil require 'spec_helper'
describe Immutable::SortedSet do
describe '#to_set' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
it 'returns a set with the same values' do
SS[*values].to_set.should eql(S[*values])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/ 0000755 0001750 0001750 00000000000 14201005456 021132 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/set/intersect_spec.rb 0000644 0001750 0001750 00000001215 14201005456 024470 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#intersect?' do
[
[[], [], false],
[['A'], [], false],
[[], ['A'], false],
[['A'], ['A'], true],
[%w[A B C], ['B'], true],
[['B'], %w[A B C], true],
[%w[A B C], %w[D E], false],
[%w[F G H I], %w[A B C], false],
[%w[A B C], %w[A B C], true],
[%w[A B C], %w[A B C D], true],
[%w[D E F G], %w[A B C], false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
S[*a].intersect?(S[*b]).should be(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/new_spec.rb 0000644 0001750 0001750 00000002511 14201005456 023261 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '.new' do
it 'initializes a new set' do
set = S.new([1,2,3])
set.size.should be(3)
[1,2,3].each { |n| set.include?(n).should == true }
end
it 'accepts a Range' do
set = S.new(1..3)
set.size.should be(3)
[1,2,3].each { |n| set.include?(n).should == true }
end
it "returns a Set which doesn't change even if the initializer is mutated" do
array = [1,2,3]
set = S.new([1,2,3])
array.push('BAD')
set.should eql(S[1,2,3])
end
context 'from a subclass' do
it 'returns a frozen instance of the subclass' do
subclass = Class.new(Immutable::Set)
instance = subclass.new(['some', 'values'])
instance.class.should be subclass
instance.should be_frozen
end
end
it 'is amenable to overriding of #initialize' do
class SnazzySet < Immutable::Set
def initialize
super(['SNAZZY!!!'])
end
end
set = SnazzySet.new
set.size.should be(1)
set.include?('SNAZZY!!!').should == true
end
end
describe '[]' do
it 'accepts any number of arguments and initializes a new set' do
set = S[1,2,3,4]
set.size.should be(4)
[1,2,3,4].each { |n| set.include?(n).should == true }
end
end
end
immutable-ruby-master/spec/lib/immutable/set/size_spec.rb 0000644 0001750 0001750 00000000554 14201005456 023447 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:size, :length].each do |method|
describe "##{method}" do
[
[[], 0],
[['A'], 1],
[%w[A B C], 3],
].each do |values, result|
it "returns #{result} for #{values.inspect}" do
S[*values].send(method).should == result
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/eqeq_spec.rb 0000644 0001750 0001750 00000004363 14201005456 023432 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable::Set do
let(:set) { S[*values] }
let(:comparison) { S[*comparison_values] }
describe '#==' do
let(:eqeq) { set == comparison }
shared_examples 'comparing non-sets' do
let(:values) { %w[A B C] }
it 'returns false' do
expect(eqeq).to eq(false)
end
end
context 'when comparing to a standard set' do
let(:comparison) { ::Set.new(%w[A B C]) }
include_examples 'comparing non-sets'
end
context 'when comparing to a arbitrary object' do
let(:comparison) { Object.new }
include_examples 'comparing non-sets'
end
context 'with an empty set for each comparison' do
let(:values) { [] }
let(:comparison_values) { [] }
it 'returns true' do
expect(eqeq).to eq(true)
end
end
context 'with an empty set and a set with nil' do
let(:values) { [] }
let(:comparison_values) { [nil] }
it 'returns false' do
expect(eqeq).to eq(false)
end
end
context 'with a single item array and empty array' do
let(:values) { ['A'] }
let(:comparison_values) { [] }
it 'returns false' do
expect(eqeq).to eq(false)
end
end
context 'with matching single item array' do
let(:values) { ['A'] }
let(:comparison_values) { ['A'] }
it 'returns true' do
expect(eqeq).to eq(true)
end
end
context 'with mismatching single item array' do
let(:values) { ['A'] }
let(:comparison_values) { ['B'] }
it 'returns false' do
expect(eqeq).to eq(false)
end
end
context 'with a multi-item array and single item array' do
let(:values) { %w[A B] }
let(:comparison_values) { ['A'] }
it 'returns false' do
expect(eqeq).to eq(false)
end
end
context 'with matching multi-item array' do
let(:values) { %w[A B] }
let(:comparison_values) { %w[A B] }
it 'returns true' do
expect(eqeq).to eq(true)
end
end
context 'with a mismatching multi-item array' do
let(:values) { %w[A B] }
let(:comparison_values) { %w[B A] }
it 'returns true' do
expect(eqeq).to eq(true)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/construction_spec.rb 0000644 0001750 0001750 00000000660 14201005456 025225 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '.set' do
context 'with no values' do
it 'returns the empty set' do
S.empty.should be_empty
S.empty.should equal(Immutable::EmptySet)
end
end
context 'with a list of values' do
it 'is equivalent to repeatedly using #add' do
S['A', 'B', 'C'].should eql(S.empty.add('A').add('B').add('C'))
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/reject_spec.rb 0000644 0001750 0001750 00000002730 14201005456 023747 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:reject, :delete_if].each do |method|
describe "##{method}" do
let(:set) { S['A', 'B', 'C'] }
context 'when nothing matches' do
it 'returns self' do
set.send(method) { |item| false }.should equal(set)
end
end
context 'when only some things match' do
context 'with a block' do
let(:result) { set.send(method) { |item| item == 'A' }}
it 'preserves the original' do
result
set.should eql(S['A', 'B', 'C'])
end
it 'returns a set with the matching values' do
result.should eql(S['B', 'C'])
end
end
context 'with no block' do
it 'returns self' do
set.send(method).class.should be(Enumerator)
set.send(method).each { |item| item == 'A' }.should == S['B', 'C']
end
end
end
context 'on a large set, with many combinations of input' do
it 'still works' do
array = (1..1000).to_a
set = S.new(array)
[0, 10, 100, 200, 500, 800, 900, 999, 1000].each do |threshold|
result = set.send(method) { |item| item > threshold }
result.size.should == threshold
1.upto(threshold) { |n| result.include?(n).should == true }
(threshold+1).upto(1000) { |n| result.include?(n).should == false }
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/flatten_spec.rb 0000644 0001750 0001750 00000002202 14201005456 024122 0 ustar boutil boutil require 'spec_helper'
describe Immutable do
describe '#flatten' do
[
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[['A', S['B'], 'C'], %w[A B C]],
[[S['A'], S['B'], S['C']], %w[A B C]],
].each do |values, expected|
describe "on #{values}" do
let(:set) { S[*values] }
it 'preserves the original' do
set.flatten
set.should eql(S[*values])
end
it 'returns the inlined values' do
set.flatten.should eql(S[*expected])
end
end
end
context 'on an empty set' do
it 'returns an empty set' do
S.empty.flatten.should equal(S.empty)
end
end
context 'on a set with multiple levels of nesting' do
it 'inlines lower levels of nesting' do
set = S[S[S[1]], S[S[2]]]
set.flatten.should eql(S[1, 2])
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Set)
subclass.new.flatten.class.should be(subclass)
subclass.new([S[1], S[2]]).flatten.class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/sample_spec.rb 0000644 0001750 0001750 00000000521 14201005456 023750 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#sample' do
let(:set) { S.new(1..10) }
it 'returns a randomly chosen item' do
chosen = 100.times.map { set.sample }
chosen.each { |item| set.include?(item).should == true }
set.each { |item| chosen.include?(item).should == true }
end
end
end
immutable-ruby-master/spec/lib/immutable/set/any_spec.rb 0000644 0001750 0001750 00000002555 14201005456 023267 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#any?' do
context 'when empty' do
it 'with a block returns false' do
S.empty.any? {}.should == false
end
it 'with no block returns false' do
S.empty.any?.should == false
end
end
context 'when not empty' do
context 'with a block' do
let(:set) { S['A', 'B', 'C', nil] }
['A', 'B', 'C', nil].each do |value|
it "returns true if the block ever returns true (#{value.inspect})" do
set.any? { |item| item == value }.should == true
end
end
it 'returns false if the block always returns false' do
set.any? { |item| item == 'D' }.should == false
end
it 'propagates exceptions raised in the block' do
-> { set.any? { |k,v| raise 'help' } }.should raise_error(RuntimeError)
end
it 'stops iterating as soon as the block returns true' do
yielded = []
set.any? { |k,v| yielded << k; true }
yielded.size.should == 1
end
end
context 'with no block' do
it 'returns true if any value is truthy' do
S[nil, false, true, 'A'].any?.should == true
end
it 'returns false if all values are falsey' do
S[nil, false].any?.should == false
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/subset_spec.rb 0000644 0001750 0001750 00000002612 14201005456 023777 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:subset?, :<=].each do |method|
describe "##{method}" do
[
[[], [], true],
[['A'], [], false],
[[], ['A'], true],
[['A'], ['A'], true],
[%w[A B C], ['B'], false],
[['B'], %w[A B C], true],
[%w[A B C], %w[A C], false],
[%w[A C], %w[A B C], true],
[%w[A B C], %w[A B C], true],
[%w[A B C], %w[A B C D], true],
[%w[A B C D], %w[A B C], false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
S[*a].send(method, S[*b]).should == expected
end
end
end
end
end
[:proper_subset?, :<].each do |method|
describe "##{method}" do
[
[[], [], false],
[['A'], [], false],
[[], ['A'], true],
[['A'], ['A'], false],
[%w[A B C], ['B'], false],
[['B'], %w[A B C], true],
[%w[A B C], %w[A C], false],
[%w[A C], %w[A B C], true],
[%w[A B C], %w[A B C], false],
[%w[A B C], %w[A B C D], true],
[%w[A B C D], %w[A B C], false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
S[*a].send(method, S[*b]).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/minimum_spec.rb 0000644 0001750 0001750 00000001524 14201005456 024146 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#min' do
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ni'],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
let(:result) { set.min { |minimum, item| minimum.length <=> item.length }}
it "returns #{expected.inspect}" do
result.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
S[*values].min.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/inspect_spec.rb 0000644 0001750 0001750 00000002420 14201005456 024134 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#inspect' do
[
[[], 'Immutable::Set[]'],
[['A'], 'Immutable::Set["A"]'],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
it "returns #{expected.inspect}" do
set.inspect.should == expected
end
it "returns a string which can be eval'd to get an equivalent set" do
eval(set.inspect).should eql(set)
end
end
end
describe 'on ["A", "B", "C"]' do
let(:set) { S['A', 'B', 'C'] }
it 'returns a programmer-readable representation of the set contents' do
set.inspect.should match(/^Immutable::Set\["[A-C]", "[A-C]", "[A-C]"\]$/)
end
it "returns a string which can be eval'd to get an equivalent set" do
eval(set.inspect).should eql(set)
end
end
context 'from a subclass' do
MySet = Class.new(Immutable::Set)
let(:set) { MySet[1, 2] }
it 'returns a programmer-readable representation of the set contents' do
set.inspect.should match(/^MySet\[[1-2], [1-2]\]$/)
end
it "returns a string which can be eval'd to get an equivalent set" do
eval(set.inspect).should eql(set)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/product_spec.rb 0000644 0001750 0001750 00000000735 14201005456 024156 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#product' do
[
[[], 1],
[[2], 2],
[[1, 3, 5, 7, 11], 1155],
].each do |values, expected|
context "on #{values.inspect}" do
let(:set) { S[*values] }
it "returns #{expected.inspect}" do
set.product.should == expected
end
it "doesn't change the original Set" do
set.should eql(S.new(values))
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/marshal_spec.rb 0000644 0001750 0001750 00000001425 14201005456 024122 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#marshal_dump/#marshal_load' do
let(:ruby) { File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']) }
let(:child_cmd) do
%Q|#{ruby} -I lib -r immutable -e 'set = Immutable::Set[:one, :two]; $stdout.write(Marshal.dump(set))'|
end
let(:reloaded_hash) do
IO.popen(child_cmd, 'r+') do |child|
reloaded_hash = Marshal.load(child)
child.close
reloaded_hash
end
end
it 'can survive dumping and loading into a new process' do
reloaded_hash.should eql(S[:one, :two])
end
it 'is still possible to test items by key after loading' do
reloaded_hash.should include :one
reloaded_hash.should include :two
end
end
end
immutable-ruby-master/spec/lib/immutable/set/find_spec.rb 0000644 0001750 0001750 00000001727 14201005456 023420 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:find, :detect].each do |method|
describe "##{method}" do
[
[[], 'A', nil],
[[], nil, nil],
[['A'], 'A', 'A'],
[['A'], 'B', nil],
[['A'], nil, nil],
[['A', 'B', nil], 'A', 'A'],
[['A', 'B', nil], 'B', 'B'],
[['A', 'B', nil], nil, nil],
[['A', 'B', nil], 'C', nil],
].each do |values, item, expected|
describe "on #{values.inspect}" do
context 'with a block' do
it "returns #{expected.inspect}" do
S[*values].send(method) { |x| x == item }.should == expected
end
end
context 'without a block' do
it 'returns an Enumerator' do
result = S[*values].send(method)
result.class.should be(Enumerator)
result.each { |x| x == item}.should == expected
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/empty_spec.rb 0000644 0001750 0001750 00000002147 14201005456 023633 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#empty?' do
[
[[], true],
[['A'], false],
[%w[A B C], false],
[[nil], false],
[[false], false]
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
S[*values].empty?.should == expected
end
end
end
end
describe '.empty' do
it 'returns the canonical empty set' do
S.empty.should be_empty
S.empty.object_id.should be(S[].object_id)
S.empty.should be(Immutable::EmptySet)
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::Set)
subclass.empty.class.should be(subclass)
subclass.empty.should be_empty
end
it 'calls overridden #initialize when creating empty Set' do
subclass = Class.new(Immutable::Set) do
def initialize
@variable = 'value'
end
end
subclass.empty.instance_variable_get(:@variable).should == 'value'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/to_a_spec.rb 0000644 0001750 0001750 00000001401 14201005456 023407 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:to_a, :entries].each do |method|
describe "##{method}" do
('a'..'z').each do |letter|
let(:values) { ('a'..letter).to_a }
let(:set) { S.new(values) }
let(:result) { set.send(method) }
context "on 'a'..'#{letter}'" do
it 'returns an equivalent array' do
result.sort.should == values.sort
end
it "doesn't change the original Set" do
result
set.should eql(S[*values])
end
it 'returns a mutable array' do
expect(result.last).to_not eq('The End')
result << 'The End'
result.last.should == 'The End'
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/each_spec.rb 0000644 0001750 0001750 00000002027 14201005456 023372 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable::Set do
let(:set) { S['A', 'B', 'C'] }
describe '#each' do
let(:each) { set.each(&block) }
context 'without a block' do
let(:block) { nil }
it 'returns an Enumerator' do
expect(each.class).to be(Enumerator)
expect(each.to_a).to eq(set.to_a)
end
end
context 'with an empty block' do
let(:block) { ->(item) {} }
it 'returns self' do
expect(each).to be(set)
end
end
context 'with a block' do
let(:items) { ::Set.new }
let(:values) { ::Set.new(%w[A B C]) }
let(:block) { ->(item) { items << item } }
before(:each) { each }
it 'yields all values' do
expect(items).to eq(values)
end
end
it 'yields both of a pair of colliding keys' do
set = S[DeterministicHash.new('a', 1010), DeterministicHash.new('b', 1010)]
yielded = []
set.each { |obj| yielded << obj }
yielded.map(&:value).sort.should == ['a', 'b']
end
end
end
immutable-ruby-master/spec/lib/immutable/set/all_spec.rb 0000644 0001750 0001750 00000002504 14201005456 023242 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#all?' do
context 'when empty' do
it 'with a block returns true' do
S.empty.all? {}.should == true
end
it 'with no block returns true' do
S.empty.all?.should == true
end
end
context 'when not empty' do
context 'with a block' do
let(:set) { S['A', 'B', 'C'] }
it 'returns true if the block always returns true' do
set.all? { |item| true }.should == true
end
it 'returns false if the block ever returns false' do
set.all? { |item| item == 'D' }.should == false
end
it 'propagates an exception from the block' do
-> { set.all? { |k,v| raise 'help' } }.should raise_error(RuntimeError)
end
it 'stops iterating as soon as the block returns false' do
yielded = []
set.all? { |k,v| yielded << k; false }
yielded.size.should == 1
end
end
describe 'with no block' do
it 'returns true if all values are truthy' do
S[true, 'A'].all?.should == true
end
[nil, false].each do |value|
it "returns false if any value is #{value.inspect}" do
S[value, true, 'A'].all?.should == false
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/delete_spec.rb 0000644 0001750 0001750 00000003455 14201005456 023742 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
let(:set) { S['A', 'B', 'C'] }
describe '#delete' do
context 'with an existing value' do
it 'preserves the original' do
set.delete('B')
set.should eql(S['A', 'B', 'C'])
end
it 'returns a copy with the remaining values' do
set.delete('B').should eql(S['A', 'C'])
end
end
context 'with a non-existing value' do
it 'preserves the original values' do
set.delete('D')
set.should eql(S['A', 'B', 'C'])
end
it 'returns self' do
set.delete('D').should equal(set)
end
end
context 'when removing the last value in a set' do
it 'returns the canonical empty set' do
set.delete('B').delete('C').delete('A').should be(Immutable::EmptySet)
end
end
it 'works on large sets, with many combinations of input' do
array = 1000.times.map { %w[a b c d e f g h i j k l m n].sample(5).join }.uniq
set = S.new(array)
array.each do |key|
result = set.delete(key)
result.size.should == set.size - 1
result.include?(key).should == false
other = array.sample
(result.include?(other).should == true) if other != key
end
end
end
describe '#delete?' do
context 'with an existing value' do
it 'preserves the original' do
set.delete?('B')
set.should eql(S['A', 'B', 'C'])
end
it 'returns a copy with the remaining values' do
set.delete?('B').should eql(S['A', 'C'])
end
end
context 'with a non-existing value' do
it 'preserves the original values' do
set.delete?('D')
set.should eql(S['A', 'B', 'C'])
end
it 'returns false' do
set.delete?('D').should be(false)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/join_spec.rb 0000644 0001750 0001750 00000003401 14201005456 023426 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#join' do
context 'with a separator' do
[
[[], ''],
[['A'], 'A'],
[[DeterministicHash.new('A', 1), DeterministicHash.new('B', 2), DeterministicHash.new('C', 3)], 'A|B|C']
].each do |values, expected|
context "on #{values.inspect}" do
let(:set) { S[*values] }
it 'preserves the original' do
set.join('|')
set.should eql(S[*values])
end
it "returns #{expected.inspect}" do
set.join('|').should eql(expected)
end
end
end
end
context 'without a separator' do
[
[[], ''],
[['A'], 'A'],
[[DeterministicHash.new('A', 1), DeterministicHash.new('B', 2), DeterministicHash.new('C', 3)], 'ABC']
].each do |values, expected|
context "on #{values.inspect}" do
let(:set) { S[*values] }
it 'preserves the original' do
set.join
set.should eql(S[*values])
end
it "returns #{expected.inspect}" do
set.join.should eql(expected)
end
end
end
end
context 'without a separator (with global default separator set)' do
before { $, = '**' }
let(:set) { S[DeterministicHash.new('A', 1), DeterministicHash.new('B', 2), DeterministicHash.new('C', 3)] }
after { $, = nil }
context "on ['A', 'B', 'C']" do
it 'preserves the original' do
set.join
set.should eql(S[DeterministicHash.new('A', 1), DeterministicHash.new('B', 2), DeterministicHash.new('C', 3)])
end
it "returns #{@expected.inspect}" do
set.join.should == 'A**B**C'
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/add_spec.rb 0000644 0001750 0001750 00000003724 14201005456 023227 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
let(:original) { S['A', 'B', 'C'] }
[:add, :<<].each do |method|
describe "##{method}" do
context 'with a unique value' do
let(:result) { original.send(method, 'D') }
it 'preserves the original' do
result
original.should eql(S['A', 'B', 'C'])
end
it 'returns a copy with the superset of values' do
result.should eql(S['A', 'B', 'C', 'D'])
end
end
context 'with a duplicate value' do
let(:result) { original.send(method, 'C') }
it 'preserves the original values' do
result
original.should eql(S['A', 'B', 'C'])
end
it 'returns self' do
result.should equal(original)
end
end
it 'can add nil to a set' do
original.add(nil).should eql(S['A', 'B', 'C', nil])
end
it 'works on large sets, with many combinations of input' do
50.times do
# Array#sample is buggy on RBX 2.5.8; that's why #uniq is needed here
# See https://github.com/rubinius/rubinius/issues/3506
array = (1..500).to_a.sample(100).uniq
set = S.new(array)
to_add = 1000 + rand(1000)
set.add(to_add).size.should == array.size + 1
set.add(to_add).include?(to_add).should == true
end
end
end
end
describe '#add?' do
context 'with a unique value' do
let(:result) { original.add?('D') }
it 'preserves the original' do
original.should eql(S['A', 'B', 'C'])
end
it 'returns a copy with the superset of values' do
result.should eql(S['A', 'B', 'C', 'D'])
end
end
context 'with a duplicate value' do
let(:result) { original.add?('C') }
it 'preserves the original values' do
original.should eql(S['A', 'B', 'C'])
end
it 'returns false' do
result.should equal(false)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/grep_spec.rb 0000644 0001750 0001750 00000002477 14201005456 023440 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
let(:set) { S[*values] }
describe '#grep' do
let(:grep) { set.grep(String, &block) }
shared_examples 'check filtered values' do
it 'returns the filtered values' do
expect(grep).to eq(S[*filtered])
end
end
shared_examples 'check different types of inputs' do
context 'with an empty set' do
let(:values) { [] }
let(:filtered) { [] }
include_examples 'check filtered values'
end
context 'with a single item set' do
let(:values) { ['A'] }
let(:filtered) { ['A'] }
include_examples 'check filtered values'
end
context "with a single item set that doesn't contain match" do
let(:values) { [1] }
let(:filtered) { [] }
include_examples 'check filtered values'
end
context "with a multi-item set where one isn't a match" do
let(:values) { ['A', 2, 'C'] }
let(:filtered) { %w[A C] }
include_examples 'check filtered values'
end
end
context 'without a block' do
let(:block) { nil }
include_examples 'check different types of inputs'
end
describe 'with a block' do
let(:block) { ->(item) { item }}
include_examples 'check different types of inputs'
end
end
end
immutable-ruby-master/spec/lib/immutable/set/select_spec.rb 0000644 0001750 0001750 00000004260 14201005456 023752 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:select, :find_all].each do |method|
describe "##{method}" do
let(:set) { S['A', 'B', 'C'] }
context 'when everything matches' do
it 'returns self' do
set.send(method) { |item| true }.should equal(set)
end
end
context 'when only some things match' do
context 'with a block' do
let(:result) { set.send(method) { |item| item == 'A' }}
it 'preserves the original' do
result
set.should eql(S['A', 'B', 'C'])
end
it 'returns a set with the matching values' do
result.should eql(S['A'])
end
end
context 'with no block' do
it 'returns an Enumerator' do
set.send(method).class.should be(Enumerator)
set.send(method).each { |item| item == 'A' }.should eql(S['A'])
end
end
end
context 'when nothing matches' do
let(:result) { set.send(method) { |item| false }}
it 'preserves the original' do
result
set.should eql(S['A', 'B', 'C'])
end
it 'returns the canonical empty set' do
result.should equal(Immutable::EmptySet)
end
end
context 'from a subclass' do
it 'returns an instance of the same class' do
subclass = Class.new(Immutable::Set)
instance = subclass.new(['A', 'B', 'C'])
instance.send(method) { true }.class.should be(subclass)
instance.send(method) { false }.class.should be(subclass)
instance.send(method) { rand(2) == 0 }.class.should be(subclass)
end
end
it 'works on a large set, with many combinations of input' do
items = (1..1000).to_a
original = S.new(items)
30.times do
threshold = rand(1000)
result = original.send(method) { |item| item <= threshold }
result.size.should == threshold
result.each { |item| item.should <= threshold }
(threshold+1).upto(1000) { |item| result.include?(item).should == false }
end
original.should eql(S.new(items))
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/sorting_spec.rb 0000644 0001750 0001750 00000003711 14201005456 024160 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[
[:sort, ->(left, right) { left.length <=> right.length }],
[:sort_by, ->(item) { item.length }],
].each do |method, comparator|
describe "##{method}" do
[
[[], []],
[['A'], ['A']],
[%w[Ichi Ni San], %w[Ni San Ichi]],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
describe 'with a block' do
let(:result) { set.send(method, &comparator) }
it "returns #{expected.inspect}" do
result.should eql(SS.new(expected, &comparator))
result.to_a.should == expected
end
it "doesn't change the original Set" do
result
set.should eql(S.new(values))
end
end
describe 'without a block' do
let(:result) { set.send(method) }
it "returns #{expected.sort.inspect}" do
result.should eql(SS[*expected])
result.to_a.should == expected.sort
end
it "doesn't change the original Set" do
result
set.should eql(S.new(values))
end
end
end
end
end
end
describe '#sort_by' do
# originally this test checked that #sort_by only called the block once
# for each item
# however, when initializing a SortedSet, we need to make sure that it
# does not include any duplicates, and we use the block when checking that
# the real point here is that the block should not be called an excessive
# number of times, degrading performance
it 'calls the passed block no more than twice for each item' do
count = 0
fn = lambda { |x| count += 1; -x }
items = 100.times.collect { rand(10000) }.uniq
S[*items].sort_by(&fn).to_a.should == items.sort.reverse
count.should <= (items.length * 2)
end
end
end
immutable-ruby-master/spec/lib/immutable/set/difference_spec.rb 0000644 0001750 0001750 00000002621 14201005456 024564 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:difference, :subtract, :-].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], ['A']],
[['A'], ['A'], []],
[%w[A B C], ['B'], %w[A C]],
[%w[A B C], %w[A C], ['B']],
[%w[A B C D E F G H], [], %w[A B C D E F G H]],
[%w[A B C M X Y Z], %w[B C D E F G H I J X], %w[A M Y Z]]
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
let(:set_a) { S[*a] }
let(:set_b) { S[*b] }
let(:result) { set_a.send(method, set_b) }
it "doesn't modify the original Sets" do
result
set_a.should eql(S.new(a))
set_b.should eql(S.new(b))
end
it "returns #{expected.inspect}" do
result.should eql(S[*expected])
end
end
context 'when passed a Ruby Array' do
it 'returns the expected Set' do
S[*a].difference(b.freeze).should eql(S[*expected])
end
end
end
it 'works on a wide variety of inputs' do
items = ('aa'..'zz').to_a
50.times do
array1 = items.sample(200)
array2 = items.sample(200)
result = S.new(array1).send(method, S.new(array2))
result.to_a.sort.should eql((array1 - array2).sort)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/eql_spec.rb 0000644 0001750 0001750 00000004664 14201005456 023264 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable::Set do
let(:set) { S[*values] }
let(:comparison) { S[*comparison_values] }
describe '#eql?' do
let(:eql?) { set.eql?(comparison) }
shared_examples 'comparing non-sets' do
let(:values) { %w[A B C] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'when comparing to a standard set' do
let(:comparison) { ::Set.new(%w[A B C]) }
include_examples 'comparing non-sets'
end
context 'when comparing to a arbitrary object' do
let(:comparison) { Object.new }
include_examples 'comparing non-sets'
end
context 'when comparing with a subclass of Immutable::Set' do
let(:comparison) { Class.new(Immutable::Set).new(%w[A B C]) }
include_examples 'comparing non-sets'
end
context 'with an empty set for each comparison' do
let(:values) { [] }
let(:comparison_values) { [] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with an empty set and a set with nil' do
let(:values) { [] }
let(:comparison_values) { [nil] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with a single item array and empty array' do
let(:values) { ['A'] }
let(:comparison_values) { [] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with matching single item array' do
let(:values) { ['A'] }
let(:comparison_values) { ['A'] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with mismatching single item array' do
let(:values) { ['A'] }
let(:comparison_values) { ['B'] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with a multi-item array and single item array' do
let(:values) { %w[A B] }
let(:comparison_values) { ['A'] }
it 'returns false' do
expect(eql?).to eq(false)
end
end
context 'with matching multi-item array' do
let(:values) { %w[A B] }
let(:comparison_values) { %w[A B] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
context 'with a mismatching multi-item array' do
let(:values) { %w[A B] }
let(:comparison_values) { %w[B A] }
it 'returns true' do
expect(eql?).to eq(true)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/include_spec.rb 0000644 0001750 0001750 00000003303 14201005456 024113 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable::Set do
[:include?, :member?].each do |method|
describe "##{method}" do
let(:set) { S['A', 'B', 'C', 2.0, nil] }
['A', 'B', 'C', 2.0, nil].each do |value|
it "returns true for an existing value (#{value.inspect})" do
set.send(method, value).should == true
end
end
it 'returns false for a non-existing value' do
set.send(method, 'D').should == false
end
it 'returns true even if existing value is nil' do
S[nil].include?(nil).should == true
end
it 'returns true even if existing value is false' do
S[false].include?(false).should == true
end
it 'returns false for a mutable item which is mutated after adding' do
item = ['mutable']
item = [rand(1000000)] while (item.hash.abs & 31 == [item[0], 'HOSED!'].hash.abs & 31)
set = S[item]
item.push('HOSED!')
set.include?(item).should == false
end
it 'uses #eql? for equality' do
set.send(method, 2).should == false
end
it 'returns the right answers after a lot of addings and removings' do
array, set, rb_set = [], S.new, ::Set.new
1000.times do
if rand(2) == 0
array << (item = rand(10000))
rb_set.add(item)
set = set.add(item)
set.include?(item).should == true
else
item = array.sample
rb_set.delete(item)
set = set.delete(item)
set.include?(item).should == false
end
end
array.each { |item| set.include?(item).should == rb_set.include?(item) }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/group_by_spec.rb 0000644 0001750 0001750 00000003357 14201005456 024327 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:group_by, :group, :classify].each do |method|
describe "##{method}" do
context 'with a block' do
[
[[], []],
[[1], [true => S[1]]],
[[1, 2, 3, 4], [true => S[3, 1], false => S[4, 2]]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:set) { S[*values] }
it "returns #{expected.inspect}" do
set.send(method, &:odd?).should eql(H[*expected])
set.should eql(S.new(values)) # make sure it hasn't changed
end
end
end
end
context 'without a block' do
[
[[], []],
[[1], [1 => S[1]]],
[[1, 2, 3, 4], [1 => S[1], 2 => S[2], 3 => S[3], 4 => S[4]]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:set) { S[*values] }
it "returns #{expected.inspect}" do
set.group_by.should eql(H[*expected])
set.should eql(S.new(values)) # make sure it hasn't changed
end
end
end
end
context 'on an empty set' do
it 'returns an empty hash' do
S.empty.group_by { |x| x }.should eql(H.empty)
end
end
it 'returns a hash without default proc' do
S[1,2,3].group_by { |x| x }.default_proc.should be_nil
end
context 'from a subclass' do
it 'returns an Hash whose values are instances of the subclass' do
subclass = Class.new(Immutable::Set)
instance = subclass.new([1, 'string', :symbol])
instance.group_by(&:class).values.each { |v| v.class.should be(subclass) }
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/clear_spec.rb 0000644 0001750 0001750 00000001330 14201005456 023554 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#clear' do
[
[],
['A'],
%w[A B C],
].each do |values|
describe "on #{values}" do
let(:set) { S[*values] }
it 'preserves the original' do
set.clear
set.should eql(S[*values])
end
it 'returns an empty set' do
set.clear.should equal(S.empty)
end
end
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::Set)
instance = subclass.new([:a, :b, :c, :d])
instance.clear.class.should be(subclass)
instance.clear.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/superset_spec.rb 0000644 0001750 0001750 00000002616 14201005456 024350 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:superset?, :>=].each do |method|
describe "##{method}" do
[
[[], [], true],
[['A'], [], true],
[[], ['A'], false],
[['A'], ['A'], true],
[%w[A B C], ['B'], true],
[['B'], %w[A B C], false],
[%w[A B C], %w[A C], true],
[%w[A C], %w[A B C], false],
[%w[A B C], %w[A B C], true],
[%w[A B C], %w[A B C D], false],
[%w[A B C D], %w[A B C], true],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
S[*a].send(method, S[*b]).should == expected
end
end
end
end
end
[:proper_superset?, :>].each do |method|
describe "##{method}" do
[
[[], [], false],
[['A'], [], true],
[[], ['A'], false],
[['A'], ['A'], false],
[%w[A B C], ['B'], true],
[['B'], %w[A B C], false],
[%w[A B C], %w[A C], true],
[%w[A C], %w[A B C], false],
[%w[A B C], %w[A B C], false],
[%w[A B C], %w[A B C D], false],
[%w[A B C D], %w[A B C], true],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
S[*a].send(method, S[*b]).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/to_list_spec.rb 0000644 0001750 0001750 00000001353 14201005456 024150 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#to_list' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
let(:set) { S[*values] }
let(:list) { set.to_list }
it 'returns a list' do
list.is_a?(Immutable::List).should == true
end
it "doesn't change the original Set" do
list
set.should eql(S.new(values))
end
describe 'the returned list' do
it 'has the correct length' do
list.size.should == values.size
end
it 'contains all values' do
list.to_a.sort.should == values.sort
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/disjoint_spec.rb 0000644 0001750 0001750 00000001212 14201005456 024310 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#disjoint?' do
[
[[], [], true],
[['A'], [], true],
[[], ['A'], true],
[['A'], ['A'], false],
[%w[A B C], ['B'], false],
[['B'], %w[A B C], false],
[%w[A B C], %w[D E], true],
[%w[F G H I], %w[A B C], true],
[%w[A B C], %w[A B C], false],
[%w[A B C], %w[A B C D], false],
[%w[D E F G], %w[A B C], true],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
S[*a].disjoint?(S[*b]).should be(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/intersection_spec.rb 0000644 0001750 0001750 00000003116 14201005456 025200 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:intersection, :&].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], []],
[['A'], ['A'], ['A']],
[%w[A B C], ['B'], ['B']],
[%w[A B C], %w[A C], %w[A C]],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
let(:set_a) { S[*a] }
let(:set_b) { S[*b] }
it "returns #{expected.inspect}, without changing the original Sets" do
set_a.send(method, set_b).should eql(S[*expected])
set_a.should eql(S.new(a))
set_b.should eql(S.new(b))
end
end
context "for #{b.inspect} and #{a.inspect}" do
let(:set_a) { S[*a] }
let(:set_b) { S[*b] }
it "returns #{expected.inspect}, without changing the original Sets" do
set_b.send(method, set_a).should eql(S[*expected])
set_a.should eql(S.new(a))
set_b.should eql(S.new(b))
end
end
context 'when passed a Ruby Array' do
it 'returns the expected Set' do
S[*a].send(method, b.freeze).should eql(S[*expected])
end
end
end
it 'returns results consistent with Array#&' do
50.times do
array1 = rand(100).times.map { rand(1000000).to_s(16) }
array2 = rand(100).times.map { rand(1000000).to_s(16) }
result = S.new(array1).send(method, S.new(array2))
result.to_a.sort.should eql((array1 & array2).sort)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/union_spec.rb 0000644 0001750 0001750 00000003651 14201005456 023626 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:union, :|, :+, :merge].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], ['A']],
[['A'], ['A'], ['A']],
[[], ['A'], ['A']],
[%w[A B C], [], %w[A B C]],
[%w[A B C], %w[A B C], %w[A B C]],
[%w[A B C], %w[X Y Z], %w[A B C X Y Z]]
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
let(:set_a) { S[*a] }
let(:set_b) { S[*b] }
it "returns #{expected.inspect}, without changing the original Sets" do
set_a.send(method, set_b).should eql(S[*expected])
set_a.should eql(S.new(a))
set_b.should eql(S.new(b))
end
end
context "for #{b.inspect} and #{a.inspect}" do
let(:set_a) { S[*a] }
let(:set_b) { S[*b] }
it "returns #{expected.inspect}, without changing the original Sets" do
set_b.send(method, set_a).should eql(S[*expected])
set_a.should eql(S.new(a))
set_b.should eql(S.new(b))
end
end
context 'when passed a Ruby Array' do
it 'returns the expected Set' do
S[*a].send(method, b.freeze).should eql(S[*expected])
S[*b].send(method, a.freeze).should eql(S[*expected])
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Set)
subclass.new(a).send(method, S.new(b)).class.should be(subclass)
subclass.new(b).send(method, S.new(a)).class.should be(subclass)
end
end
end
context 'when receiving a subset' do
let(:set_a) { S.new(1..300) }
let(:set_b) { S.new(1..200) }
it 'returns self' do
set_a.send(method, set_b).should be(set_a)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/compact_spec.rb 0000644 0001750 0001750 00000001226 14201005456 024120 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#compact' do
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[[nil], []],
[[nil, 'B'], ['B']],
[['A', nil], ['A']],
[[nil, nil], []],
[['A', nil, 'C'], %w[A C]],
[[nil, 'B', nil], ['B']],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
it 'preserves the original' do
set.compact
set.should eql(S[*values])
end
it "returns #{expected.inspect}" do
set.compact.should eql(S[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/none_spec.rb 0000644 0001750 0001750 00000002334 14201005456 023432 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#none?' do
context 'when empty' do
it 'with a block returns true' do
S.empty.none? {}.should == true
end
it 'with no block returns true' do
S.empty.none?.should == true
end
end
context 'when not empty' do
context 'with a block' do
let(:set) { S['A', 'B', 'C', nil] }
['A', 'B', 'C', nil].each do |value|
it "returns false if the block ever returns true (#{value.inspect})" do
set.none? { |item| item == value }.should == false
end
end
it 'returns true if the block always returns false' do
set.none? { |item| item == 'D' }.should == true
end
it 'stops iterating as soon as the block returns true' do
yielded = []
set.none? { |item| yielded << item; true }
yielded.size.should == 1
end
end
context 'with no block' do
it 'returns false if any value is truthy' do
S[nil, false, true, 'A'].none?.should == false
end
it 'returns true if all values are falsey' do
S[nil, false].none?.should == true
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/maximum_spec.rb 0000644 0001750 0001750 00000001525 14201005456 024151 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#max' do
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
let(:result) { set.max { |maximum, item| maximum.length <=> item.length }}
it "returns #{expected.inspect}" do
result.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'San'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
S[*values].max.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/first_spec.rb 0000644 0001750 0001750 00000001250 14201005456 023616 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#first' do
context 'on an empty set' do
it 'returns nil' do
S.empty.first.should be_nil
end
end
context 'on a non-empty set' do
it 'returns an arbitrary value from the set' do
%w[A B C].include?(S['A', 'B', 'C'].first).should == true
end
end
it 'returns nil if only member of set is nil' do
S[nil].first.should be(nil)
end
it 'returns the first item yielded by #each' do
10.times do
set = S.new((rand(10)+1).times.collect { rand(10000 )})
set.each { |item| break item }.should be(set.first)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/one_spec.rb 0000644 0001750 0001750 00000002302 14201005456 023247 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#one?' do
context 'when empty' do
it 'with a block returns false' do
S.empty.one? {}.should == false
end
it 'with no block returns false' do
S.empty.one?.should == false
end
end
context 'when not empty' do
context 'with a block' do
let(:set) { S['A', 'B', 'C'] }
it 'returns false if the block returns true more than once' do
set.one? { |item| true }.should == false
end
it 'returns false if the block never returns true' do
set.one? { |item| false }.should == false
end
it 'returns true if the block only returns true once' do
set.one? { |item| item == 'A' }.should == true
end
end
context 'with no block' do
it 'returns false if more than one value is truthy' do
S[nil, true, 'A'].one?.should == false
end
it 'returns true if only one value is truthy' do
S[nil, true, false].one?.should == true
end
it 'returns false if no values are truthy' do
S[nil, false].one?.should == false
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/count_spec.rb 0000644 0001750 0001750 00000001422 14201005456 023620 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#count' do
[
[[], 0],
[[1], 1],
[[1, 2], 1],
[[1, 2, 3], 2],
[[1, 2, 3, 4], 2],
[[1, 2, 3, 4, 5], 3],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
set.count(&:odd?).should == expected
end
end
context 'without a block' do
it 'returns length' do
set.count.should == set.length
end
end
end
end
it 'works on large sets' do
set = Immutable::Set.new(1..2000)
set.count.should == 2000
set.count(&:odd?).should == 1000
end
end
end
immutable-ruby-master/spec/lib/immutable/set/grep_v_spec.rb 0000644 0001750 0001750 00000002563 14201005456 023761 0 ustar boutil boutil require 'spec_helper'
require 'immutable/set'
describe Immutable::Set do
let(:set) { S[*values] }
describe '#grep_v' do
let(:grep_v) { set.grep_v(String, &block) }
shared_examples 'check filtered values' do
it 'returns the filtered values' do
expect(grep_v).to eq(S[*filtered])
end
end
context 'without a block' do
let(:block) { nil }
context 'with an empty set' do
let(:values) { [] }
let(:filtered) { [] }
include_examples 'check filtered values'
end
context 'with a single item set' do
let(:values) { ['A'] }
let(:filtered) { [] }
include_examples 'check filtered values'
end
context "with a single item set that doesn't contain match" do
let(:values) { [1] }
let(:filtered) { [1] }
include_examples 'check filtered values'
end
context "with a multi-item set where one isn't a match" do
let(:values) { [2, 'C', 4] }
let(:filtered) { [2, 4] }
include_examples 'check filtered values'
end
end
describe 'with a block' do
let(:block) { ->(item) { item + 100 }}
context 'resulting items are processed with the block' do
let(:values) { [2, 'C', 4] }
let(:filtered) { [102, 104] }
include_examples 'check filtered values'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/exclusion_spec.rb 0000644 0001750 0001750 00000002470 14201005456 024505 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:exclusion, :^].each do |method|
describe "##{method}" do
[
[[], [], []],
[['A'], [], ['A']],
[['A'], ['A'], []],
[%w[A B C], ['B'], %w[A C]],
[%w[A B C], %w[B C D], %w[A D]],
[%w[A B C], %w[D E F], %w[A B C D E F]],
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
let(:set_a) { S[*a] }
let(:set_b) { S[*b] }
let(:result) { set_a.send(method, set_b) }
it "doesn't modify the original Sets" do
result
set_a.should eql(S.new(a))
set_b.should eql(S.new(b))
end
it "returns #{expected.inspect}" do
result.should eql(S[*expected])
end
end
context 'when passed a Ruby Array' do
it 'returns the expected Set' do
S[*a].exclusion(b.freeze).should eql(S[*expected])
end
end
end
it 'works for a wide variety of inputs' do
50.times do
array1 = (1..400).to_a.sample(100)
array2 = (1..400).to_a.sample(100)
result = S.new(array1) ^ S.new(array2)
result.to_a.sort.should eql(((array1 | array2) - (array1 & array2)).sort)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/reduce_spec.rb 0000644 0001750 0001750 00000002734 14201005456 023746 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:reduce, :inject].each do |method|
describe "##{method}" do
[
[[], 10, 10],
[[1], 10, 9],
[[1, 2, 3], 10, 4],
].each do |values, initial, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
context "with an initial value of #{initial}" do
context 'and a block' do
it "returns #{expected.inspect}" do
set.send(method, initial) { |memo, item| memo - item }.should == expected
end
end
end
end
end
[
[[], nil],
[[1], 1],
[[1, 2, 3], 6],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
context 'with no initial value' do
context 'and a block' do
it "returns #{expected.inspect}" do
set.send(method) { |memo, item| memo + item }.should == expected
end
end
end
end
end
describe 'with no block and a symbol argument' do
it 'uses the symbol as the name of a method to reduce with' do
S[1, 2, 3].reduce(:+).should == 6
end
end
describe 'with no block and a string argument' do
it 'uses the string as the name of a method to reduce with' do
S[1, 2, 3].reduce('+').should == 6
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/sum_spec.rb 0000644 0001750 0001750 00000000723 14201005456 023277 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#sum' do
[
[[], 0],
[[2], 2],
[[1, 3, 5, 7, 11], 27],
].each do |values, expected|
context "on #{values.inspect}" do
let(:set) { S[*values] }
it "returns #{expected.inspect}" do
set.sum.should == expected
end
it "doesn't change the original Set" do
set.should eql(S.new(values))
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/map_spec.rb 0000644 0001750 0001750 00000003234 14201005456 023250 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:map, :collect].each do |method|
describe "##{method}" do
context 'when empty' do
it 'returns self' do
S.empty.send(method) {}.should equal(S.empty)
end
end
context 'when not empty' do
let(:set) { S['A', 'B', 'C'] }
context 'with a block' do
it 'preserves the original values' do
set.send(method, &:downcase)
set.should eql(S['A', 'B', 'C'])
end
it 'returns a new set with the mapped values' do
set.send(method, &:downcase).should eql(S['a', 'b', 'c'])
end
end
context 'with no block' do
it 'returns an Enumerator' do
set.send(method).class.should be(Enumerator)
set.send(method).each(&:downcase).should == S['a', 'b', 'c']
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Set)
instance = subclass['a', 'b']
instance.map(&:upcase).class.should be(subclass)
end
end
context 'when multiple items map to the same value' do
it 'filters out the duplicates' do
set = S.new('aa'..'zz')
result = set.map { |s| s[0] }
result.should eql(Immutable::Set.new('a'..'z'))
result.size.should == 26
end
end
it 'works on large sets' do
set = S.new(1..1000)
result = set.map { |x| x * 10 }
result.size.should == 1000
1.upto(1000) { |n| result.include?(n * 10).should == true }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/reverse_each_spec.rb 0000644 0001750 0001750 00000001526 14201005456 025130 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable::Set do
let(:set) { S['A', 'B', 'C'] }
describe '#reverse_each' do
let(:reverse_each) { set.reverse_each(&block) }
context 'without a block' do
let(:block) { nil }
it 'returns an Enumerator' do
expect(reverse_each.class).to be(Enumerator)
expect(reverse_each.to_a).to eq(set.to_a.reverse)
end
end
context 'with an empty block' do
let(:block) { ->(item) {} }
it 'returns self' do
expect(reverse_each).to be(set)
end
end
context 'with a block' do
let(:items) { ::Set.new }
let(:values) { ::Set.new(%w[A B C]) }
let(:block) { ->(item) { items << item } }
before(:each) { reverse_each }
it 'yields all values' do
expect(items).to eq(values)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/hash_spec.rb 0000644 0001750 0001750 00000001271 14201005456 023415 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#hash' do
context 'on an empty set' do
it 'returns 0' do
S.empty.hash.should == 0
end
end
it 'generates the same hash value for a set regardless of the order things were added to it' do
item1 = DeterministicHash.new('a', 121)
item2 = DeterministicHash.new('b', 474)
item3 = DeterministicHash.new('c', 121)
S.empty.add(item1).add(item2).add(item3).hash.should == S.empty.add(item3).add(item2).add(item1).hash
end
it 'values are sufficiently distributed' do
(1..4000).each_slice(4).map { |a, b, c, d| S[a, b, c, d].hash }.uniq.size.should == 1000
end
end
end
immutable-ruby-master/spec/lib/immutable/set/copying_spec.rb 0000644 0001750 0001750 00000000367 14201005456 024147 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
[:dup, :clone].each do |method|
let(:set) { S['A', 'B', 'C'] }
describe "##{method}" do
it 'returns self' do
set.send(method).should equal(set)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/partition_spec.rb 0000644 0001750 0001750 00000002652 14201005456 024507 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#partition' do
[
[[], [], []],
[[1], [1], []],
[[1, 2], [1], [2]],
[[1, 2, 3], [1, 3], [2]],
[[1, 2, 3, 4], [1, 3], [2, 4]],
[[2, 3, 4], [3], [2, 4]],
[[3, 4], [3], [4]],
[[4], [], [4]],
].each do |values, expected_matches, expected_remainder|
context "on #{values.inspect}" do
let(:set) { S[*values] }
context 'with a block' do
let(:result) { set.partition(&:odd?) }
let(:matches) { result.first }
let(:remainder) { result.last }
it 'preserves the original' do
result
set.should eql(S[*values])
end
it 'returns a frozen array with two items' do
result.class.should be(Array)
result.should be_frozen
result.size.should be(2)
end
it 'correctly identifies the matches' do
matches.should eql(S[*expected_matches])
end
it 'correctly identifies the remainder' do
remainder.should eql(S[*expected_remainder])
end
end
describe 'without a block' do
it 'returns an Enumerator' do
set.partition.class.should be(Enumerator)
set.partition.each(&:odd?).should eql([S.new(expected_matches), S.new(expected_remainder)])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/set/to_set_spec.rb 0000644 0001750 0001750 00000000506 14201005456 023767 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Set do
describe '#to_set' do
[
[],
['A'],
%w[A B C],
].each do |values|
describe "on #{values.inspect}" do
let(:set) { S[*values] }
it 'returns self' do
set.to_set.should equal(set)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/ 0000755 0001750 0001750 00000000000 14201005456 021442 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/deque/new_spec.rb 0000644 0001750 0001750 00000002230 14201005456 023567 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '.new' do
it 'accepts a single enumerable argument and creates a new deque' do
deque = Immutable::Deque.new([1,2,3])
deque.size.should be(3)
deque.first.should be(1)
deque.dequeue.first.should be(2)
deque.dequeue.dequeue.first.should be(3)
end
it 'is amenable to overriding of #initialize' do
class SnazzyDeque < Immutable::Deque
def initialize
super(['SNAZZY!!!'])
end
end
deque = SnazzyDeque.new
deque.size.should be(1)
deque.to_a.should == ['SNAZZY!!!']
end
context 'from a subclass' do
it 'returns a frozen instance of the subclass' do
subclass = Class.new(Immutable::Deque)
instance = subclass.new(['some', 'values'])
instance.class.should be subclass
instance.frozen?.should be true
end
end
end
describe '.[]' do
it 'accepts a variable number of items and creates a new deque' do
deque = Immutable::Deque['a', 'b']
deque.size.should be(2)
deque.first.should == 'a'
deque.dequeue.first.should == 'b'
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/to_ary_spec.rb 0000644 0001750 0001750 00000001326 14201005456 024300 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
let(:deque) { D['A', 'B', 'C', 'D'] }
describe '#to_ary' do
context 'enables implicit conversion to' do
it 'block parameters' do
def func(&block)
yield(deque)
end
func do |a, b, *c|
expect(a).to eq('A')
expect(b).to eq('B')
expect(c).to eq(%w[C D])
end
end
it 'method arguments' do
def func(a, b, *c)
expect(a).to eq('A')
expect(b).to eq('B')
expect(c).to eq(%w[C D])
end
func(*deque)
end
it 'works with splat' do
array = *deque
expect(array).to eq(%w[A B C D])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/size_spec.rb 0000644 0001750 0001750 00000000642 14201005456 023755 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
[:size, :length].each do |method|
describe "##{method}" do
[
[[], 0],
[['A'], 1],
[%w[A B C], 3],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
D[*values].send(method).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/construction_spec.rb 0000644 0001750 0001750 00000001304 14201005456 025531 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '.[]' do
context 'with no arguments' do
it 'always returns the same instance' do
D[].class.should be(Immutable::Deque)
D[].should equal(D[])
end
it 'returns an empty, frozen deque' do
D[].should be_empty
D[].should be_frozen
end
end
context 'with a number of items' do
let(:deque) { D['A', 'B', 'C'] }
it 'always returns a different instance' do
deque.should_not equal(D['A', 'B', 'C'])
end
it 'is the same as repeatedly using #endeque' do
deque.should eql(D.empty.enqueue('A').enqueue('B').enqueue('C'))
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/pop_spec.rb 0000644 0001750 0001750 00000001512 14201005456 023576 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#pop' do
[
[[], []],
[['A'], []],
[%w[A B C], %w[A B]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:deque) { D[*values] }
it 'preserves the original' do
deque.pop
deque.should eql(D[*values])
end
it "returns #{expected.inspect}" do
deque.pop.should eql(D[*expected])
end
it 'returns a frozen instance' do
deque.pop.should be_frozen
end
end
end
context 'on empty subclass' do
let(:subclass) { Class.new(Immutable::Deque) }
let(:empty_instance) { subclass.new }
it 'returns an empty object of the same class' do
empty_instance.pop.class.should be subclass
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/push_spec.rb 0000644 0001750 0001750 00000001642 14201005456 023763 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#push' do
[
[[], 'A', ['A']],
[['A'], 'B', %w[A B]],
[%w[A B C], 'D', %w[A B C D]],
].each do |original, item, expected|
context "pushing #{item.inspect} into #{original.inspect}" do
let(:deque) { D.new(original) }
it 'preserves the original' do
deque.push(item)
deque.should eql(D.new(original))
end
it "returns #{expected.inspect}" do
deque.push(item).should eql(D.new(expected))
end
it 'returns a frozen instance' do
deque.push(item).should be_frozen
end
end
end
context 'on a subclass' do
let(:subclass) { Class.new(Immutable::Deque) }
let(:empty_instance) { subclass.new }
it 'returns an object of same class' do
empty_instance.push(1).class.should be subclass
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/inspect_spec.rb 0000644 0001750 0001750 00000001114 14201005456 024443 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#inspect' do
[
[[], 'Immutable::Deque[]'],
[['A'], 'Immutable::Deque["A"]'],
[%w[A B C], 'Immutable::Deque["A", "B", "C"]']
].each do |values, expected|
context "on #{values.inspect}" do
let(:deque) { D[*values] }
it "returns #{expected.inspect}" do
deque.inspect.should == expected
end
it "returns a string which can be eval'd to get an equivalent object" do
eval(deque.inspect).should eql(deque)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/marshal_spec.rb 0000644 0001750 0001750 00000002036 14201005456 024431 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#marshal_dump/#marshal_load' do
let(:ruby) do
File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
end
let(:child_cmd) do
%Q|#{ruby} -I lib -r immutable -e 'deque = Immutable::Deque[5, 10, 15]; $stdout.write(Marshal.dump(deque))'|
end
let(:reloaded_deque) do
IO.popen(child_cmd, 'r+') do |child|
reloaded_deque = Marshal.load(child)
child.close
reloaded_deque
end
end
it 'can survive dumping and loading into a new process' do
expect(reloaded_deque).to eql(D[5, 10, 15])
end
it 'is still possible to push and pop items after loading' do
expect(reloaded_deque.first).to eq(5)
expect(reloaded_deque.last).to eq(15)
expect(reloaded_deque.push(20)).to eql(D[5, 10, 15, 20])
expect(reloaded_deque.pop).to eql(D[5, 10])
expect(reloaded_deque.unshift(1)).to eql(D[1, 5, 10, 15])
expect(reloaded_deque.shift).to eql(D[10, 15])
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/empty_spec.rb 0000644 0001750 0001750 00000001742 14201005456 024143 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#empty?' do
[
[[], true],
[['A'], false],
[%w[A B C], false],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
D[*values].empty?.should == expected
end
end
end
context "after dedequeing an item from #{%w[A B C].inspect}" do
it 'returns false' do
D['A', 'B', 'C'].dequeue.should_not be_empty
end
end
end
describe '.empty' do
it 'returns the canonical empty deque' do
D.empty.size.should be(0)
D.empty.class.should be(Immutable::Deque)
D.empty.object_id.should be(Immutable::EmptyDeque.object_id)
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::Deque)
subclass.empty.class.should be(subclass)
subclass.empty.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/enqueue_spec.rb 0000644 0001750 0001750 00000001310 14201005456 024443 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
[:enqueue, :push].each do |method|
describe "##{method}" do
[
[[], 'A', ['A']],
[['A'], 'B', %w[A B]],
[['A'], 'A', %w[A A]],
[%w[A B C], 'D', %w[A B C D]],
].each do |values, new_value, expected|
describe "on #{values.inspect} with #{new_value.inspect}" do
let(:deque) { D[*values] }
it 'preserves the original' do
deque.send(method, new_value)
deque.should eql(D[*values])
end
it "returns #{expected.inspect}" do
deque.send(method, new_value).should eql(D[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/to_a_spec.rb 0000644 0001750 0001750 00000001155 14201005456 023725 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
[:to_a, :entries].each do |method|
describe "##{method}" do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
it "returns #{values.inspect}" do
D[*values].send(method).should == values
end
it 'returns a mutable array' do
result = D[*values].send(method)
expect(result.last).to_not eq('The End')
result << 'The End'
result.last.should == 'The End'
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/pretty_print_spec.rb 0000644 0001750 0001750 00000001106 14201005456 025542 0 ustar boutil boutil require 'spec_helper'
require 'pp'
require 'stringio'
describe Immutable::Deque do
describe '#pretty_print' do
let(:deque) { Immutable::Deque['AAAA', 'BBBB', 'CCCC'] }
let(:stringio) { StringIO.new }
it 'prints the whole Deque on one line if it fits' do
PP.pp(deque, stringio, 80)
stringio.string.chomp.should == 'Immutable::Deque["AAAA", "BBBB", "CCCC"]'
end
it 'prints each item on its own line, if not' do
PP.pp(deque, stringio, 10)
stringio.string.chomp.should == 'Immutable::Deque[
"AAAA",
"BBBB",
"CCCC"]'
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/last_spec.rb 0000644 0001750 0001750 00000000531 14201005456 023743 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#last' do
[
[[], nil],
[['A'], 'A'],
[%w[A B C], 'C'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
D[*values].last.should eql(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/random_modification_spec.rb 0000644 0001750 0001750 00000001573 14201005456 027014 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe 'modification (using #push, #pop, #shift, and #unshift)' do
it 'works when applied in many random combinations' do
array = [1,2,3]
deque = Immutable::Deque.new(array)
1000.times do
case [:push, :pop, :shift, :unshift].sample
when :push
value = rand(10000)
array.push(value)
deque = deque.push(value)
when :pop
array.pop
deque = deque.pop
when :shift
array.shift
deque = deque.shift
when :unshift
value = rand(10000)
array.unshift(value)
deque = deque.unshift(value)
end
deque.to_a.should eql(array)
deque.size.should == array.size
deque.first.should == array.first
deque.last.should == array.last
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/rotate_spec.rb 0000644 0001750 0001750 00000004111 14201005456 024274 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
# Deques can have items distributed differently between the 'front' and 'rear' lists
# and still be equivalent
# Since the implementation of #rotate depends on how items are distributed between the
# two lists, we need to test both the case where most items are on the 'front' and
# where most are on the 'rear'
big_front = D.alloc(L.from_enum([1, 2, 3]), L.from_enum([5, 4]))
big_rear = D.alloc(L.from_enum([1, 2]), L.from_enum([5, 4, 3]))
describe '#rotate' do
[
[[], 9999, []],
[['A'], -1, ['A']],
[['A', 'B', 'C'], -1, ['B', 'C', 'A']],
[['A', 'B', 'C', 'D'], 0, ['A', 'B', 'C', 'D']],
[%w[A B C D], 2, %w[C D A B]],
].each do |values, rotation, expected|
context "on #{values.inspect}" do
let(:deque) { D[*values] }
it 'preserves the original' do
deque.rotate(rotation)
deque.should eql(D[*values])
end
it "returns #{expected.inspect}" do
deque.rotate(rotation).should eql(D[*expected])
end
it 'returns a frozen instance' do
deque.rotate(rotation).should be_frozen
end
end
end
context "on a Deque with most items on 'front' list" do
it 'works with a small rotation' do
big_front.rotate(2).should eql(D[4, 5, 1, 2, 3])
end
it 'works with a larger rotation' do
big_front.rotate(4).should eql(D[2, 3, 4, 5, 1])
end
end
context "on a Deque with most items on 'rear' list" do
it 'works with a small rotation' do
big_rear.rotate(2).should eql(D[4, 5, 1, 2, 3])
end
it 'works with a larger rotation' do
big_rear.rotate(4).should eql(D[2, 3, 4, 5, 1])
end
end
context 'on empty subclass' do
let(:subclass) { Class.new(Immutable::Deque) }
let(:empty_instance) { subclass.new }
it 'returns an empty object of the same class' do
empty_instance.rotate(1).class.should be subclass
empty_instance.rotate(-1).class.should be subclass
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/clear_spec.rb 0000644 0001750 0001750 00000001304 14201005456 024065 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#clear' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values}" do
let(:deque) { D[*values] }
it 'preserves the original' do
deque.clear
deque.should eql(D[*values])
end
it 'returns an empty deque' do
deque.clear.should equal(D.empty)
end
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Deque)
instance = subclass.new([1,2])
instance.clear.should be_empty
instance.clear.class.should be(subclass)
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/to_list_spec.rb 0000644 0001750 0001750 00000001071 14201005456 024455 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#to_list' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
it "returns a list containing #{values.inspect}" do
D[*values].to_list.should eql(L[*values])
end
end
end
context "after dedequeing an item from #{%w[A B C].inspect}" do
it "returns a list containing #{%w[B C].inspect}" do
list = D['A', 'B', 'C'].dequeue.to_list
list.should eql(L['B', 'C'])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/first_spec.rb 0000644 0001750 0001750 00000000531 14201005456 024127 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#first' do
[
[[], nil],
[['A'], 'A'],
[%w[A B C], 'A'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
D[*values].first.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/dequeue_spec.rb 0000644 0001750 0001750 00000001530 14201005456 024435 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
[:dequeue, :shift].each do |method|
describe "##{method}" do
[
[[], []],
[['A'], []],
[%w[A B C], %w[B C]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:deque) { D[*values] }
it 'preserves the original' do
deque.send(method)
deque.should eql(D[*values])
end
it "returns #{expected.inspect}" do
deque.send(method).should eql(D[*expected])
end
end
end
end
context 'on empty subclass' do
let(:subclass) { Class.new(Immutable::Deque) }
let(:empty_instance) { subclass.new }
it 'returns empty object of same class' do
empty_instance.send(method).class.should be subclass
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/shift_spec.rb 0000644 0001750 0001750 00000001131 14201005456 024112 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#shift' do
[
[[], []],
[['A'], []],
[%w[A B C], %w[B C]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:deque) { D.new(values) }
it 'preserves the original' do
deque.shift
deque.should eql(D.new(values))
end
it "returns #{expected.inspect}" do
deque.shift.should eql(D.new(expected))
end
it 'returns a frozen instance' do
deque.shift.should be_frozen
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/unshift_spec.rb 0000644 0001750 0001750 00000001326 14201005456 024463 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
describe '#unshift' do
[
[[], 'A', ['A']],
[['A'], 'B', %w[B A]],
[['A'], 'A', %w[A A]],
[%w[A B C], 'D', %w[D A B C]],
].each do |values, new_value, expected|
context "on #{values.inspect} with #{new_value.inspect}" do
let(:deque) { D[*values] }
it 'preserves the original' do
deque.unshift(new_value)
deque.should eql(D[*values])
end
it "returns #{expected.inspect}" do
deque.unshift(new_value).should eql(D[*expected])
end
it 'returns a frozen instance' do
deque.unshift(new_value).should be_frozen
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/deque/copying_spec.rb 0000644 0001750 0001750 00000000535 14201005456 024454 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Deque do
[:dup, :clone].each do |method|
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
let(:deque) { D[*values] }
it 'returns self' do
deque.send(method).should equal(deque)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/ 0000755 0001750 0001750 00000000000 14201005456 021262 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/hash/key_spec.rb 0000644 0001750 0001750 00000001355 14201005456 023415 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#key' do
let(:hash) { H[a: 1, b: 1, c: 2, d: 3] }
it 'returns a key associated with the given value, if there is one' do
[:a, :b].include?(hash.key(1)).should == true
hash.key(2).should be(:c)
hash.key(3).should be(:d)
end
it 'returns nil if there is no key associated with the given value' do
hash.key(5).should be_nil
hash.key(0).should be_nil
end
it 'uses #== to compare values for equality' do
hash.key(EqualNotEql.new).should_not be_nil
hash.key(EqlNotEqual.new).should be_nil
end
it "doesn't use default block if value is not found" do
H.new(a: 1) { fail }.key(2).should be_nil
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/new_spec.rb 0000644 0001750 0001750 00000003657 14201005456 023425 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '.new' do
it 'is amenable to overriding of #initialize' do
class SnazzyHash < Immutable::Hash
def initialize
super({'snazzy?' => 'oh yeah'})
end
end
SnazzyHash.new['snazzy?'].should == 'oh yeah'
end
context 'from a subclass' do
it 'returns a frozen instance of the subclass' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new('some' => 'values')
instance.class.should be(subclass)
instance.frozen?.should be true
end
end
it 'accepts an array as initializer' do
H.new([['a', 'b'], ['c', 'd']]).should eql(H['a' => 'b', 'c' => 'd'])
end
it "returns a Hash which doesn't change even if initializer is mutated" do
rbhash = {a: 1, b: 2}
hash = H.new(rbhash)
rbhash[:a] = 'BAD'
hash.should eql(H[a: 1, b: 2])
end
end
describe '.[]' do
it 'accepts a Ruby Hash as initializer' do
hash = H[a: 1, b: 2]
hash.class.should be(Immutable::Hash)
hash.size.should == 2
hash.key?(:a).should == true
hash.key?(:b).should == true
end
it 'accepts a Immutable::Hash as initializer' do
hash = H[H.new(a: 1, b: 2)]
hash.class.should be(Immutable::Hash)
hash.size.should == 2
hash.key?(:a).should == true
hash.key?(:b).should == true
end
it 'accepts an array as initializer' do
hash = H[[[:a, 1], [:b, 2]]]
hash.class.should be(Immutable::Hash)
hash.size.should == 2
hash.key?(:a).should == true
hash.key?(:b).should == true
end
it 'can be used with a subclass of Immutable::Hash' do
subclass = Class.new(Immutable::Hash)
instance = subclass[a: 1, b: 2]
instance.class.should be(subclass)
instance.size.should == 2
instance.key?(:a).should == true
instance.key?(:b).should == true
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/size_spec.rb 0000644 0001750 0001750 00000002546 14201005456 023602 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:size, :length].each do |method|
describe "##{method}" do
[
[[], 0],
[['A' => 'aye'], 1],
[['A' => 'bee', 'B' => 'bee', 'C' => 'see'], 3],
].each do |values, result|
it "returns #{result} for #{values.inspect}" do
H[*values].send(method).should == result
end
end
lots = (1..10_842).to_a
srand 89_533_474
random_things = (lots + lots).sort_by { |x|rand }
it 'has the correct size after adding lots of things with colliding keys and such' do
h = H.empty
random_things.each do |thing|
h = h.put(thing, thing * 2)
end
h.size.should == 10_842
end
random_actions = (lots.map { |x|[:add, x] } + lots.map { |x|[:add, x] } + lots.map { |x|[:remove, x] }).sort_by { |x|rand }
ending_size = random_actions.reduce({}) do |h, (act, ob)|
if act == :add
h[ob] = 1
else
h.delete(ob)
end
h
end.size
it 'has the correct size after lots of addings and removings' do
h = H.empty
random_actions.each do |(act, ob)|
if act == :add
h = h.put(ob, ob * 3)
else
h = h.delete(ob)
end
end
h.size.should == ending_size
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/construction_spec.rb 0000644 0001750 0001750 00000001642 14201005456 025356 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '.hash' do
context 'with nothing' do
it 'returns the canonical empty hash' do
H.empty.should be_empty
H.empty.should equal(Immutable::EmptyHash)
end
end
context 'with an implicit hash' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
it 'is equivalent to repeatedly using #put' do
hash.should eql(H.empty.put('A', 'aye').put('B', 'bee').put('C', 'see'))
hash.size.should == 3
end
end
context 'with an array of pairs' do
let(:hash) { H[[[:a, 1], [:b, 2]]] }
it 'initializes a new Hash' do
hash.should eql(H[a: 1, b: 2])
end
end
context 'with an Immutable::Hash' do
let(:hash) { H[a: 1, b: 2] }
let(:other) { H[hash] }
it 'initializes an equivalent Hash' do
hash.should eql(other)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/sort_spec.rb 0000644 0001750 0001750 00000001330 14201005456 023605 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H[a: 3, b: 2, c: 1] }
describe '#sort' do
it 'returns a Vector of sorted key/val pairs' do
hash.sort.should eql(V[[:a, 3], [:b, 2], [:c, 1]])
end
it 'works on large hashes' do
array = (1..1000).map { |n| [n,n] }
H.new(array.shuffle).sort.should eql(V.new(array))
end
it 'uses block as comparator to sort if passed a block' do
hash.sort { |a,b| b <=> a }.should eql(V[[:c, 1], [:b, 2], [:a, 3]])
end
end
describe '#sort_by' do
it 'returns a Vector of key/val pairs, sorted using the block as a key function' do
hash.sort_by { |k,v| v }.should eql(V[[:c, 1], [:b, 2], [:a, 3]])
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/reject_spec.rb 0000644 0001750 0001750 00000004116 14201005456 024077 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:reject, :delete_if].each do |method|
describe "##{method}" do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'when nothing matches' do
it 'returns self' do
hash.send(method) { |key, value| false }.should equal(hash)
end
end
context 'when only some things match' do
context 'with a block' do
let(:result) { hash.send(method) { |key, value| key == 'A' && value == 'aye' }}
it 'preserves the original' do
result
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a set with the matching values' do
result.should eql(H['B' => 'bee', 'C' => 'see'])
end
it 'yields entries in the same order as #each' do
each_pairs = []
remove_pairs = []
hash.each_pair { |k,v| each_pairs << [k,v] }
hash.send(method) { |k,v| remove_pairs << [k,v] }
each_pairs.should == remove_pairs
end
end
context 'with no block' do
it 'returns an Enumerator' do
hash.send(method).class.should be(Enumerator)
hash.send(method).to_a.sort.should == [['A', 'aye'], ['B', 'bee'], ['C', 'see']]
hash.send(method).each { true }.should eql(H.empty)
end
end
context 'on a large hash, with many combinations of input' do
it 'still works' do
array = 1000.times.collect { |n| [n, n] }
hash = H.new(array)
[0, 10, 100, 200, 500, 800, 900, 999, 1000].each do |threshold|
result = hash.send(method) { |k,v| k >= threshold}
result.size.should == threshold
0.upto(threshold-1) { |n| result.key?(n).should == true }
threshold.upto(1000) { |n| result.key?(n).should == false }
end
# shouldn't have changed
hash.should eql(H.new(1000.times.collect { |n| [n, n] }))
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/flatten_spec.rb 0000644 0001750 0001750 00000007736 14201005456 024273 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#flatten' do
context 'with flatten depth of zero' do
it 'returns a vector of keys/value' do
hash = H[a: 1, b: 2]
hash.flatten(0).sort.should eql(V[[:a, 1], [:b, 2]])
end
end
context 'without array keys or values' do
it 'returns a vector of keys and values' do
hash = H[a: 1, b: 2, c: 3]
possibilities = [[:a, 1, :b, 2, :c, 3],
[:a, 1, :c, 3, :b, 2],
[:b, 2, :a, 1, :c, 3],
[:b, 2, :c, 3, :a, 1],
[:c, 3, :a, 1, :b, 2],
[:c, 3, :b, 2, :a, 1]]
possibilities.include?(hash.flatten).should == true
possibilities.include?(hash.flatten(1)).should == true
possibilities.include?(hash.flatten(2)).should == true
hash.flatten(2).class.should be(Immutable::Vector)
possibilities.include?(hash.flatten(10)).should == true
end
it "doesn't modify the receiver" do
hash = H[a: 1, b: 2, c: 3]
hash.flatten(1)
hash.flatten(2)
hash.should eql(H[a: 1, b: 2, c: 3])
end
end
context 'on an empty Hash' do
it 'returns an empty Vector' do
H.empty.flatten.should eql(V.empty)
end
end
context 'with array keys' do
it 'flattens array keys into returned vector if flatten depth is sufficient' do
hash = H[[1, 2] => 3, [4, 5] => 6]
[[[1, 2], 3, [4, 5], 6], [[4, 5], 6, [1, 2], 3]].include?(hash.flatten(1)).should == true
[[[1, 2], 3, [4, 5], 6], [[4, 5], 6, [1, 2], 3]].include?(hash.flatten).should == true
hash.flatten(1).class.should be(Immutable::Vector)
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(2)).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(3)).should == true
end
it "doesn't modify the receiver (or its contents)" do
hash = H[[1, 2] => 3, [4, 5] => 6]
hash.flatten(1)
hash.flatten(2)
hash.should eql(H[[1, 2] => 3, [4, 5] => 6])
end
end
context 'with array values' do
it 'flattens array values into returned vector if flatten depth is sufficient' do
hash = H[1 => [2, 3], 4 => [5, 6]]
[[1, [2, 3], 4, [5, 6]], [4, [5, 6], 1, [2, 3]]].include?(hash.flatten(1)).should == true
[[1, [2, 3], 4, [5, 6]], [4, [5, 6], 1, [2, 3]]].include?(hash.flatten).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(2)).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(3)).should == true
hash.flatten(3).class.should be(Immutable::Vector)
end
it "doesn't modify the receiver (or its contents)" do
hash = H[1 => [2, 3], 4 => [5, 6]]
hash.flatten(1)
hash.flatten(2)
hash.should eql(H[1 => [2, 3], 4 => [5, 6]])
end
end
context 'with vector keys' do
it 'flattens vector keys into returned vector if flatten depth is sufficient' do
hash = H[V[1, 2] => 3, V[4, 5] => 6]
[[V[1, 2], 3, V[4, 5], 6], [V[4, 5], 6, V[1, 2], 3]].include?(hash.flatten).should == true
[[V[1, 2], 3, V[4, 5], 6], [V[4, 5], 6, V[1, 2], 3]].include?(hash.flatten(1)).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(2)).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(3)).should == true
end
end
context 'with vector values' do
it 'flattens vector values into returned vector if flatten depth is sufficient' do
hash = H[1 => V[2, 3], 4 => V[5, 6]]
[[1, V[2, 3], 4, V[5, 6]], [4, V[5, 6], 1, V[2, 3]]].include?(hash.flatten(1)).should == true
[[1, V[2, 3], 4, V[5, 6]], [4, V[5, 6], 1, V[2, 3]]].include?(hash.flatten).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(2)).should == true
[[1, 2, 3, 4, 5, 6], [4, 5, 6, 1, 2, 3]].include?(hash.flatten(3)).should == true
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/dig_spec.rb 0000644 0001750 0001750 00000001773 14201005456 023374 0 ustar boutil boutil require 'spec_helper'
require 'immutable/hash'
describe Immutable::Hash do
describe '#dig' do
let(:h) { H[:a => 9, :b => H[:c => 'a', :d => 4], :e => nil] }
it 'returns the value with one argument to dig' do
expect(h.dig(:a)).to eq(9)
end
it 'returns the value in nested hashes' do
expect(h.dig(:b, :c)).to eq('a')
end
it 'returns nil if the key is not present' do
expect(h.dig(:f, :foo)).to eq(nil)
end
it 'returns nil if you dig out the end of the hash' do
expect(h.dig(:f, :foo, :bar)).to eq(nil)
end
# This is a bit different from Ruby's Hash; it raises TypeError for
# objects which don't respond to #dig
it 'raises a NoMethodError if a value does not support #dig' do
expect { h.dig(:a, :foo) }.to raise_error(NoMethodError)
end
it 'returns the correct value when there is a default proc' do
default_hash = H.new { |k, v| "#{k}-default" }
expect(default_hash.dig(:a)).to eq('a-default')
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/values_spec.rb 0000644 0001750 0001750 00000001135 14201005456 024120 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#values' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
let(:result) { hash.values }
it 'returns the keys as a Vector' do
result.should be_a Immutable::Vector
result.to_a.sort.should == %w(aye bee see)
end
context 'with duplicates' do
let(:hash) { H[:A => 15, :B => 19, :C => 15] }
let(:result) { hash.values }
it 'returns the keys as a Vector' do
result.class.should be(Immutable::Vector)
result.to_a.sort.should == [15, 15, 19]
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/merge_spec.rb 0000644 0001750 0001750 00000004664 14201005456 023732 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#merge' do
[
[{}, {}, {}],
[{'A' => 'aye'}, {}, {'A' => 'aye'}],
[{'A' => 'aye'}, {'A' => 'bee'}, {'A' => 'bee'}],
[{'A' => 'aye'}, {'B' => 'bee'}, {'A' => 'aye', 'B' => 'bee'}],
[(1..300).zip(1..300), (150..450).zip(150..450), (1..450).zip(1..450)]
].each do |a, b, expected|
context "for #{a.inspect} and #{b.inspect}" do
let(:hash_a) { H[a] }
let(:hash_b) { H[b] }
let(:result) { hash_a.merge(hash_b) }
it "returns #{expected.inspect} when passed an Immutable::Hash" do
result.should eql(H[expected])
end
it "returns #{expected.inspect} when passed a Ruby Hash" do
H[a].merge(::Hash[b]).should eql(H[expected])
end
it "doesn't change the original Hashes" do
result
hash_a.should eql(H[a])
hash_b.should eql(H[b])
end
end
end
context 'when merging with an empty Hash' do
it 'returns self' do
hash = H[a: 1, b: 2]
hash.merge(H.empty).should be(hash)
end
end
context 'when merging with subset Hash' do
it 'returns self' do
big_hash = H[(1..300).zip(1..300)]
small_hash = H[(1..200).zip(1..200)]
big_hash.merge(small_hash).should be(big_hash)
end
end
context 'when called on a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new(a: 1, b: 2)
instance.merge(c: 3, d: 4).class.should be(subclass)
end
end
it 'sets any duplicate key to the value of block if passed a block' do
h1 = H[a: 2, b: 1, d: 5]
h2 = H[a: -2, b: 4, c: -3]
r = h1.merge(h2) { |k,x,y| nil }
r.should eql(H[a: nil, b: nil, c: -3, d: 5])
r = h1.merge(h2) { |k,x,y| "#{k}:#{x+2*y}" }
r.should eql(H[a: 'a:-2', b: 'b:9', c: -3, d: 5])
lambda {
h1.merge(h2) { |k, x, y| raise(IndexError) }
}.should raise_error(IndexError)
r = h1.merge(h1) { |k,x,y| :x }
r.should eql(H[a: :x, b: :x, d: :x])
end
it 'yields key/value pairs in the same order as #each' do
hash = H[a: 1, b: 2, c: 3]
each_pairs = []
merge_pairs = []
hash.each { |k, v| each_pairs << [k, v] }
hash.merge(hash) { |k, v1, v2| merge_pairs << [k, v1] }
each_pairs.should == merge_pairs
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/sample_spec.rb 0000644 0001750 0001750 00000000577 14201005456 024113 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#sample' do
let(:hash) { Immutable::Hash.new((:a..:z).zip(1..26)) }
it 'returns a randomly chosen item' do
chosen = 250.times.map { hash.sample }.sort.uniq
chosen.each { |item| hash.include?(item[0]).should == true }
hash.each { |item| chosen.include?(item).should == true }
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/any_spec.rb 0000644 0001750 0001750 00000002603 14201005456 023411 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#any?' do
context 'when empty' do
it 'with a block returns false' do
H.empty.any? {}.should == false
end
it 'with no block returns false' do
H.empty.any?.should == false
end
end
context 'when not empty' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'] }
context 'with a block' do
[
%w[A aye],
%w[B bee],
%w[C see],
[nil, 'NIL'],
].each do |pair|
it "returns true if the block ever returns true (#{pair.inspect})" do
hash.any? { |key, value| key == pair.first && value == pair.last }.should == true
end
it 'returns false if the block always returns false' do
hash.any? { |key, value| key == 'D' && value == 'dee' }.should == false
end
end
it 'propagates exceptions raised in the block' do
-> { hash.any? { |k,v| raise 'help' } }.should raise_error(RuntimeError)
end
it 'stops iterating as soon as the block returns true' do
yielded = []
hash.any? { |k,v| yielded << k; true }
yielded.size.should == 1
end
end
context 'with no block' do
it 'returns true' do
hash.any?.should == true
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/subset_spec.rb 0000644 0001750 0001750 00000002277 14201005456 024136 0 ustar boutil boutil require 'spec_helper'
require 'immutable/hash'
describe Immutable::Hash do
describe '#<=' do
[
[{}, {}, true],
[{'A' => 1}, {}, false],
[{}, {'A' => 1}, true],
[{'A' => 1}, {'A' => 1}, true],
[{'A' => 1}, {'A' => 2}, false],
[{'B' => 2}, {'A' => 1, 'B' => 2, 'C' => 3}, true],
[{'A' => 1, 'B' => 2, 'C' => 3}, {'B' => 2}, false],
[{'B' => 0}, {'A' => 1, 'B' => 2, 'C' => 3}, false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
expect(H[a] <= H[b]).to eq(expected)
end
end
end
end
describe '#<' do
[
[{}, {}, false],
[{'A' => 1}, {}, false],
[{}, {'A' => 1}, true],
[{'A' => 1}, {'A' => 1}, false],
[{'A' => 1}, {'A' => 2}, false],
[{'B' => 2}, {'A' => 1, 'B' => 2, 'C' => 3}, true],
[{'A' => 1, 'B' => 2, 'C' => 3}, {'B' => 2}, false],
[{'B' => 0}, {'A' => 1, 'B' => 2, 'C' => 3}, false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
expect(H[a] < H[b]).to eq(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/get_spec.rb 0000644 0001750 0001750 00000004144 14201005456 023403 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:get, :[]].each do |method|
describe "##{method}" do
context 'with a default block' do
let(:hash) { H.new('A' => 'aye') { |key| fail }}
context 'when the key exists' do
it 'returns the value associated with the key' do
hash.send(method, 'A').should == 'aye'
end
it "does not call the default block even if the key is 'nil'" do
H.new(nil => 'something') { fail }.send(method, nil)
end
end
context 'when the key does not exist' do
let(:hash) do
H.new('A' => 'aye') do |key|
expect(key).to eq('B')
'bee'
end
end
it 'returns the value from the default block' do
hash.send(method, 'B').should == 'bee'
end
end
end
context 'with no default block' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'] }
[
%w[A aye],
%w[B bee],
%w[C see],
[nil, 'NIL']
].each do |key, value|
it "returns the value (#{value.inspect}) for an existing key (#{key.inspect})" do
hash.send(method, key).should == value
end
end
it 'returns nil for a non-existing key' do
hash.send(method, 'D').should be_nil
end
end
it 'uses #hash to look up keys' do
x = double('0')
x.should_receive(:hash).and_return(0)
H[foo: :bar].send(method, x).should be_nil
end
it 'uses #eql? to compare keys with the same hash code' do
x = double('x', hash: 42)
x.should_not_receive(:eql?)
y = double('y', hash: 42)
y.should_receive(:eql?).and_return(true)
H[y => 1][x].should == 1
end
it 'does not use #eql? to compare keys with different hash codes' do
x = double('x', hash: 0)
x.should_not_receive(:eql?)
y = double('y', hash: 1)
y.should_not_receive(:eql?)
H[y => 1][x].should be_nil
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/inspect_spec.rb 0000644 0001750 0001750 00000001614 14201005456 024270 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#inspect' do
[
[[], 'Immutable::Hash[]'],
[['A' => 'aye'], 'Immutable::Hash["A" => "aye"]'],
[[DeterministicHash.new('A', 1) => 'aye', DeterministicHash.new('B', 2) => 'bee', DeterministicHash.new('C', 3) => 'see'], 'Immutable::Hash["A" => "aye", "B" => "bee", "C" => "see"]']
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
H[*values].inspect.should == expected
end
end
end
[
{},
{'A' => 'aye'},
{a: 'aye', b: 'bee', c: 'see'}
].each do |values|
describe "on #{values.inspect}" do
it "returns a string which can be eval'd to get an equivalent object" do
original = H.new(values)
eval(original.inspect).should eql(original)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/keys_spec.rb 0000644 0001750 0001750 00000000516 14201005456 023576 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#keys' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
it 'returns the keys as a set' do
hash.keys.should eql(S['A', 'B', 'C'])
end
it 'returns frozen String keys' do
hash.keys.each { |s| s.should be_frozen }
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/to_hash_spec.rb 0000644 0001750 0001750 00000001070 14201005456 024244 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:to_hash, :to_h].each do |method|
describe "##{method}" do
it 'converts an empty Immutable::Hash to an empty Ruby Hash' do
H.empty.send(method).should eql({})
end
it 'converts a non-empty Immutable::Hash to a Hash with the same keys and values' do
H[a: 1, b: 2].send(method).should eql({a: 1, b: 2})
end
it "doesn't modify the receiver" do
hash = H[a: 1, b: 2]
hash.send(method)
hash.should eql(H[a: 1, b: 2])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/default_proc_spec.rb 0000644 0001750 0001750 00000004007 14201005456 025271 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#default_proc' do
let(:hash) { H.new(1 => 2, 2 => 4) { |k| k * 2 } }
it 'returns the default block given when the Hash was created' do
hash.default_proc.class.should be(Proc)
hash.default_proc.call(3).should == 6
end
it 'returns nil if no default block was given' do
H.empty.default_proc.should be_nil
end
context 'after a key/val pair are inserted' do
it "doesn't change" do
other = hash.put(3, 6)
other.default_proc.should be(hash.default_proc)
other.default_proc.call(4).should == 8
end
end
context 'after all key/val pairs are filtered out' do
it "doesn't change" do
other = hash.reject { true }
other.default_proc.should be(hash.default_proc)
other.default_proc.call(4).should == 8
end
end
context 'after Hash is inverted' do
it "doesn't change" do
other = hash.invert
other.default_proc.should be(hash.default_proc)
other.default_proc.call(4).should == 8
end
end
context 'when a slice is taken' do
it "doesn't change" do
other = hash.slice(1)
other.default_proc.should be(hash.default_proc)
other.default_proc.call(5).should == 10
end
end
context 'when keys are removed with #except' do
it "doesn't change" do
other = hash.except(1, 2)
other.default_proc.should be(hash.default_proc)
other.default_proc.call(5).should == 10
end
end
context 'when Hash is mapped' do
it "doesn't change" do
other = hash.map { |k,v| [k + 10, v] }
other.default_proc.should be(hash.default_proc)
other.default_proc.call(5).should == 10
end
end
context 'when another Hash is merged in' do
it "doesn't change" do
other = hash.merge(3 => 6, 4 => 8)
other.default_proc.should be(hash.default_proc)
other.default_proc.call(5).should == 10
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/marshal_spec.rb 0000644 0001750 0001750 00000001504 14201005456 024250 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#marshal_dump/#marshal_load' do
let(:ruby) do
File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
end
let(:child_cmd) do
%Q|#{ruby} -I lib -r immutable -e 'dict = Immutable::Hash[existing_key: 42, other_thing: "data"]; $stdout.write(Marshal.dump(dict))'|
end
let(:reloaded_hash) do
IO.popen(child_cmd, 'r+') do |child|
reloaded_hash = Marshal.load(child)
child.close
reloaded_hash
end
end
it 'can survive dumping and loading into a new process' do
expect(reloaded_hash).to eql(H[existing_key: 42, other_thing: 'data'])
end
it 'is still possible to find items by key after loading' do
expect(reloaded_hash[:existing_key]).to eq(42)
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/flat_map_spec.rb 0000644 0001750 0001750 00000002202 14201005456 024400 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
describe '#flat_map' do
it 'yields each key/val pair' do
passed = []
hash.flat_map { |pair| passed << pair }
passed.sort.should == [['A', 'aye'], ['B', 'bee'], ['C', 'see']]
end
it 'returns the concatenation of block return values' do
hash.flat_map { |k,v| [k,v] }.sort.should == ['A', 'B', 'C', 'aye', 'bee', 'see']
hash.flat_map { |k,v| L[k,v] }.sort.should == ['A', 'B', 'C', 'aye', 'bee', 'see']
hash.flat_map { |k,v| V[k,v] }.sort.should == ['A', 'B', 'C', 'aye', 'bee', 'see']
end
it "doesn't change the receiver" do
hash.flat_map { |k,v| [k,v] }
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
context 'with no block' do
it 'returns an Enumerator' do
hash.flat_map.class.should be(Enumerator)
hash.flat_map.each { |k,v| [k] }.sort.should == ['A', 'B', 'C']
end
end
it 'returns an empty array if only empty arrays are returned by block' do
hash.flat_map { [] }.should eql([])
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/find_spec.rb 0000644 0001750 0001750 00000002524 14201005456 023544 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:find, :detect].each do |method|
describe "##{method}" do
[
[[], 'A', nil],
[[], nil, nil],
[['A' => 'aye'], 'A', ['A', 'aye']],
[['A' => 'aye'], 'B', nil],
[['A' => 'aye'], nil, nil],
[['A' => 'aye', 'B' => 'bee', nil => 'NIL'], 'A', ['A', 'aye']],
[['A' => 'aye', 'B' => 'bee', nil => 'NIL'], 'B', ['B', 'bee']],
[['A' => 'aye', 'B' => 'bee', nil => 'NIL'], nil, [nil, 'NIL']],
[['A' => 'aye', 'B' => 'bee', nil => 'NIL'], 'C', nil],
].each do |values, key, expected|
describe "on #{values.inspect}" do
let(:hash) { H[*values] }
describe 'with a block' do
it "returns #{expected.inspect}" do
hash.send(method) { |k, v| k == key }.should == expected
end
end
describe 'without a block' do
it 'returns an Enumerator' do
result = hash.send(method)
result.class.should be(Enumerator)
result.each { |k,v| k == key }.should == expected
end
end
end
end
it 'stops iterating when the block returns true' do
yielded = []
H[a: 1, b: 2].find { |k,v| yielded << k; true }
yielded.size.should == 1
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/empty_spec.rb 0000644 0001750 0001750 00000002202 14201005456 023753 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#empty?' do
[
[[], true],
[['A' => 'aye'], false],
[['A' => 'aye', 'B' => 'bee', 'C' => 'see'], false],
].each do |pairs, result|
it "returns #{result} for #{pairs.inspect}" do
H[*pairs].empty?.should == result
end
end
it 'returns true for empty hashes which have a default block' do
H.new { 'default' }.empty?.should == true
end
end
describe '.empty' do
it 'returns the canonical empty Hash' do
H.empty.should be_empty
H.empty.should be(Immutable::EmptyHash)
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::Hash)
subclass.empty.class.should be subclass
subclass.empty.should be_empty
end
it 'calls overridden #initialize when creating empty Hash' do
subclass = Class.new(Immutable::Hash) do
def initialize
@variable = 'value'
end
end
subclass.empty.instance_variable_get(:@variable).should == 'value'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/to_a_spec.rb 0000644 0001750 0001750 00000000540 14201005456 023542 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#to_a' do
it 'returns an Array of [key, value] pairs in same order as #each' do
hash = H[:a => 1, 1 => :a, 3 => :b, :b => 5]
pairs = []
hash.each_pair { |k,v| pairs << [k,v] }
hash.to_a.should be_kind_of(Array)
hash.to_a.should == pairs
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/fetch_spec.rb 0000644 0001750 0001750 00000003376 14201005456 023723 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#fetch' do
context 'with no default provided' do
context 'when the key exists' do
it 'returns the value associated with the key' do
H['A' => 'aye'].fetch('A').should == 'aye'
end
end
context 'when the key does not exist' do
it 'raises a KeyError' do
-> { H['A' => 'aye'].fetch('B') }.should raise_error(KeyError)
end
end
end
context 'with a default value' do
context 'when the key exists' do
it 'returns the value associated with the key' do
H['A' => 'aye'].fetch('A', 'default').should == 'aye'
end
end
context 'when the key does not exist' do
it 'returns the default value' do
H['A' => 'aye'].fetch('B', 'default').should == 'default'
end
end
end
context 'with a default block' do
context 'when the key exists' do
it 'returns the value associated with the key' do
H['A' => 'aye'].fetch('A') { 'default'.upcase }.should == 'aye'
end
end
context 'when the key does not exist' do
it 'invokes the default block with the missing key as paramter' do
H['A' => 'aye'].fetch('B') { |key| key.should == 'B' }
H['A' => 'aye'].fetch('B') { 'default'.upcase }.should == 'DEFAULT'
end
end
end
it 'gives precedence to default block over default argument if passed both' do
H['A' => 'aye'].fetch('B', 'one') { 'two' }.should == 'two'
end
it 'raises an ArgumentError when not passed one or 2 arguments' do
-> { H.empty.fetch }.should raise_error(ArgumentError)
-> { H.empty.fetch(1, 2, 3) }.should raise_error(ArgumentError)
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/update_in_spec.rb 0000644 0001750 0001750 00000004750 14201005456 024577 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#update_in' do
let(:hash) {
Immutable::Hash[
'A' => 'aye',
'B' => Immutable::Hash['C' => 'see', 'D' => Immutable::Hash['E' => 'eee']],
'F' => Immutable::Vector['G', Immutable::Hash['H' => 'eitch'], 'I']
]
}
context 'with one level on existing key' do
it 'passes the value to the block' do
hash.update_in('A') { |value| value.should == 'aye' }
end
it 'replaces the value with the result of the block' do
result = hash.update_in('A') { |value| 'FLIBBLE' }
result.get('A').should == 'FLIBBLE'
end
it 'should preserve the original' do
result = hash.update_in('A') { |value| 'FLIBBLE' }
hash.get('A').should == 'aye'
end
end
context 'with multi-level on existing keys' do
it 'passes the value to the block' do
hash.update_in('B', 'D', 'E') { |value| value.should == 'eee' }
end
it 'replaces the value with the result of the block' do
result = hash.update_in('B', 'D', 'E') { |value| 'FLIBBLE' }
result['B']['D']['E'].should == 'FLIBBLE'
end
it 'should preserve the original' do
result = hash.update_in('B', 'D', 'E') { |value| 'FLIBBLE' }
hash['B']['D']['E'].should == 'eee'
end
end
context "with multi-level creating sub-hashes when keys don't exist" do
it 'passes nil to the block' do
hash.update_in('B', 'X', 'Y') { |value| value.should be_nil }
end
it 'creates subhashes on the way to set the value' do
result = hash.update_in('B', 'X', 'Y') { |value| 'NEWVALUE' }
result['B']['X']['Y'].should == 'NEWVALUE'
result['B']['D']['E'].should == 'eee'
end
end
context 'with multi-level including vector with existing keys' do
it 'passes the value to the block' do
hash.update_in('F', 1, 'H') { |value| value.should == 'eitch' }
end
it 'replaces the value with the result of the block' do
result = hash.update_in('F', 1, 'H') { |value| 'FLIBBLE' }
result['F'][1]['H'].should == 'FLIBBLE'
end
it 'should preserve the original' do
result = hash.update_in('F', 1, 'H') { |value| 'FLIBBLE' }
hash['F'][1]['H'].should == 'eitch'
end
end
context 'with empty key_path' do
it 'raises ArguemntError' do
expect { hash.update_in() { |v| 42 } }.to raise_error(ArgumentError)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/each_spec.rb 0000644 0001750 0001750 00000004261 14201005456 023524 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
[:each, :each_pair].each do |method|
describe "##{method}" do
context 'with a block (internal iteration)' do
it 'returns self' do
hash.send(method) {}.should be(hash)
end
it 'yields all key/value pairs' do
actual_pairs = {}
hash.send(method) { |key, value| actual_pairs[key] = value }
actual_pairs.should == { 'A' => 'aye', 'B' => 'bee', 'C' => 'see' }
end
it 'yields key/value pairs in the same order as #each_key and #each_value' do
hash.each.to_a.should eql(hash.each_key.zip(hash.each_value))
end
it 'yields both of a pair of colliding keys' do
yielded = []
hash = H[DeterministicHash.new('a', 1) => 1, DeterministicHash.new('b', 1) => 1]
hash.each { |k,v| yielded << k }
yielded.size.should == 2
yielded.map(&:value).sort.should == ['a', 'b']
end
it 'yields only the key to a block expecting |key,|' do
keys = []
hash.each { |key,| keys << key }
keys.sort.should == ['A', 'B', 'C']
end
end
context 'with no block' do
it 'returns an Enumerator' do
@result = hash.send(method)
@result.class.should be(Enumerator)
@result.to_a.should == hash.to_a
end
end
end
end
describe '#each_key' do
it 'yields all keys' do
keys = []
hash.each_key { |k| keys << k }
keys.sort.should == ['A', 'B', 'C']
end
context 'with no block' do
it 'returns an Enumerator' do
hash.each_key.class.should be(Enumerator)
hash.each_key.to_a.sort.should == ['A', 'B', 'C']
end
end
end
describe '#each_value' do
it 'yields all values' do
values = []
hash.each_value { |v| values << v }
values.sort.should == ['aye', 'bee', 'see']
end
context 'with no block' do
it 'returns an Enumerator' do
hash.each_value.class.should be(Enumerator)
hash.each_value.to_a.sort.should == ['aye', 'bee', 'see']
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/invert_spec.rb 0000644 0001750 0001750 00000001463 14201005456 024134 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#invert' do
let(:hash) { H[a: 3, b: 2, c: 1] }
it 'uses the existing keys as values and values as keys' do
hash.invert.should eql(H[3 => :a, 2 => :b, 1 => :c])
end
it 'will select one key/value pair among multiple which have same value' do
[H[1 => :a],
H[1 => :b],
H[1 => :c]].include?(H[a: 1, b: 1, c: 1].invert).should == true
end
it "doesn't change the original Hash" do
hash.invert
hash.should eql(H[a: 3, b: 2, c: 1])
end
context 'from a subclass of Hash' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new(a: 1, b: 2)
instance.invert.class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/has_value_spec.rb 0000644 0001750 0001750 00000001535 14201005456 024574 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H[toast: 'buttered', jam: 'strawberry'] }
[:value?, :has_value?].each do |method|
describe "##{method}" do
it 'returns true if any key/val pair in Hash has the same value' do
hash.send(method, 'strawberry').should == true
end
it 'returns false if no key/val pair in Hash has the same value' do
hash.send(method, 'marmalade').should == false
end
it 'uses #== to check equality' do
H[a: EqualNotEql.new].send(method, EqualNotEql.new).should == true
H[a: EqlNotEqual.new].send(method, EqlNotEqual.new).should == false
end
it 'works on a large hash' do
large = H.new((1..1000).zip(2..1001))
[2, 100, 200, 500, 900, 1000, 1001].each { |n| large.value?(n).should == true }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/store_spec.rb 0000644 0001750 0001750 00000004331 14201005456 023756 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#store' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'with a unique key' do
let(:result) { hash.store('D', 'dee') }
it 'preserves the original' do
result
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a copy with the superset of key/value pairs' do
result.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see', 'D' => 'dee'])
end
end
context 'with a duplicate key' do
let(:result) { hash.store('C', 'sea') }
it 'preserves the original' do
result
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a copy with the superset of key/value pairs' do
result.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'sea'])
end
end
context 'with duplicate key and identical value' do
let(:hash) { H['X' => 1, 'Y' => 2] }
let(:result) { hash.store('X', 1) }
it 'returns the original hash unmodified' do
result.should be(hash)
end
context 'with big hash (force nested tries)' do
let(:keys) { (0..99).map(&:to_s) }
let(:values) { (100..199).to_a }
let(:hash) { H[keys.zip(values)] }
it 'returns the original hash unmodified for all changes' do
keys.each_with_index do |key, index|
result = hash.store(key, values[index])
result.should be(hash)
end
end
end
end
context 'with unequal keys which hash to the same value' do
let(:hash) { H[DeterministicHash.new('a', 1) => 'aye'] }
it 'stores and can retrieve both' do
result = hash.store(DeterministicHash.new('b', 1), 'bee')
result.get(DeterministicHash.new('a', 1)).should eql('aye')
result.get(DeterministicHash.new('b', 1)).should eql('bee')
end
end
context 'when a String is inserted as key and then mutated' do
it 'is not affected' do
string = 'a string!'
hash = H.empty.store(string, 'a value!')
string.upcase!
hash['a string!'].should == 'a value!'
hash['A STRING!'].should be_nil
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/all_spec.rb 0000644 0001750 0001750 00000002374 14201005456 023377 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H[values] }
describe '#all?' do
context 'when empty' do
let(:values) { H.new }
context 'without a block' do
it 'returns true' do
hash.all?.should == true
end
end
context 'with a block' do
it 'returns true' do
hash.all? { false }.should == true
end
end
end
context 'when not empty' do
let(:values) { { 'A' => 1, 'B' => 2, 'C' => 3 } }
context 'without a block' do
it 'returns true' do
hash.all?.should == true
end
end
context 'with a block' do
it 'returns true if the block always returns true' do
hash.all? { true }.should == true
end
it 'returns false if the block ever returns false' do
hash.all? { |k,v| k != 'C' }.should == false
end
it 'propagates an exception from the block' do
-> { hash.all? { |k,v| raise 'help' } }.should raise_error(RuntimeError)
end
it 'stops iterating as soon as the block returns false' do
yielded = []
hash.all? { |k,v| yielded << k; false }
yielded.size.should == 1
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/pretty_print_spec.rb 0000644 0001750 0001750 00000002006 14201005456 025362 0 ustar boutil boutil require 'spec_helper'
require 'pp'
require 'stringio'
describe Immutable::Hash do
describe '#pretty_print' do
let(:hash) { Immutable::Hash.new(DeterministicHash.new(1,1) => 'tin', DeterministicHash.new(2,2) => 'earwax', DeterministicHash.new(3,3) => 'neanderthal') }
let(:stringio) { StringIO.new }
it 'prints the whole Hash on one line if it fits' do
PP.pp(hash, stringio, 80)
stringio.string.chomp.should == 'Immutable::Hash[1 => "tin", 2 => "earwax", 3 => "neanderthal"]'
end
it 'prints each key/val pair on its own line, if not' do
PP.pp(hash, stringio, 20)
stringio.string.chomp.should == 'Immutable::Hash[
1 => "tin",
2 => "earwax",
3 => "neanderthal"]'
end
it 'prints keys and vals on separate lines, if space is very tight' do
PP.pp(hash, stringio, 15)
# the trailing space after "3 =>" below is needed, don't remove it
stringio.string.chomp.should == 'Immutable::Hash[
1 => "tin",
2 => "earwax",
3 =>
"neanderthal"]'
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/delete_spec.rb 0000644 0001750 0001750 00000002006 14201005456 024061 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#delete' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'with an existing key' do
let(:result) { hash.delete('B') }
it 'preserves the original' do
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a copy with the remaining key/value pairs' do
result.should eql(H['A' => 'aye', 'C' => 'see'])
end
end
context 'with a non-existing key' do
let(:result) { hash.delete('D') }
it 'preserves the original values' do
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns self' do
result.should equal(hash)
end
end
context 'when removing the last key' do
context 'from a Hash with no default block' do
it 'returns the canonical empty Hash' do
hash.delete('A').delete('B').delete('C').should be(Immutable::EmptyHash)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/slice_spec.rb 0000644 0001750 0001750 00000002341 14201005456 023720 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H.new('A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL') }
describe '#slice' do
let(:slice) { hash.slice(*values) }
context 'with all keys present in the Hash' do
let(:values) { ['B', nil] }
it 'returns the sliced values' do
expect(slice).to eq(described_class.new('B' => 'bee', nil => 'NIL'))
end
it "doesn't modify the original Hash" do
slice
hash.should eql(H.new('A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'))
end
end
context "with keys aren't present in the Hash" do
let(:values) { ['B', 'A', 3] }
it 'returns the sliced values of the matching keys' do
expect(slice).to eq(described_class.new('A' => 'aye', 'B' => 'bee'))
end
it "doesn't modify the original Hash" do
slice
hash.should eql(H.new('A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'))
end
end
context 'on a Hash with a default block' do
let(:hash) { H.new('A' => 'aye', 'B' => 'bee') { 'nothing' }}
let(:values) { ['B', nil] }
it 'maintains the default block' do
expect(slice['C']).to eq('nothing')
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/to_proc_spec.rb 0000644 0001750 0001750 00000002103 14201005456 024262 0 ustar boutil boutil require 'spec_helper'
require 'immutable/hash'
describe Immutable::Hash do
describe '#to_proc' do
context 'on Hash without default proc' do
let(:hash) { H.new('A' => 'aye') }
it 'returns a Proc instance' do
hash.to_proc.should be_kind_of(Proc)
end
it 'returns a Proc that returns the value of an existing key' do
hash.to_proc.call('A').should == 'aye'
end
it 'returns a Proc that returns nil for a missing key' do
hash.to_proc.call('B').should be_nil
end
end
context 'on Hash with a default proc' do
let(:hash) { H.new('A' => 'aye') { |key| "#{key}-VAL" } }
it 'returns a Proc instance' do
hash.to_proc.should be_kind_of(Proc)
end
it 'returns a Proc that returns the value of an existing key' do
hash.to_proc.call('A').should == 'aye'
end
it "returns a Proc that returns the result of the hash's default proc for a missing key" do
hash.to_proc.call('B').should == 'B-VAL'
hash.should == H.new('A' => 'aye')
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/each_with_index_spec.rb 0000644 0001750 0001750 00000001676 14201005456 025755 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#each_with_index' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
describe 'with a block (internal iteration)' do
it 'returns self' do
hash.each_with_index {}.should be(hash)
end
it 'yields all key/value pairs with numeric indexes' do
actual_pairs = {}
indexes = []
hash.each_with_index { |(key, value), index| actual_pairs[key] = value; indexes << index }
actual_pairs.should == { 'A' => 'aye', 'B' => 'bee', 'C' => 'see' }
indexes.sort.should == [0, 1, 2]
end
end
describe 'with no block' do
it 'returns an Enumerator' do
hash.each_with_index.should be_kind_of(Enumerator)
hash.each_with_index.to_a.map(&:first).sort.should eql([['A', 'aye'], ['B', 'bee'], ['C', 'see']])
hash.each_with_index.to_a.map(&:last).should eql([0,1,2])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/take_spec.rb 0000644 0001750 0001750 00000002502 14201005456 023544 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
describe '#take' do
it 'returns the first N key/val pairs from hash' do
hash.take(0).should == []
[[['A', 'aye']], [['B', 'bee']], [['C', 'see']]].include?(hash.take(1)).should == true
[['A', 'aye'], ['B', 'bee'], ['C', 'see']].combination(2).include?(hash.take(2).sort).should == true
hash.take(3).sort.should == [['A', 'aye'], ['B', 'bee'], ['C', 'see']]
hash.take(4).sort.should == [['A', 'aye'], ['B', 'bee'], ['C', 'see']]
end
end
describe '#take_while' do
it 'passes elements to the block until the block returns nil/false' do
passed = nil
hash.take_while { |k,v| passed = k; false }
['A', 'B', 'C'].include?(passed).should == true
end
it 'returns an array of all elements before the one which returned nil/false' do
count = 0
result = hash.take_while { count += 1; count < 3 }
[['A', 'aye'], ['B', 'bee'], ['C', 'see']].combination(2).include?(result.sort).should == true
end
it 'passes all elements if the block never returns nil/false' do
passed = []
hash.take_while { |k,v| passed << [k, v]; true }.should == hash.to_a
passed.sort.should == [['A', 'aye'], ['B', 'bee'], ['C', 'see']]
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/values_at_spec.rb 0000644 0001750 0001750 00000002166 14201005456 024611 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#values_at' do
context 'on Hash without default proc' do
let(:hash) { H[:a => 9, :b => 'a', :c => -10, :d => nil] }
it 'returns an empty vector when no keys are given' do
hash.values_at.should be_kind_of(Immutable::Vector)
hash.values_at.should eql(V.empty)
end
it 'returns a vector of values for the given keys' do
hash.values_at(:a, :d, :b).should be_kind_of(Immutable::Vector)
hash.values_at(:a, :d, :b).should eql(V[9, nil, 'a'])
end
it 'fills nil when keys are missing' do
hash.values_at(:x, :a, :y, :b).should be_kind_of(Immutable::Vector)
hash.values_at(:x, :a, :y, :b).should eql(V[nil, 9, nil, 'a'])
end
end
context 'on Hash with default proc' do
let(:hash) { Immutable::Hash.new(:a => 9) { |key| "#{key}-VAL" } }
it 'fills the result of the default proc when keys are missing' do
hash.values_at(:x, :a, :y).should be_kind_of(Immutable::Vector)
hash.values_at(:x, :a, :y).should eql(V['x-VAL', 9, 'y-VAL'])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/select_spec.rb 0000644 0001750 0001750 00000003577 14201005456 024114 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:select, :find_all, :keep_if].each do |method|
describe "##{method}" do
let(:original) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'when everything matches' do
it 'returns self' do
original.send(method) { |key, value| true }.should equal(original)
end
end
context 'when only some things match' do
context 'with a block' do
let(:result) { original.send(method) { |key, value| key == 'A' && value == 'aye' }}
it 'preserves the original' do
original.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a set with the matching values' do
result.should eql(H['A' => 'aye'])
end
end
it 'yields entries as [key, value] pairs' do
original.send(method) do |e|
e.should be_kind_of(Array)
['A', 'B', 'C'].include?(e[0]).should == true
['aye', 'bee', 'see'].include?(e[1]).should == true
end
end
context 'with no block' do
it 'returns an Enumerator' do
original.send(method).class.should be(Enumerator)
original.send(method).to_a.sort.should == [['A', 'aye'], ['B', 'bee'], ['C', 'see']]
end
end
end
it 'works on a large hash, with many combinations of input' do
keys = (1..1000).to_a
original = H.new(keys.zip(2..1001))
25.times do
threshold = rand(1000)
result = original.send(method) { |k,v| k <= threshold }
result.size.should == threshold
result.each_key { |k| k.should <= threshold }
(threshold+1).upto(1000) { |k| result.key?(k).should == false }
end
original.should eql(H.new(keys.zip(2..1001))) # shouldn't have changed
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/eql_spec.rb 0000644 0001750 0001750 00000005102 14201005456 023400 0 ustar boutil boutil require 'spec_helper'
require 'bigdecimal'
describe Immutable::Hash do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
describe '#eql?' do
it 'returns false when comparing with a standard hash' do
hash.eql?('A' => 'aye', 'B' => 'bee', 'C' => 'see').should == false
end
it 'returns false when comparing with an arbitrary object' do
hash.eql?(Object.new).should == false
end
it 'returns false when comparing with a subclass of Immutable::Hash' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new('A' => 'aye', 'B' => 'bee', 'C' => 'see')
hash.eql?(instance).should == false
end
end
describe '#==' do
it 'returns true when comparing with a standard hash' do
(hash == {'A' => 'aye', 'B' => 'bee', 'C' => 'see'}).should == true
end
it 'returns false when comparing with an arbitrary object' do
(hash == Object.new).should == false
end
it 'returns true when comparing with a subclass of Immutable::Hash' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new('A' => 'aye', 'B' => 'bee', 'C' => 'see')
(hash == instance).should == true
end
it 'performs numeric conversions between floats and BigDecimals' do
expect(H[a: 0.0] == H[a: BigDecimal('0.0')]).to be true
expect(H[a: BigDecimal('0.0')] == H[a: 0.0]).to be true
end
end
[:eql?, :==].each do |method|
describe "##{method}" do
[
[{}, {}, true],
[{ 'A' => 'aye' }, {}, false],
[{}, { 'A' => 'aye' }, false],
[{ 'A' => 'aye' }, { 'A' => 'aye' }, true],
[{ 'A' => 'aye' }, { 'B' => 'bee' }, false],
[{ 'A' => 'aye', 'B' => 'bee' }, { 'A' => 'aye' }, false],
[{ 'A' => 'aye' }, { 'A' => 'aye', 'B' => 'bee' }, false],
[{ 'A' => 'aye', 'B' => 'bee', 'C' => 'see' }, { 'A' => 'aye', 'B' => 'bee', 'C' => 'see' }, true],
[{ 'C' => 'see', 'A' => 'aye', 'B' => 'bee' }, { 'A' => 'aye', 'B' => 'bee', 'C' => 'see' }, true],
].each do |a, b, expected|
describe "returns #{expected.inspect}" do
it "for #{a.inspect} and #{b.inspect}" do
H[a].send(method, H[b]).should == expected
end
it "for #{b.inspect} and #{a.inspect}" do
H[b].send(method, H[a]).should == expected
end
end
end
end
end
it 'returns true on a large hash which is modified and then modified back again' do
hash = H.new((1..1000).zip(2..1001))
hash.put('a', 1).delete('a').should == hash
hash.put('b', 2).delete('b').should eql(hash)
end
end
immutable-ruby-master/spec/lib/immutable/hash/clear_spec.rb 0000644 0001750 0001750 00000002035 14201005456 023707 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#clear' do
[
[],
['A' => 'aye'],
['A' => 'aye', 'B' => 'bee', 'C' => 'see'],
].each do |values|
context "on #{values}" do
let(:original) { H[*values] }
let(:result) { original.clear }
it 'preserves the original' do
result
original.should eql(H[*values])
end
it 'returns an empty hash' do
result.should equal(H.empty)
result.should be_empty
end
end
end
it 'maintains the default Proc, if there is one' do
hash = H.new(a: 1) { 1 }
hash.clear[:b].should == 1
hash.clear[:c].should == 1
hash.clear.default_proc.should_not be_nil
end
context 'on a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new(a: 1, b: 2)
instance.clear.class.should be(subclass)
instance.clear.should be_empty
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/except_spec.rb 0000644 0001750 0001750 00000002725 14201005456 024117 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#except' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'] }
context 'with only keys that the Hash has' do
it 'returns a Hash without those values' do
hash.except('B', nil).should eql(H['A' => 'aye', 'C' => 'see'])
end
it "doesn't change the original Hash" do
hash.except('B', nil)
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'])
end
end
context "with keys that the Hash doesn't have" do
it 'returns a Hash without the values that it had keys for' do
hash.except('B', 'A', 3).should eql(H['C' => 'see', nil => 'NIL'])
end
it "doesn't change the original Hash" do
hash.except('B', 'A', 3)
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'])
end
end
it 'works on a large Hash, with many combinations of input' do
keys = (1..1000).to_a
original = H.new(keys.zip(2..1001))
100.times do
to_remove = rand(100).times.collect { keys.sample }
result = original.except(*to_remove)
result.size.should == original.size - to_remove.uniq.size
to_remove.each { |key| result.key?(key).should == false }
(keys.sample(100) - to_remove).each { |key| result.key?(key).should == true }
end
original.should eql(H.new(keys.zip(2..1001))) # shouldn't have changed
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/superset_spec.rb 0000644 0001750 0001750 00000002277 14201005456 024503 0 ustar boutil boutil require 'spec_helper'
require 'immutable/hash'
describe Immutable::Hash do
describe '#>=' do
[
[{}, {}, true],
[{'A' => 1}, {}, true],
[{}, {'A' => 1}, false],
[{'A' => 1}, {'A' => 1}, true],
[{'A' => 1}, {'A' => 2}, false],
[{'A' => 1, 'B' => 2, 'C' => 3}, {'B' => 2}, true],
[{'B' => 2}, {'A' => 1, 'B' => 2, 'C' => 3}, false],
[{'A' => 1, 'B' => 2, 'C' => 3}, {'B' => 0}, false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
expect(H[a] >= H[b]).to eq(expected)
end
end
end
end
describe '#>' do
[
[{}, {}, false],
[{'A' => 1}, {}, true],
[{}, {'A' => 1}, false],
[{'A' => 1}, {'A' => 1}, false],
[{'A' => 1}, {'A' => 2}, false],
[{'A' => 1, 'B' => 2, 'C' => 3}, {'B' => 2}, true],
[{'B' => 2}, {'A' => 1, 'B' => 2, 'C' => 3}, false],
[{'A' => 1, 'B' => 2, 'C' => 3}, {'B' => 0}, false],
].each do |a, b, expected|
describe "for #{a.inspect} and #{b.inspect}" do
it "returns #{expected}" do
expect(H[a] > H[b]).to eq(expected)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/none_spec.rb 0000644 0001750 0001750 00000002367 14201005456 023570 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#none?' do
context 'when empty' do
it 'with a block returns true' do
H.empty.none? {}.should == true
end
it 'with no block returns true' do
H.empty.none?.should == true
end
end
context 'when not empty' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL'] }
context 'with a block' do
[
%w[A aye],
%w[B bee],
%w[C see],
[nil, 'NIL'],
].each do |pair|
it "returns false if the block ever returns true (#{pair.inspect})" do
hash.none? { |key, value| key == pair.first && value == pair.last }.should == false
end
it 'returns true if the block always returns false' do
hash.none? { |key, value| key == 'D' && value == 'dee' }.should == true
end
it 'stops iterating as soon as the block returns true' do
yielded = []
hash.none? { |k,v| yielded << k; true }
yielded.size.should == 1
end
end
end
context 'with no block' do
it 'returns false' do
hash.none?.should == false
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/min_max_spec.rb 0000644 0001750 0001750 00000002210 14201005456 024244 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['a' => 3, 'b' => 2, 'c' => 1] }
describe '#min' do
it 'returns the smallest key/val pair' do
hash.min.should == ['a', 3]
end
end
describe '#max' do
it 'returns the largest key/val pair' do
hash.max.should == ['c', 1]
end
end
describe '#min_by' do
it 'returns the smallest key/val pair (after passing it through a key function)' do
hash.min_by { |k,v| v }.should == ['c', 1]
end
it 'returns the first key/val pair yielded by #each in case of a tie' do
hash.min_by { 0 }.should == hash.each.first
end
it 'returns nil if the hash is empty' do
H.empty.min_by { |k,v| v }.should be_nil
end
end
describe '#max_by' do
it 'returns the largest key/val pair (after passing it through a key function)' do
hash.max_by { |k,v| v }.should == ['a', 3]
end
it 'returns the first key/val pair yielded by #each in case of a tie' do
hash.max_by { 0 }.should == hash.each.first
end
it 'returns nil if the hash is empty' do
H.empty.max_by { |k,v| v }.should be_nil
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/fetch_values_spec.rb 0000644 0001750 0001750 00000001337 14201005456 025275 0 ustar boutil boutil require 'spec_helper'
require 'immutable/hash'
describe Immutable::Hash do
describe '#fetch_values' do
context 'when the all the requested keys exist' do
it 'returns a vector of values for the given keys' do
h = H[:a => 9, :b => 'a', :c => -10, :d => nil]
h.fetch_values.should be_kind_of(Immutable::Vector)
h.fetch_values.should eql(V.empty)
h.fetch_values(:a, :d, :b).should be_kind_of(Immutable::Vector)
h.fetch_values(:a, :d, :b).should eql(V[9, nil, 'a'])
end
end
context 'when the key does not exist' do
it 'raises a KeyError' do
-> { H['A' => 'aye', 'C' => 'Cee'].fetch_values('A', 'B') }.should raise_error(KeyError)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/reduce_spec.rb 0000644 0001750 0001750 00000002003 14201005456 024063 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:reduce, :inject].each do |method|
describe "##{method}" do
context 'when empty' do
it 'returns the memo' do
H.empty.send(method, 'ABC') {}.should == 'ABC'
end
end
context 'when not empty' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'with a block' do
it 'returns the final memo' do
hash.send(method, 0) { |memo, key, value| memo + 1 }.should == 3
end
end
context 'with no block' do
let(:hash) { H[a: 1, b: 2] }
it 'uses a passed string as the name of a method to use instead' do
[[:a, 1, :b, 2], [:b, 2, :a, 1]].include?(hash.send(method, '+')).should == true
end
it 'uses a passed symbol as the name of a method to use instead' do
[[:a, 1, :b, 2], [:b, 2, :a, 1]].include?(hash.send(method, :+)).should == true
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/put_spec.rb 0000644 0001750 0001750 00000006336 14201005456 023441 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#[]=' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
it 'raises error pointing to #put' do
expect { hash[:A] = 'aye' }
.to raise_error(NoMethodError, /Immutable::Hash.*`put'/)
end
end
describe '#put' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'with a block' do
it 'passes the value to the block' do
hash.put('A') { |value| value.should == 'aye' }
end
it 'replaces the value with the result of the block' do
result = hash.put('A') { |value| 'FLIBBLE' }
result.get('A').should == 'FLIBBLE'
end
it 'supports to_proc methods' do
result = hash.put('A', &:upcase)
result.get('A').should == 'AYE'
end
context 'if there is no existing association' do
it 'passes nil to the block' do
hash.put('D') { |value| value.should be_nil }
end
it 'stores the result of the block as the new value' do
result = hash.put('D') { |value| 'FLIBBLE' }
result.get('D').should == 'FLIBBLE'
end
end
end
context 'with a unique key' do
let(:result) { hash.put('D', 'dee') }
it 'preserves the original' do
result
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a copy with the superset of key/value pairs' do
result.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see', 'D' => 'dee'])
end
end
context 'with a duplicate key' do
let(:result) { hash.put('C', 'sea') }
it 'preserves the original' do
result
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a copy with the superset of key/value pairs' do
result.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'sea'])
end
end
context 'with duplicate key and identical value' do
let(:hash) { H['X' => 1, 'Y' => 2] }
let(:result) { hash.put('X', 1) }
it 'returns the original hash unmodified' do
result.should be(hash)
end
context 'with big hash (force nested tries)' do
let(:keys) { (0..99).map(&:to_s) }
let(:values) { (100..199).to_a }
let(:hash) { H[keys.zip(values)] }
it 'returns the original hash unmodified for all changes' do
keys.each_with_index do |key, index|
result = hash.put(key, values[index])
result.should be(hash)
end
end
end
end
context 'with unequal keys which hash to the same value' do
let(:hash) { H[DeterministicHash.new('a', 1) => 'aye'] }
it 'stores and can retrieve both' do
result = hash.put(DeterministicHash.new('b', 1), 'bee')
result.get(DeterministicHash.new('a', 1)).should eql('aye')
result.get(DeterministicHash.new('b', 1)).should eql('bee')
end
end
context 'when a String is inserted as key and then mutated' do
it 'is not affected' do
string = 'a string!'
hash = H.empty.put(string, 'a value!')
string.upcase!
hash['a string!'].should == 'a value!'
hash['A STRING!'].should be_nil
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/map_spec.rb 0000644 0001750 0001750 00000002553 14201005456 023403 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:map, :collect].each do |method|
describe "##{method}" do
context 'when empty' do
it 'returns self' do
H.empty.send(method) {}.should equal(H.empty)
end
end
context 'when not empty' do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
context 'with a block' do
let(:mapped) { hash.send(method) { |key, value| [key.downcase, value.upcase] }}
it 'preserves the original values' do
mapped
hash.should eql(H['A' => 'aye', 'B' => 'bee', 'C' => 'see'])
end
it 'returns a new hash with the mapped values' do
mapped.should eql(H['a' => 'AYE', 'b' => 'BEE', 'c' => 'SEE'])
end
end
context 'with no block' do
it 'returns an Enumerator' do
hash.send(method).class.should be(Enumerator)
hash.send(method).each { |k,v| [k.downcase, v] }.should == hash.map { |k,v| [k.downcase, v] }
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new('a' => 'aye', 'b' => 'bee')
instance.map { |k,v| [k, v.upcase] }.class.should be(subclass)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/reverse_each_spec.rb 0000644 0001750 0001750 00000001261 14201005456 025254 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
describe '#reverse_each' do
context 'with a block' do
it 'returns self' do
hash.reverse_each {}.should be(hash)
end
it 'yields all key/value pairs in the opposite order as #each' do
result = []
hash.reverse_each { |entry| result << entry }
result.should eql(hash.to_a.reverse)
end
end
context 'with no block' do
it 'returns an Enumerator' do
result = hash.reverse_each
result.class.should be(Enumerator)
result.to_a.should eql(hash.to_a.reverse)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/assoc_spec.rb 0000644 0001750 0001750 00000002631 14201005456 023733 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H[a: 3, b: 2, c: 1] }
describe '#assoc' do
it 'searches for a key/val pair with a given key' do
hash.assoc(:a).should == [:a, 3]
hash.assoc(:b).should == [:b, 2]
hash.assoc(:c).should == [:c, 1]
end
it 'returns nil if a matching key is not found' do
hash.assoc(:d).should be_nil
hash.assoc(nil).should be_nil
hash.assoc(0).should be_nil
end
it 'returns nil even if there is a default' do
H.new(a: 1, b: 2) { fail }.assoc(:c).should be_nil
end
it 'uses #== to compare keys with provided object' do
hash.assoc(EqualNotEql.new).should_not be_nil
hash.assoc(EqlNotEqual.new).should be_nil
end
end
describe '#rassoc' do
it 'searches for a key/val pair with a given value' do
hash.rassoc(1).should == [:c, 1]
hash.rassoc(2).should == [:b, 2]
hash.rassoc(3).should == [:a, 3]
end
it 'returns nil if a matching value is not found' do
hash.rassoc(0).should be_nil
hash.rassoc(4).should be_nil
hash.rassoc(nil).should be_nil
end
it 'returns nil even if there is a default' do
H.new(a: 1, b: 2) { fail }.rassoc(3).should be_nil
end
it 'uses #== to compare values with provided object' do
hash.rassoc(EqualNotEql.new).should_not be_nil
hash.rassoc(EqlNotEqual.new).should be_nil
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/hash_spec.rb 0000644 0001750 0001750 00000001633 14201005456 023547 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
describe '#hash' do
it 'values are sufficiently distributed' do
(1..4000).each_slice(4).map { |ka, va, kb, vb| H[ka => va, kb => vb].hash }.uniq.size.should == 1000
end
it 'differs given the same keys and different values' do
H['ka' => 'va'].hash.should_not == H['ka' => 'vb'].hash
end
it 'differs given the same values and different keys' do
H['ka' => 'va'].hash.should_not == H['kb' => 'va'].hash
end
it 'generates the same hash value for a hash regardless of the order things were added to it' do
key1 = DeterministicHash.new('abc', 1)
key2 = DeterministicHash.new('xyz', 1)
H.empty.put(key1, nil).put(key2, nil).hash.should == H.empty.put(key2, nil).put(key1, nil).hash
end
describe 'on an empty hash' do
it 'returns 0' do
H.empty.hash.should == 0
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/has_key_spec.rb 0000644 0001750 0001750 00000001602 14201005456 024243 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
[:key?, :has_key?, :include?, :member?].each do |method|
describe "##{method}" do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see', nil => 'NIL', 2.0 => 'two'] }
['A', 'B', 'C', nil, 2.0].each do |key|
it "returns true for an existing key (#{key.inspect})" do
hash.send(method, key).should == true
end
end
it 'returns false for a non-existing key' do
hash.send(method, 'D').should == false
end
it 'uses #eql? for equality' do
hash.send(method, 2).should == false
end
it 'returns true if the key is found and maps to nil' do
H['A' => nil].send(method, 'A').should == true
end
it 'returns true if the key is found and maps to false' do
H['A' => false].send(method, 'A').should == true
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/copying_spec.rb 0000644 0001750 0001750 00000000424 14201005456 024271 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['A' => 'aye', 'B' => 'bee', 'C' => 'see'] }
[:dup, :clone].each do |method|
describe "##{method}" do
it 'returns self' do
hash.send(method).should equal(hash)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/hash/partition_spec.rb 0000644 0001750 0001750 00000002126 14201005456 024633 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Hash do
let(:hash) { H['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4] }
let(:partition) { hash.partition { |k,v| v % 2 == 0 }}
describe '#partition' do
it 'returns a pair of Immutable::Hashes' do
partition.each { |h| h.class.should be(Immutable::Hash) }
partition.should be_frozen
end
it 'returns key/val pairs for which predicate is true in first Hash' do
partition[0].should == {'b' => 2, 'd' => 4}
end
it 'returns key/val pairs for which predicate is false in second Hash' do
partition[1].should == {'a' => 1, 'c' => 3}
end
it "doesn't modify the original Hash" do
partition
hash.should eql(H['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4])
end
context 'from a subclass' do
it 'should return instances of the subclass' do
subclass = Class.new(Immutable::Hash)
instance = subclass.new('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4)
partition = instance.partition { |k,v| v % 2 == 0 }
partition.each { |h| h.class.should be(subclass) }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/ 0000755 0001750 0001750 00000000000 14201005456 021641 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/vector/new_spec.rb 0000644 0001750 0001750 00000002507 14201005456 023775 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '.new' do
it 'accepts a single enumerable argument and creates a new vector' do
vector = Immutable::Vector.new([1,2,3])
vector.size.should be(3)
vector[0].should be(1)
vector[1].should be(2)
vector[2].should be(3)
end
it 'makes a defensive copy of a non-frozen mutable Array passed in' do
array = [1,2,3]
vector = Immutable::Vector.new(array)
array[0] = 'changed'
vector[0].should be(1)
end
it 'is amenable to overriding of #initialize' do
class SnazzyVector < Immutable::Vector
def initialize
super(['SNAZZY!!!'])
end
end
vector = SnazzyVector.new
vector.size.should be(1)
vector.should == ['SNAZZY!!!']
end
context 'from a subclass' do
it 'returns a frozen instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new(['some', 'values'])
instance.class.should be subclass
instance.frozen?.should be true
end
end
end
describe '.[]' do
it 'accepts a variable number of items and creates a new vector' do
vector = Immutable::Vector['a', 'b']
vector.size.should be(2)
vector[0].should == 'a'
vector[1].should == 'b'
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/to_ary_spec.rb 0000644 0001750 0001750 00000001317 14201005456 024477 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#to_ary' do
let(:values) { %w[A B C D] }
it 'converts using block parameters' do
def expectations(&block)
yield(vector)
end
expectations do |a, b, *c|
expect(a).to eq('A')
expect(b).to eq('B')
expect(c).to eq(%w[C D])
end
end
it 'converts using method arguments' do
def expectations(a, b, *c)
expect(a).to eq('A')
expect(b).to eq('B')
expect(c).to eq(%w[C D])
end
expectations(*vector)
end
it 'converts using splat' do
array = *vector
expect(array).to eq(%w[A B C D])
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/delete_at_spec.rb 0000644 0001750 0001750 00000003172 14201005456 025131 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#delete_at' do
let(:vector) { V[1,2,3,4,5] }
it 'removes the element at the specified index' do
vector.delete_at(0).should eql(V[2,3,4,5])
vector.delete_at(2).should eql(V[1,2,4,5])
vector.delete_at(-1).should eql(V[1,2,3,4])
end
it 'makes no modification if the index is out of range' do
vector.delete_at(5).should eql(vector)
vector.delete_at(-6).should eql(vector)
end
it 'works when deleting last item at boundary where vector trie needs to get shallower' do
vector = Immutable::Vector.new(1..33)
vector.delete_at(32).size.should == 32
vector.delete_at(32).to_a.should eql((1..32).to_a)
end
it 'works on an empty vector' do
V.empty.delete_at(0).should be(V.empty)
V.empty.delete_at(1).should be(V.empty)
end
it 'works on a vector with 1 item' do
V[10].delete_at(0).should eql(V.empty)
V[10].delete_at(1).should eql(V[10])
end
it 'works on a vector with 32 items' do
V.new(1..32).delete_at(0).should eql(V.new(2..32))
V.new(1..32).delete_at(31).should eql(V.new(1..31))
end
it 'has the right size and contents after many deletions' do
array = (1..2000).to_a # we use an Array as standard of correctness
vector = Immutable::Vector.new(array)
500.times do
index = rand(vector.size)
vector = vector.delete_at(index)
array.delete_at(index)
vector.size.should == array.size
ary = vector.to_a
ary.size.should == vector.size
ary.should eql(array)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/drop_spec.rb 0000644 0001750 0001750 00000002104 14201005456 024141 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#drop' do
[
[[], 10, []],
[['A'], 10, []],
[['A'], 1, []],
[['A'], 0, ['A']],
[%w[A B C], 0, %w[A B C]],
[%w[A B C], 2, ['C']],
[(1..32), 3, (4..32)],
[(1..33), 32, [33]]
].each do |values, number, expected|
describe "#{number} from #{values.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.drop(number)
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.drop(number).should eql(V[*expected])
end
end
end
it 'raises an ArgumentError if number of elements specified is negative' do
-> { V[1, 2, 3].drop(-1) }.should raise_error(ArgumentError)
-> { V[1, 2, 3].drop(-3) }.should raise_error(ArgumentError)
end
context 'when number of elements specified is zero' do
let(:vector) { V[1, 2, 3, 4, 5, 6] }
it 'returns self' do
vector.drop(0).should be(vector)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/pop_spec.rb 0000644 0001750 0001750 00000001033 14201005456 023773 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#pop' do
[
[[], []],
[['A'], []],
[%w[A B C], %w[A B]],
[1..32, 1..31],
[1..33, 1..32]
].each do |values, expected|
context "on #{values.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.pop
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.pop.should eql(V[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/reject_spec.rb 0000644 0001750 0001750 00000002455 14201005456 024462 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:reject, :delete_if].each do |method|
describe "##{method}" do
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[%w[A b C], %w[A C]],
[%w[a b c], []],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
vector.send(method) { |item| item == item.downcase }.should eql(V[*expected])
end
end
context 'without a block' do
it 'returns an Enumerator' do
vector.send(method).class.should be(Enumerator)
vector.send(method).each { |item| item == item.downcase }.should eql(V[*expected])
end
end
end
end
it 'works with a variety of inputs' do
[1, 2, 10, 31, 32, 33, 1023, 1024, 1025].each do |size|
[0, 5, 32, 50, 500, 800, 1024].each do |threshold|
vector = V.new(1..size)
result = vector.send(method) { |item| item > threshold }
result.size.should == [size, threshold].min
result.should eql(V.new(1..[size, threshold].min))
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/flatten_spec.rb 0000644 0001750 0001750 00000003306 14201005456 024637 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#flatten' do
it 'recursively flattens nested vectors into containing vector' do
V[V[1], V[2]].flatten.should eql(V[1,2])
V[V[V[V[V[V[1,2,3]]]]]].flatten.should eql(V[1,2,3])
V[V[V[1]], V[V[V[2]]]].flatten.should eql(V[1,2])
end
it 'flattens nested arrays as well' do
V[[1,2,3],[[4],[5,6]]].flatten.should eql(V[1,2,3,4,5,6])
end
context 'with an integral argument' do
it 'only flattens down to the specified depth' do
V[V[V[1,2]]].flatten(1).should eql(V[V[1,2]])
V[V[V[V[1]], V[2], V[3]]].flatten(2).should eql(V[V[1], 2, 3])
end
end
context 'with an argument of zero' do
it 'returns self' do
vector = V[1,2,3]
vector.flatten(0).should be(vector)
end
end
context 'on a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2])
instance.flatten.class.should be(subclass)
end
end
context 'on a vector with no nested vectors' do
it 'returns an unchanged vector' do
vector = V[1,2,3]
vector.flatten.should.eql?(V[1,2,3])
end
context 'on a Vector larger than 32 items initialized with Vector.new' do
# Regression test, for problem discovered while working on GH issue #182
it 'returns an unchanged vector' do
vector1,vector2 = 2.times.collect { V.new(0..33) }
vector1.flatten.should eql(vector2)
end
end
end
it 'leaves the original unmodified' do
vector = V[1,2,3]
vector.flatten
vector.should eql(V[1,2,3])
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/dig_spec.rb 0000644 0001750 0001750 00000001543 14201005456 023746 0 ustar boutil boutil require 'spec_helper'
require 'immutable/vector'
describe Immutable::Vector do
let(:v) { V[1, 2, V[3, 4]] }
describe '#dig' do
it 'returns value at the index with one argument' do
expect(v.dig(0)).to eq(1)
end
it 'returns value at index in nested arrays' do
expect(v.dig(2, 0)).to eq(3)
end
# This is different from Hash#dig, but it matches the behavior of Ruby's
# built-in Array#dig (except that Array#dig raises a TypeError)
it 'raises an error when indexing deeper than possible' do
expect { (v.dig(0, 0)) }.to raise_error(NoMethodError)
end
it 'returns nil if you index past the end of an array' do
expect(v.dig(5)).to eq(nil)
end
it "raises an error when indexing with a key vectors don't understand" do
expect { v.dig(:foo) }.to raise_error(ArgumentError)
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/reverse_spec.rb 0000644 0001750 0001750 00000001016 14201005456 024651 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#reverse' do
[
[[], []],
[[1], [1]],
[[1,2], [2,1]],
[(1..32).to_a, (1..32).to_a.reverse],
[(1..33).to_a, (1..33).to_a.reverse],
[(1..100).to_a, (1..100).to_a.reverse],
[(1..1024).to_a, (1..1024).to_a.reverse]
].each do |initial, expected|
describe "on #{initial}" do
it "returns #{expected}" do
V.new(initial).reverse.should eql(V.new(expected))
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/take_while_spec.rb 0000644 0001750 0001750 00000001544 14201005456 025320 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#take_while' do
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B]]
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
let(:result) { vector.take_while { |item| item < 'C' }}
describe 'with a block' do
it "returns #{expected.inspect}" do
result.should eql(V[*expected])
end
it 'preserves the original' do
result
vector.should eql(V[*values])
end
end
describe 'without a block' do
it 'returns an Enumerator' do
vector.take_while.class.should be(Enumerator)
vector.take_while.each { |item| item < 'C' }.should eql(V[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/multiply_spec.rb 0000644 0001750 0001750 00000002436 14201005456 025064 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#*' do
let(:vector) { V[1, 2, 3] }
context 'with a String argument' do
it 'acts just like #join' do
(vector * 'boo').should eql(vector.join('boo'))
end
end
context 'with an Integer argument' do
it 'concatenates n copies of the array' do
(vector * 0).should eql(V.empty)
(vector * 1).should eql(vector)
(vector * 2).should eql(V[1,2,3,1,2,3])
(vector * 3).should eql(V[1,2,3,1,2,3,1,2,3])
end
it 'raises an ArgumentError if integer is negative' do
-> { vector * -1 }.should raise_error(ArgumentError)
end
it 'works on large vectors' do
array = (1..50).to_a
(V.new(array) * 25).should eql(V.new(array * 25))
end
end
context 'with a subclass of Vector' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
(instance * 10).class.should be(subclass)
end
end
it 'raises a TypeError if passed nil' do
-> { vector * nil }.should raise_error(TypeError)
end
it 'raises an ArgumentError if passed no arguments' do
-> { vector.* }.should raise_error(ArgumentError)
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/transpose_spec.rb 0000644 0001750 0001750 00000004115 14201005456 025217 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#transpose' do
it 'takes a vector of vectors and transposes rows and columns' do
V[V[1, 'a'], V[2, 'b'], V[3, 'c']].transpose.should eql(V[V[1, 2, 3], V['a', 'b', 'c']])
V[V[1, 2, 3], V['a', 'b', 'c']].transpose.should eql(V[V[1, 'a'], V[2, 'b'], V[3, 'c']])
V[].transpose.should eql(V[])
V[V[]].transpose.should eql(V[])
V[V[], V[]].transpose.should eql(V[])
V[V[0]].transpose.should eql(V[V[0]])
V[V[0], V[1]].transpose.should eql(V[V[0, 1]])
end
it 'raises an IndexError if the vectors are not of the same length' do
-> { V[V[1,2], V[:a]].transpose }.should raise_error(IndexError)
end
it 'also works on Vectors of Arrays' do
V[[1,2,3], [4,5,6]].transpose.should eql(V[V[1,4], V[2,5], V[3,6]])
end
[10, 31, 32, 33, 1000, 1023, 1024, 1025, 2000].each do |size|
context "on #{size}-item vectors" do
it 'behaves like Array#transpose' do
array = rand(10).times.map { size.times.map { rand(10000) }}
vector = V.new(array)
result = vector.transpose
# Array#== uses Object#== to compare corresponding elements,
# so although Vector#== does type coercion, it does not consider
# nested Arrays and corresponding nested Vectors to be equal
# That is why the following ".map { |a| V.new(a) }" is needed
result.should == array.transpose.map { |a| V.new(a) }
result.each { |v| v.class.should be(Immutable::Vector) }
end
end
end
context 'on a subclass of Vector' do
it 'returns instances of the subclass' do
subclass = Class.new(V)
instance = subclass.new([[1,2,3], [4,5,6]])
instance.transpose.class.should be(subclass)
instance.transpose.each { |v| v.class.should be(subclass) }
end
end
context 'if an item does not respond to #size and #[]' do
it 'raises TypeError' do
expect {
V[[1, 2], [2, 3], nil].transpose
}.to raise_error(TypeError)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/sample_spec.rb 0000644 0001750 0001750 00000000540 14201005456 024460 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#sample' do
let(:vector) { V.new(1..10) }
it 'returns a randomly chosen item' do
chosen = 100.times.map { vector.sample }
chosen.each { |item| vector.include?(item).should == true }
vector.each { |item| chosen.include?(item).should == true }
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/any_spec.rb 0000644 0001750 0001750 00000002717 14201005456 023776 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#any?' do
let(:any?) { vector.any?(&block) }
context 'when created with no values' do
let(:values) { [] }
context 'with a block' do
let(:block) { ->(item) { item + 1 } }
it 'returns false' do
expect(any?).to be(false)
end
end
context 'with a block' do
let(:block) { nil }
it 'returns false' do
expect(any?).to be(false)
end
end
end
context 'when created with values' do
let(:values) { ['A', 'B', 3, nil] }
context 'with a block that returns true' do
let(:block) { ->(item) { item == 3 } }
it 'returns true' do
expect(any?).to be(true)
end
end
context "with a block that doesn't return true" do
let(:block) { ->(item) { item == 'D' } }
it 'returns false' do
expect(any?).to be(false)
end
end
context 'without a block' do
let(:block) { nil }
context 'with some values that are truthy' do
let(:values) { [nil, false, 'B'] }
it 'returns true' do
expect(any?).to be(true)
end
end
context 'with all values that are falsey' do
let(:values) { [nil, false] }
it 'returns false' do
expect(any?).to be(false)
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/shuffle_spec.rb 0000644 0001750 0001750 00000002251 14201005456 024634 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#shuffle' do
let(:vector) { V[1,2,3,4] }
it 'returns the same values, in a usually different order' do
different = false
10.times do
shuffled = vector.shuffle
shuffled.sort.should eql(vector)
different ||= (shuffled != vector)
end
different.should be(true)
end
it 'leaves the original unchanged' do
vector.shuffle
vector.should eql(V[1,2,3,4])
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.shuffle.class.should be(subclass)
end
end
[32, 33, 1023, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
it 'works correctly' do
vector = V.new(1..size)
shuffled = vector.shuffle
shuffled = vector.shuffle while shuffled.eql?(vector) # in case we get the same
vector.should eql(V.new(1..size))
shuffled.size.should == vector.size
shuffled.sort.should eql(vector)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/ltlt_spec.rb 0000644 0001750 0001750 00000003244 14201005456 024162 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#<<' do
let(:ltlt) { vector << added_value }
shared_examples 'checking adding values' do
let(:added_vector) { V[*added_values] }
it 'preserves the original' do
original = vector
vector << added_value
expect(original).to eq(vector)
end
it 'ltlts the item to the vector' do
expect(ltlt).to eq(added_vector)
end
end
context 'with a empty array adding a single item' do
let(:values) { [] }
let(:added_value) { 'A' }
let(:added_values) { ['A'] }
include_examples 'checking adding values'
end
context 'with a single-item array adding a different item' do
let(:values) { ['A'] }
let(:added_value) { 'B' }
let(:added_values) { %w[A B] }
include_examples 'checking adding values'
end
context 'with a single-item array adding a duplicate item' do
let(:values) { ['A'] }
let(:added_value) { 'A' }
let(:added_values) { %w[A A] }
include_examples 'checking adding values'
end
[31, 32, 33, 1023, 1024, 1025].each do |size|
context "with a #{size}-item vector adding a different item" do
let(:values) { (1..size).to_a }
let(:added_value) { size+1 }
let(:added_values) { (1..(size+1)).to_a }
include_examples 'checking adding values'
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass[1,2,3]
(instance << 4).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/get_spec.rb 0000644 0001750 0001750 00000004344 14201005456 023764 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:get, :at].each do |method|
describe "##{method}" do
context 'when empty' do
it 'always returns nil' do
(-1..1).each do |i|
V.empty.send(method, i).should be_nil
end
end
end
context 'when not empty' do
let(:vector) { V[*(1..1025)] }
context 'with a positive index' do
context 'within the absolute bounds of the vector' do
it 'returns the value at the specified index from the head' do
(0..(vector.size - 1)).each do |i|
vector.send(method, i).should == i + 1
end
end
end
context 'outside the absolute bounds of the vector' do
it 'returns nil' do
vector.send(method, vector.size).should be_nil
end
end
end
context 'with a negative index' do
context 'within the absolute bounds of the vector' do
it 'returns the value at the specified index from the tail' do
(-vector.size..-1).each do |i|
vector.send(method, i).should == vector.size + i + 1
end
end
end
context 'outside the absolute bounds of the vector' do
it 'returns nil' do
vector.send(method, -vector.size.next).should be_nil
end
end
end
end
[1, 10, 31, 32, 33, 1024, 1025, 2000].each do |size|
context "on a #{size}-item vector" do
it 'works correctly, even after various addings and removings' do
array = size.times.map { rand(10000) }
vector = V.new(array)
100.times do
if rand(2) == 0
value, index = rand(10000), rand(size)
array[index] = value
vector = vector.set(index, value)
else
index = rand(array.size)
array.delete_at(index)
vector = vector.delete_at(index)
end
end
0.upto(array.size) do |i|
array[i].should == vector.send(method, i)
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/minimum_spec.rb 0000644 0001750 0001750 00000001431 14201005456 024652 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#min' do
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ni'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].min { |minimum, item| minimum.length <=> item.length }.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].min.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/inspect_spec.rb 0000644 0001750 0001750 00000002272 14201005456 024650 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#inspect' do
let(:inspect) { vector.inspect }
shared_examples 'checking output' do
it 'returns its contents as a programmer-readable string' do
expect(inspect).to eq(output)
end
it "returns a string which can be eval'd to get back an equivalent vector" do
expect(eval(inspect)).to eql(vector)
end
end
context 'with an empty array' do
let(:output) { 'Immutable::Vector[]' }
let(:values) { [] }
include_examples 'checking output'
end
context 'with a single item array' do
let(:output) { 'Immutable::Vector["A"]' }
let(:values) { %w[A] }
include_examples 'checking output'
end
context 'with a multi-item array' do
let(:output) { 'Immutable::Vector["A", "B"]' }
let(:values) { %w[A B] }
include_examples 'checking output'
end
context 'from a subclass' do
MyVector = Class.new(Immutable::Vector)
let(:vector) { MyVector.new(values) }
let(:output) { 'MyVector[1, 2]' }
let(:values) { [1, 2] }
include_examples 'checking output'
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/product_spec.rb 0000644 0001750 0001750 00000004477 14201005456 024674 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#product' do
context 'when passed no arguments' do
it 'multiplies all items in vector' do
[
[[], 1],
[[2], 2],
[[1, 3, 5, 7, 11], 1155],
].each do |values, expected|
V[*values].product.should == expected
end
end
end
context 'when passed one or more vectors' do
let(:vector) { V[1,2,3] }
context 'when passed a block' do
it 'yields an array for each combination of items from the vectors' do
yielded = []
vector.product(vector) { |obj| yielded << obj }
yielded.should eql([[1,1], [1,2], [1,3], [2,1], [2,2], [2,3], [3,1], [3,2], [3,3]])
yielded = []
vector.product(V[3,4,5], V[6,8]) { |obj| yielded << obj }
yielded.should eql(
[[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8],
[3, 3, 6], [3, 3, 8], [3, 4, 6], [3, 4, 8], [3, 5, 6], [3, 5, 8]])
end
it 'returns self' do
vector.product(V.empty) {}.should be(vector)
vector.product(V[1,2], V[3]) {}.should be(vector)
V.empty.product(vector) {}.should be(V.empty)
end
end
context 'when not passed a block' do
it 'returns the cartesian product in an array' do
V[1,2].product(V[3,4,5], V[6,8]).should eql(
[[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]])
end
end
context 'when one of the arguments is empty' do
it 'returns an empty array' do
vector.product(V.empty, V[4,5,6]).should eql([])
end
end
context 'when the receiver is empty' do
it 'returns an empty array' do
V.empty.product(vector, V[4,5,6]).should eql([])
end
end
end
context 'when passed one or more Arrays' do
it 'also calculates the cartesian product correctly' do
V[1,2].product([3,4,5], [6,8]).should eql(
[[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/marshal_spec.rb 0000644 0001750 0001750 00000001625 14201005456 024633 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#marshal_dump/#marshal_load' do
let(:ruby) do
File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
end
let(:child_cmd) do
%Q|#{ruby} -I lib -r immutable -e 'vector = Immutable::Vector[5, 10, 15]; $stdout.write(Marshal.dump(vector))'|
end
let(:reloaded_vector) do
IO.popen(child_cmd, 'r+') do |child|
reloaded_vector = Marshal.load(child)
child.close
reloaded_vector
end
end
it 'can survive dumping and loading into a new process' do
expect(reloaded_vector).to eql(V[5, 10, 15])
end
it 'is still possible to find items by index after loading' do
expect(reloaded_vector[0]).to eq(5)
expect(reloaded_vector[1]).to eq(10)
expect(reloaded_vector[2]).to eq(15)
expect(reloaded_vector.size).to eq(3)
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/flat_map_spec.rb 0000644 0001750 0001750 00000002475 14201005456 024773 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#flat_map' do
let(:block) { ->(item) { [item, item + 1, item * item] } }
let(:flat_map) { vector.flat_map(&block) }
let(:flattened_vector) { V[*flattened_values] }
shared_examples 'checking flattened result' do
it 'returns the flattened values as an Immutable::Vector' do
expect(flat_map).to eq(flattened_vector)
end
it 'returns an Immutable::Vector' do
expect(flat_map).to be_a(Immutable::Vector)
end
end
context 'with an empty vector' do
let(:values) { [] }
let(:flattened_values) { [] }
include_examples 'checking flattened result'
end
context 'with a block that returns an empty vector' do
let(:block) { ->(item) { [] } }
let(:values) { [1, 2, 3] }
let(:flattened_values) { [] }
include_examples 'checking flattened result'
end
context 'with a vector of one item' do
let(:values) { [7] }
let(:flattened_values) { [7, 8, 49] }
include_examples 'checking flattened result'
end
context 'with a vector of multiple items' do
let(:values) { [1, 2, 3] }
let(:flattened_values) { [1, 2, 1, 2, 3, 4, 3, 4, 9] }
include_examples 'checking flattened result'
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/empty_spec.rb 0000644 0001750 0001750 00000002040 14201005456 024332 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#empty?' do
[
[[], true],
[['A'], false],
[%w[A B C], false],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].empty?.should == expected
end
end
end
end
describe '.empty' do
it 'returns the canonical empty vector' do
V.empty.size.should be(0)
V.empty.object_id.should be(V.empty.object_id)
end
context 'from a subclass' do
it 'returns an empty instance of the subclass' do
subclass = Class.new(Immutable::Vector)
subclass.empty.class.should be(subclass)
subclass.empty.should be_empty
end
it 'calls overridden #initialize when creating empty Hash' do
subclass = Class.new(Immutable::Vector) do
def initialize
@variable = 'value'
end
end
subclass.empty.instance_variable_get(:@variable).should == 'value'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/to_a_spec.rb 0000644 0001750 0001750 00000001551 14201005456 024124 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#to_a' do
let(:to_a) { vector.to_a }
shared_examples 'checking to_a values' do
it 'returns the values' do
expect(to_a).to eq(values)
end
end
context 'with an empty vector' do
let(:values) { [] }
include_examples 'checking to_a values'
end
context 'with an single item vector' do
let(:values) { %w[A] }
include_examples 'checking to_a values'
end
context 'with an multi-item vector' do
let(:values) { %w[A B] }
include_examples 'checking to_a values'
end
[10, 31, 32, 33, 1000, 1023, 1024, 1025].each do |size|
context "with a #{size}-item vector" do
let(:values) { (1..size).to_a }
include_examples 'checking to_a values'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/fetch_spec.rb 0000644 0001750 0001750 00000004011 14201005456 024265 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#fetch' do
let(:vector) { V['a', 'b', 'c'] }
context 'with no default provided' do
context 'when the index exists' do
it 'returns the value at the index' do
vector.fetch(0).should == 'a'
vector.fetch(1).should == 'b'
vector.fetch(2).should == 'c'
end
end
context 'when the key does not exist' do
it 'raises an IndexError' do
-> { vector.fetch(3) }.should raise_error(IndexError)
-> { vector.fetch(-4) }.should raise_error(IndexError)
end
end
end
context 'with a default value' do
context 'when the index exists' do
it 'returns the value at the index' do
vector.fetch(0, 'default').should == 'a'
vector.fetch(1, 'default').should == 'b'
vector.fetch(2, 'default').should == 'c'
end
end
context 'when the index does not exist' do
it 'returns the default value' do
vector.fetch(3, 'default').should == 'default'
vector.fetch(-4, 'default').should == 'default'
end
end
end
context 'with a default block' do
context 'when the index exists' do
it 'returns the value at the index' do
vector.fetch(0) { 'default'.upcase }.should == 'a'
vector.fetch(1) { 'default'.upcase }.should == 'b'
vector.fetch(2) { 'default'.upcase }.should == 'c'
end
end
context 'when the index does not exist' do
it 'invokes the block with the missing index as parameter' do
vector.fetch(3) { |index| index.should == 3}
vector.fetch(-4) { |index| index.should == -4 }
vector.fetch(3) { 'default'.upcase }.should == 'DEFAULT'
vector.fetch(-4) { 'default'.upcase }.should == 'DEFAULT'
end
end
end
it 'gives precedence to default block over default argument if passed both' do
vector.fetch(3, 'one') { 'two' }.should == 'two'
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/update_in_spec.rb 0000644 0001750 0001750 00000004715 14201005456 025157 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#update_in' do
let(:vector) {
Immutable::Vector[
100,
101,
102,
Immutable::Vector[200, 201, Immutable::Vector[300, 301, 302]],
Immutable::Hash['A' => 'alpha', 'B' => 'bravo'],
[400, 401, 402]
]
}
context 'with one level on existing key' do
it 'passes the value to the block' do
vector.update_in(1) { |value| value.should == 101 }
end
it 'replaces the value with the result of the block' do
result = vector.update_in(1) { |value| 'FLIBBLE' }
result.get(1).should == 'FLIBBLE'
end
it 'should preserve the original' do
result = vector.update_in(1) { |value| 'FLIBBLE' }
vector.get(1).should == 101
end
end
context 'with multi-level vectors on existing keys' do
it 'passes the value to the block' do
vector.update_in(3, 2, 0) { |value| value.should == 300 }
end
it 'replaces the value with the result of the block' do
result = vector.update_in(3, 2, 0) { |value| 'FLIBBLE' }
result[3][2][0].should == 'FLIBBLE'
end
it 'should preserve the original' do
result = vector.update_in(3, 2, 0) { |value| 'FLIBBLE' }
vector[3][2][0].should == 300
end
end
context "with multi-level creating sub-hashes when keys don't exist" do
it 'passes nil to the block' do
vector.update_in(3, 3, 'X', 'Y') { |value| value.should be_nil }
end
it 'creates subhashes on the way to set the value' do
result = vector.update_in(3, 3, 'X', 'Y') { |value| 'NEWVALUE' }
result[3][3]['X']['Y'].should == 'NEWVALUE'
result[3][2][0].should == 300
end
end
context 'with multi-level including hash with existing keys' do
it 'passes the value to the block' do
vector.update_in(4, 'B') { |value| value.should == 'bravo' }
end
it 'replaces the value with the result of the block' do
result = vector.update_in(4, 'B') { |value| 'FLIBBLE' }
result[4]['B'].should == 'FLIBBLE'
end
it 'should preserve the original' do
result = vector.update_in(4, 'B') { |value| 'FLIBBLE' }
vector[4]['B'].should == 'bravo'
end
end
context 'with empty key_path' do
it 'raises ArguemntError' do
expect { vector.update_in() { |v| 42 } }.to raise_error(ArgumentError)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/each_index_spec.rb 0000644 0001750 0001750 00000001734 14201005456 025274 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#each_index' do
let(:vector) { V[1,2,3,4] }
context 'with a block' do
it 'yields all the valid indices into the vector' do
result = []
vector.each_index { |i| result << i }
result.should eql([0,1,2,3])
end
it 'returns self' do
vector.each_index {}.should be(vector)
end
end
context 'without a block' do
it 'returns an Enumerator' do
vector.each_index.class.should be(Enumerator)
vector.each_index.to_a.should eql([0,1,2,3])
end
end
context 'on an empty vector' do
it "doesn't yield anything" do
V.empty.each_index { fail }
end
end
[1, 2, 10, 31, 32, 33, 1000, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
it 'yields all valid indices' do
V.new(1..size).each_index.to_a.should == (0..(size-1)).to_a
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/each_spec.rb 0000644 0001750 0001750 00000002100 14201005456 024071 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#each' do
describe 'with no block' do
let(:vector) { V['A', 'B', 'C'] }
it 'returns an Enumerator' do
vector.each.class.should be(Enumerator)
vector.each.to_a.should == vector
end
end
[31, 32, 33, 1023, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
describe 'with a block' do
let(:vector) { V.new(1..size) }
it 'returns self' do
items = []
vector.each { |item| items << item }.should be(vector)
end
it 'yields all the items' do
items = []
vector.each { |item| items << item }
items.should == (1..size).to_a
end
it 'iterates over the items in order' do
vector.each.first.should == 1
vector.each.to_a.last.should == size
end
end
end
end
context 'on an empty vector' do
it "doesn't yield anything" do
V.empty.each { fail }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/last_spec.rb 0000644 0001750 0001750 00000001705 14201005456 024146 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#last' do
let(:last) { vector.last }
shared_examples 'checking values' do
it 'returns the last item' do
expect(last).to eq(last_item)
end
end
context 'with an empty vector' do
let(:last_item) { nil }
let(:values) { [] }
include_examples 'checking values'
end
context 'with a single item vector' do
let(:last_item) { 'A' }
let(:values) { %w[A] }
include_examples 'checking values'
end
context 'with a multi-item vector' do
let(:last_item) { 'B' }
let(:values) { %w[A B] }
include_examples 'checking values'
end
[31, 32, 33, 1023, 1024, 1025].each do |size|
context "with a #{size}-item vector" do
let(:last_item) { size }
let(:values) { (1..size).to_a }
include_examples 'checking values'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/delete_spec.rb 0000644 0001750 0001750 00000001665 14201005456 024452 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#delete' do
it 'removes elements that are #== to the argument' do
V[1,2,3].delete(1).should eql(V[2,3])
V[1,2,3].delete(2).should eql(V[1,3])
V[1,2,3].delete(3).should eql(V[1,2])
V[1,2,3].delete(0).should eql(V[1,2,3])
V['a','b','a','c','a','a','d'].delete('a').should eql(V['b','c','d'])
V[EqualNotEql.new, EqualNotEql.new].delete(:something).should eql(V.empty)
V[EqlNotEqual.new, EqlNotEqual.new].delete(:something).should_not be_empty
end
context 'on an empty vector' do
it 'returns self' do
V.empty.delete(1).should be(V.empty)
end
end
context 'on a subclass of Vector' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.delete(1).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/slice_spec.rb 0000644 0001750 0001750 00000025724 14201005456 024311 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[1,2,3,4] }
let(:big) { V.new(1..10000) }
[:slice, :[]].each do |method|
describe "##{method}" do
context 'when passed a positive integral index' do
it 'returns the element at that index' do
vector.send(method, 0).should be(1)
vector.send(method, 1).should be(2)
vector.send(method, 2).should be(3)
vector.send(method, 3).should be(4)
vector.send(method, 4).should be(nil)
vector.send(method, 10).should be(nil)
big.send(method, 0).should be(1)
big.send(method, 9999).should be(10000)
end
it 'leaves the original unchanged' do
vector.should eql(V[1,2,3,4])
end
end
context 'when passed a negative integral index' do
it 'returns the element which is number (index.abs) counting from the end of the vector' do
vector.send(method, -1).should be(4)
vector.send(method, -2).should be(3)
vector.send(method, -3).should be(2)
vector.send(method, -4).should be(1)
vector.send(method, -5).should be(nil)
vector.send(method, -10).should be(nil)
big.send(method, -1).should be(10000)
big.send(method, -10000).should be(1)
end
end
context 'when passed a positive integral index and count' do
it "returns 'count' elements starting from 'index'" do
vector.send(method, 0, 0).should eql(V.empty)
vector.send(method, 0, 1).should eql(V[1])
vector.send(method, 0, 2).should eql(V[1,2])
vector.send(method, 0, 4).should eql(V[1,2,3,4])
vector.send(method, 0, 6).should eql(V[1,2,3,4])
vector.send(method, 0, -1).should be_nil
vector.send(method, 0, -2).should be_nil
vector.send(method, 0, -4).should be_nil
vector.send(method, 2, 0).should eql(V.empty)
vector.send(method, 2, 1).should eql(V[3])
vector.send(method, 2, 2).should eql(V[3,4])
vector.send(method, 2, 4).should eql(V[3,4])
vector.send(method, 2, -1).should be_nil
vector.send(method, 4, 0).should eql(V.empty)
vector.send(method, 4, 2).should eql(V.empty)
vector.send(method, 4, -1).should be_nil
vector.send(method, 5, 0).should be_nil
vector.send(method, 5, 2).should be_nil
vector.send(method, 5, -1).should be_nil
vector.send(method, 6, 0).should be_nil
vector.send(method, 6, 2).should be_nil
vector.send(method, 6, -1).should be_nil
big.send(method, 0, 3).should eql(V[1,2,3])
big.send(method, 1023, 4).should eql(V[1024,1025,1026,1027])
big.send(method, 1024, 4).should eql(V[1025,1026,1027,1028])
end
it 'leaves the original unchanged' do
vector.should eql(V[1,2,3,4])
end
end
context 'when passed a negative integral index and count' do
it "returns 'count' elements, starting from index which is number 'index.abs' counting from the end of the array" do
vector.send(method, -1, 0).should eql(V.empty)
vector.send(method, -1, 1).should eql(V[4])
vector.send(method, -1, 2).should eql(V[4])
vector.send(method, -1, -1).should be_nil
vector.send(method, -2, 0).should eql(V.empty)
vector.send(method, -2, 1).should eql(V[3])
vector.send(method, -2, 2).should eql(V[3,4])
vector.send(method, -2, 4).should eql(V[3,4])
vector.send(method, -2, -1).should be_nil
vector.send(method, -4, 0).should eql(V.empty)
vector.send(method, -4, 1).should eql(V[1])
vector.send(method, -4, 2).should eql(V[1,2])
vector.send(method, -4, 4).should eql(V[1,2,3,4])
vector.send(method, -4, 6).should eql(V[1,2,3,4])
vector.send(method, -4, -1).should be_nil
vector.send(method, -5, 0).should be_nil
vector.send(method, -5, 1).should be_nil
vector.send(method, -5, 10).should be_nil
vector.send(method, -5, -1).should be_nil
big.send(method, -1, 1).should eql(V[10000])
big.send(method, -1, 2).should eql(V[10000])
big.send(method, -6, 2).should eql(V[9995,9996])
end
end
context 'when passed a Range' do
it 'returns the elements whose indexes are within the given Range' do
vector.send(method, 0..-1).should eql(V[1,2,3,4])
vector.send(method, 0..-10).should eql(V.empty)
vector.send(method, 0..0).should eql(V[1])
vector.send(method, 0..1).should eql(V[1,2])
vector.send(method, 0..2).should eql(V[1,2,3])
vector.send(method, 0..3).should eql(V[1,2,3,4])
vector.send(method, 0..4).should eql(V[1,2,3,4])
vector.send(method, 0..10).should eql(V[1,2,3,4])
vector.send(method, 2..-10).should eql(V.empty)
vector.send(method, 2..0).should eql(V.empty)
vector.send(method, 2..2).should eql(V[3])
vector.send(method, 2..3).should eql(V[3,4])
vector.send(method, 2..4).should eql(V[3,4])
vector.send(method, 3..0).should eql(V.empty)
vector.send(method, 3..3).should eql(V[4])
vector.send(method, 3..4).should eql(V[4])
vector.send(method, 4..0).should eql(V.empty)
vector.send(method, 4..4).should eql(V.empty)
vector.send(method, 4..5).should eql(V.empty)
vector.send(method, 5..0).should be_nil
vector.send(method, 5..5).should be_nil
vector.send(method, 5..6).should be_nil
big.send(method, 159..162).should eql(V[160,161,162,163])
big.send(method, 160..162).should eql(V[161,162,163])
big.send(method, 161..162).should eql(V[162,163])
big.send(method, 9999..10100).should eql(V[10000])
big.send(method, 10000..10100).should eql(V.empty)
big.send(method, 10001..10100).should be_nil
vector.send(method, 0...-1).should eql(V[1,2,3])
vector.send(method, 0...-10).should eql(V.empty)
vector.send(method, 0...0).should eql(V.empty)
vector.send(method, 0...1).should eql(V[1])
vector.send(method, 0...2).should eql(V[1,2])
vector.send(method, 0...3).should eql(V[1,2,3])
vector.send(method, 0...4).should eql(V[1,2,3,4])
vector.send(method, 0...10).should eql(V[1,2,3,4])
vector.send(method, 2...-10).should eql(V.empty)
vector.send(method, 2...0).should eql(V.empty)
vector.send(method, 2...2).should eql(V.empty)
vector.send(method, 2...3).should eql(V[3])
vector.send(method, 2...4).should eql(V[3,4])
vector.send(method, 3...0).should eql(V.empty)
vector.send(method, 3...3).should eql(V.empty)
vector.send(method, 3...4).should eql(V[4])
vector.send(method, 4...0).should eql(V.empty)
vector.send(method, 4...4).should eql(V.empty)
vector.send(method, 4...5).should eql(V.empty)
vector.send(method, 5...0).should be_nil
vector.send(method, 5...5).should be_nil
vector.send(method, 5...6).should be_nil
big.send(method, 159...162).should eql(V[160,161,162])
big.send(method, 160...162).should eql(V[161,162])
big.send(method, 161...162).should eql(V[162])
big.send(method, 9999...10100).should eql(V[10000])
big.send(method, 10000...10100).should eql(V.empty)
big.send(method, 10001...10100).should be_nil
vector.send(method, -1..-1).should eql(V[4])
vector.send(method, -1...-1).should eql(V.empty)
vector.send(method, -1..3).should eql(V[4])
vector.send(method, -1...3).should eql(V.empty)
vector.send(method, -1..4).should eql(V[4])
vector.send(method, -1...4).should eql(V[4])
vector.send(method, -1..10).should eql(V[4])
vector.send(method, -1...10).should eql(V[4])
vector.send(method, -1..0).should eql(V.empty)
vector.send(method, -1..-4).should eql(V.empty)
vector.send(method, -1...-4).should eql(V.empty)
vector.send(method, -1..-6).should eql(V.empty)
vector.send(method, -1...-6).should eql(V.empty)
vector.send(method, -2..-2).should eql(V[3])
vector.send(method, -2...-2).should eql(V.empty)
vector.send(method, -2..-1).should eql(V[3,4])
vector.send(method, -2...-1).should eql(V[3])
vector.send(method, -2..10).should eql(V[3,4])
vector.send(method, -2...10).should eql(V[3,4])
big.send(method, -1..-1).should eql(V[10000])
big.send(method, -1..9999).should eql(V[10000])
big.send(method, -1...9999).should eql(V.empty)
big.send(method, -2...9999).should eql(V[9999])
big.send(method, -2..-1).should eql(V[9999,10000])
vector.send(method, -4..-4).should eql(V[1])
vector.send(method, -4..-2).should eql(V[1,2,3])
vector.send(method, -4...-2).should eql(V[1,2])
vector.send(method, -4..-1).should eql(V[1,2,3,4])
vector.send(method, -4...-1).should eql(V[1,2,3])
vector.send(method, -4..3).should eql(V[1,2,3,4])
vector.send(method, -4...3).should eql(V[1,2,3])
vector.send(method, -4..4).should eql(V[1,2,3,4])
vector.send(method, -4...4).should eql(V[1,2,3,4])
vector.send(method, -4..0).should eql(V[1])
vector.send(method, -4...0).should eql(V.empty)
vector.send(method, -4..1).should eql(V[1,2])
vector.send(method, -4...1).should eql(V[1])
vector.send(method, -5..-5).should be_nil
vector.send(method, -5...-5).should be_nil
vector.send(method, -5..-4).should be_nil
vector.send(method, -5..-1).should be_nil
vector.send(method, -5..10).should be_nil
big.send(method, -10001..-1).should be_nil
end
it 'leaves the original unchanged' do
vector.should eql(V[1,2,3,4])
end
end
end
context 'when passed a subclass of Range' do
it 'works the same as with a Range' do
subclass = Class.new(Range)
vector.send(method, subclass.new(1,2)).should eql(V[2,3])
vector.send(method, subclass.new(-3,-1,true)).should eql(V[2,3])
end
end
context 'on a subclass of Vector' do
it 'with index and count or a range, returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.send(method, 0, 0).class.should be(subclass)
instance.send(method, 0, 2).class.should be(subclass)
instance.send(method, 0..0).class.should be(subclass)
instance.send(method, 1..-1).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/join_spec.rb 0000644 0001750 0001750 00000002752 14201005456 024145 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#join' do
context 'with a separator' do
[
[[], ''],
[['A'], 'A'],
[[DeterministicHash.new('A', 1), DeterministicHash.new('B', 2), DeterministicHash.new('C', 3)], 'A|B|C']
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.join('|')
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.join('|').should == expected
end
end
end
end
context 'without a separator' do
[
[[], ''],
[['A'], 'A'],
[[DeterministicHash.new('A', 1), DeterministicHash.new('B', 2), DeterministicHash.new('C', 3)], 'ABC']
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.join
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.join.should == expected
end
end
end
end
context 'without a separator (with global default separator set)' do
before { $, = '**' }
after { $, = nil }
describe 'on ["A", "B", "C"]' do
it 'returns "A**B**C"' do
V['A', 'B', 'C'].join.should == 'A**B**C'
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/concat_spec.rb 0000644 0001750 0001750 00000002077 14201005456 024455 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:+, :concat].each do |method|
describe "##{method}" do
let(:vector) { V.new(1..100) }
it 'preserves the original' do
vector.concat([1,2,3])
vector.should eql(V.new(1..100))
end
it 'appends the elements in the other enumerable' do
vector.concat([1,2,3]).should eql(V.new((1..100).to_a + [1,2,3]))
vector.concat(1..1000).should eql(V.new((1..100).to_a + (1..1000).to_a))
vector.concat(1..200).size.should == 300
vector.concat(vector).should eql(V.new((1..100).to_a * 2))
vector.concat(V.empty).should eql(vector)
V.empty.concat(vector).should eql(vector)
end
[1, 31, 32, 33, 1023, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
it 'works the same' do
vector = V.new(1..size)
result = vector.concat((size+1)..size+10)
result.size.should == size + 10
result.should eql(V.new(1..(size+10)))
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/each_with_index_spec.rb 0000644 0001750 0001750 00000002134 14201005456 026322 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#each_with_index' do
describe 'with no block' do
let(:vector) { V['A', 'B', 'C'] }
it 'returns an Enumerator' do
vector.each_with_index.class.should be(Enumerator)
vector.each_with_index.to_a.should == [['A', 0], ['B', 1], ['C', 2]]
end
end
[1, 2, 31, 32, 33, 1023, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
describe 'with a block' do
let(:vector) { V.new(1..size) }
it 'returns self' do
pairs = []
vector.each_with_index { |item, index| pairs << [item, index] }.should be(vector)
end
it 'iterates over the items in order' do
pairs = []
vector.each_with_index { |item, index| pairs << [item, index] }.should be(vector)
pairs.should == (1..size).zip(0..size.pred)
end
end
end
end
context 'on an empty vector' do
it "doesn't yield anything" do
V.empty.each_with_index { |item, index| fail }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/add_spec.rb 0000644 0001750 0001750 00000003601 14201005456 023730 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
[:add, :<<, :push].each do |method|
describe "##{method}" do
shared_examples 'checking adding values' do
let(:added_vector) { V[*added_values] }
it 'preserves the original' do
original = vector
vector.send(method, added_value)
expect(original).to eq(vector)
end
it 'adds the item to the vector' do
result = vector.send(method, added_value)
expect(result).to eq(added_vector)
expect(result.size).to eq(vector.size + 1)
end
end
context 'with a empty vector adding a single item' do
let(:values) { [] }
let(:added_value) { 'A' }
let(:added_values) { ['A'] }
include_examples 'checking adding values'
end
context 'with a single-item vector adding a different item' do
let(:values) { ['A'] }
let(:added_value) { 'B' }
let(:added_values) { %w[A B] }
include_examples 'checking adding values'
end
context 'with a single-item vector adding a duplicate item' do
let(:values) { ['A'] }
let(:added_value) { 'A' }
let(:added_values) { %w[A A] }
include_examples 'checking adding values'
end
[31, 32, 33, 1023, 1024, 1025].each do |size|
context "with a #{size}-item vector adding a different item" do
let(:values) { (1..size).to_a }
let(:added_value) { size+1 }
let(:added_values) { (1..(size+1)).to_a }
include_examples 'checking adding values'
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass[1,2,3]
instance.add(4).class.should be(subclass)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/take_spec.rb 0000644 0001750 0001750 00000002100 14201005456 024115 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#take' do
[
[[], 10, []],
[['A'], 10, ['A']],
[%w[A B C], 0, []],
[%w[A B C], 2, %w[A B]],
[(1..32), 1, [1]],
[(1..33), 32, (1..32)],
[(1..100), 40, (1..40)]
].each do |values, number, expected|
describe "#{number} from #{values.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.take(number)
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.take(number).should eql(V[*expected])
end
end
end
context 'when number of elements specified is identical to size' do
let(:vector) { V[1, 2, 3, 4, 5, 6] }
it 'returns self' do
vector.take(vector.size).should be(vector)
end
end
context 'when number of elements specified is bigger than size' do
let(:vector) { V[1, 2, 3, 4, 5, 6] }
it 'returns self' do
vector.take(vector.size + 1).should be(vector)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/values_at_spec.rb 0000644 0001750 0001750 00000001645 14201005456 025171 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#values_at' do
let(:vector) { V['a', 'b', 'c'] }
it 'accepts any number of indices, and returns a vector of items at those indices' do
vector.values_at(0).should eql(V['a'])
vector.values_at(1,2).should eql(V['b', 'c'])
end
context 'when passed invalid indices' do
it 'fills in with nils' do
vector.values_at(1,2,3).should eql(V['b', 'c', nil])
vector.values_at(-10,10).should eql(V[nil, nil])
end
end
context 'when passed no arguments' do
it 'returns an empty vector' do
vector.values_at.should eql(V.empty)
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.values_at(1,2).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/select_spec.rb 0000644 0001750 0001750 00000003602 14201005456 024460 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:select, :find_all].each do |method|
describe "##{method}" do
let(:vector) { V['A', 'B', 'C'] }
describe 'with a block' do
it 'preserves the original' do
vector.send(method) { |item| item == 'A' }
vector.should eql(V['A', 'B', 'C'])
end
it 'returns a vector with the matching values' do
vector.send(method) { |item| item == 'A' }.should eql(V['A'])
end
end
describe 'with no block' do
it 'returns an Enumerator' do
vector.send(method).class.should be(Enumerator)
vector.send(method).each { |item| item == 'A' }.should eql(V['A'])
end
end
describe 'when nothing matches' do
it 'preserves the original' do
vector.send(method) { |item| false }
vector.should eql(V['A', 'B', 'C'])
end
it 'returns an empty vector' do
vector.send(method) { |item| false }.should equal(V.empty)
end
end
context 'on an empty vector' do
it 'returns self' do
V.empty.send(method) { |item| true }.should be(V.empty)
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass[1,2,3]
instance.send(method) { |x| x > 1 }.class.should be(subclass)
end
end
it 'works with a variety of inputs' do
[1, 2, 10, 31, 32, 33, 1023, 1024, 1025].each do |size|
[0, 5, 32, 50, 500, 800, 1024].each do |threshold|
vector = V.new(1..size)
result = vector.send(method) { |item| item <= threshold }
result.size.should == [size, threshold].min
result.should eql(V.new(1..[size, threshold].min))
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/uniq_spec.rb 0000644 0001750 0001750 00000004263 14201005456 024161 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#uniq' do
let(:vector) { V['a', 'b', 'a', 'a', 'c', 'b'] }
it 'returns a vector with no duplicates' do
vector.uniq.should eql(V['a', 'b', 'c'])
end
it 'leaves the original unmodified' do
vector.uniq
vector.should eql(V['a', 'b', 'a', 'a', 'c', 'b'])
end
it 'uses #eql? semantics' do
V[1.0, 1].uniq.should eql(V[1.0, 1])
end
it 'also uses #hash when determining which values are duplicates' do
x = double(1)
x.should_receive(:hash).at_least(1).times.and_return(1)
y = double(2)
y.should_receive(:hash).at_least(1).times.and_return(2)
V[x, y].uniq
end
it 'keeps the first of each group of duplicate values' do
x, y, z = 'a', 'a', 'a'
result = V[x, y, z].uniq
result.size.should == 1
result[0].should be(x)
end
context 'when passed a block' do
it 'uses the return value of the block to determine which items are duplicate' do
v = V['a', 'A', 'B', 'b']
v.uniq(&:upcase).should == V['a', 'B']
end
end
context 'on a vector with no duplicates' do
it 'returns an unchanged vector' do
V[1, 2, 3].uniq.should eql(V[1, 2, 3])
end
context 'if the vector has more than 32 elements and is initialized with Vector.new' do
# Regression test for GitHub issue #182
it 'returns an unchanged vector' do
vector1,vector2 = 2.times.collect { V.new(0..36) }
vector1.uniq.should eql(vector2)
end
end
end
[10, 31, 32, 33, 1000, 1023, 1024, 1025, 2000].each do |size|
context "on a #{size}-item vector" do
it 'behaves like Array#uniq' do
array = size.times.map { rand(size*2) }
vector = V.new(array)
result = vector.uniq
result.should == array.uniq
result.class.should be(Immutable::Vector)
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.uniq.class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/sorting_spec.rb 0000644 0001750 0001750 00000003057 14201005456 024672 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[
[:sort, ->(left, right) { left.length <=> right.length }],
[:sort_by, ->(item) { item.length }],
].each do |method, comparator|
describe "##{method}" do
[
[[], []],
[['A'], ['A']],
[%w[Ichi Ni San], %w[Ni San Ichi]],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
context 'with a block' do
it 'preserves the original' do
vector.send(method, &comparator)
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.send(method, &comparator).should eql(V[*expected])
end
end
context 'without a block' do
it 'preserves the original' do
vector.send(method)
vector.should eql(V[*values])
end
it "returns #{expected.sort.inspect}" do
vector.send(method).should eql(V[*expected.sort])
end
end
end
end
[10, 31, 32, 33, 1023, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
it "behaves like Array#{method}" do
array = size.times.map { rand(10000) }
vector = V.new(array)
if method == :sort
vector.sort.should == array.sort
else
vector.sort_by(&:-@).should == array.sort_by(&:-@)
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/eql_spec.rb 0000644 0001750 0001750 00000004216 14201005456 023764 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#eql' do
let(:vector) { V['A', 'B', 'C'] }
it 'returns false when comparing with an array with the same contents' do
vector.eql?(%w[A B C]).should == false
end
it 'returns false when comparing with an arbitrary object' do
vector.eql?(Object.new).should == false
end
it 'returns false when comparing an empty vector with an empty array' do
V.empty.eql?([]).should == false
end
it 'returns false when comparing with a subclass of Immutable::Vector' do
vector.eql?(Class.new(Immutable::Vector).new(%w[A B C])).should == false
end
end
describe '#==' do
let(:vector) { V['A', 'B', 'C'] }
it 'returns true when comparing with an array with the same contents' do
(vector == %w[A B C]).should == true
end
it 'returns false when comparing with an arbitrary object' do
(vector == Object.new).should == false
end
it 'returns true when comparing an empty vector with an empty array' do
(V.empty == []).should == true
end
it 'returns true when comparing with a subclass of Immutable::Vector' do
(vector == Class.new(Immutable::Vector).new(%w[A B C])).should == true
end
it 'works on larger vectors' do
array = 2000.times.map { rand(10000) }
(V.new(array.dup) == array).should == true
end
end
[:eql?, :==].each do |method|
describe "##{method}" do
[
[[], [], true],
[[], [nil], false],
[['A'], [], false],
[['A'], ['A'], true],
[['A'], ['B'], false],
[%w[A B], ['A'], false],
[%w[A B C], %w[A B C], true],
[%w[C A B], %w[A B C], false],
].each do |a, b, expected|
describe "returns #{expected.inspect}" do
let(:vector_a) { V[*a] }
let(:vector_b) { V[*b] }
it "for vectors #{a.inspect} and #{b.inspect}" do
vector_a.send(method, vector_b).should == expected
end
it "for vectors #{b.inspect} and #{a.inspect}" do
vector_b.send(method, vector_a).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/rotate_spec.rb 0000644 0001750 0001750 00000004013 14201005456 024474 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#rotate' do
let(:vector) { V[1,2,3,4,5] }
context 'when passed no argument' do
it 'returns a new vector with the first element moved to the end' do
vector.rotate.should eql(V[2,3,4,5,1])
end
end
context 'with an integral argument n' do
it 'returns a new vector with the first (n % size) elements moved to the end' do
vector.rotate(2).should eql(V[3,4,5,1,2])
vector.rotate(3).should eql(V[4,5,1,2,3])
vector.rotate(4).should eql(V[5,1,2,3,4])
vector.rotate(5).should eql(V[1,2,3,4,5])
vector.rotate(-1).should eql(V[5,1,2,3,4])
end
end
context 'with a floating-point argument n' do
it 'coerces the argument to integer using to_int' do
vector.rotate(2.1).should eql(V[3,4,5,1,2])
end
end
context 'with a non-numeric argument' do
it 'raises a TypeError' do
-> { vector.rotate('hello') }.should raise_error(TypeError)
end
end
context 'with an argument of zero' do
it 'returns self' do
vector.rotate(0).should be(vector)
end
end
context "with an argument equal to the vector's size" do
it 'returns self' do
vector.rotate(5).should be(vector)
end
end
[31, 32, 33, 1000, 1023, 1024, 1025].each do |size|
context "on a #{size}-item vector" do
it 'behaves like Array#rotate' do
array = (1..size).to_a
vector = V.new(array)
10.times do
offset = rand(size)
vector.rotate(offset).should == array.rotate(offset)
end
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.rotate(2).class.should be(subclass)
end
end
it 'leaves the original unmodified' do
vector.rotate(3)
vector.should eql(V[1,2,3,4,5])
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/include_spec.rb 0000644 0001750 0001750 00000001455 14201005456 024630 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:include?, :member?].each do |method|
describe "##{method}" do
[
[[], 'A', false],
[[], nil, false],
[['A'], 'A', true],
[['A'], 'B', false],
[['A'], nil, false],
[['A', 'B', nil], 'A', true],
[['A', 'B', nil], 'B', true],
[['A', 'B', nil], nil, true],
[['A', 'B', nil], 'C', false],
[['A', 'B', false], false, true],
[[2], 2, true],
[[2], 2.0, true],
[[2.0], 2.0, true],
[[2.0], 2, true],
].each do |values, item, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].send(method, item).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/group_by_spec.rb 0000644 0001750 0001750 00000003157 14201005456 025034 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#group_by' do
context 'with a block' do
[
[[], []],
[[1], [true => V[1]]],
[[1, 2, 3, 4], [true => V[1, 3], false => V[2, 4]]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:vector) { V[*values] }
it "returns #{expected.inspect}" do
vector.group_by(&:odd?).should eql(H[*expected])
vector.should eql(V.new(values)) # make sure it hasn't changed
end
end
end
end
context 'without a block' do
[
[[], []],
[[1], [1 => V[1]]],
[[1, 2, 3, 4], [1 => V[1], 2 => V[2], 3 => V[3], 4 => V[4]]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:vector) { V[*values] }
it "returns #{expected.inspect}" do
vector.group_by.should eql(H[*expected])
vector.should eql(V.new(values)) # make sure it hasn't changed
end
end
end
end
context 'on an empty vector' do
it 'returns an empty hash' do
V.empty.group_by { |x| x }.should eql(H.empty)
end
end
it 'returns a hash without default proc' do
V[1,2,3].group_by { |x| x }.default_proc.should be_nil
end
context 'from a subclass' do
it 'returns an Hash whose values are instances of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1, 'string', :symbol])
instance.group_by(&:class).values.each { |v| v.class.should be(subclass) }
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/clear_spec.rb 0000644 0001750 0001750 00000001360 14201005456 024266 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#clear' do
[
[],
['A'],
%w[A B C],
].each do |values|
describe "on #{values}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.clear
vector.should eql(V[*values])
end
it 'returns an empty vector' do
vector.clear.should equal(V.empty)
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new(%w{a b c})
instance.clear.class.should be(subclass)
instance.clear.should be_empty
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/to_list_spec.rb 0000644 0001750 0001750 00000001172 14201005456 024656 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#to_list' do
[
[],
['A'],
%w[A B C],
].each do |values|
describe "on #{values.inspect}" do
let(:vector) { V.new(values) }
let(:list) { vector.to_list }
it 'returns a list' do
list.is_a?(Immutable::List).should == true
end
describe 'the returned list' do
it 'has the correct length' do
list.size.should == values.size
end
it 'contains all values' do
list.to_a.should == values
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/repeated_combination_spec.rb 0000644 0001750 0001750 00000005060 14201005456 027354 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#repeated_combination' do
let(:vector) { V[1,2,3,4] }
context 'with no block' do
it 'returns an Enumerator' do
vector.repeated_combination(2).class.should be(Enumerator)
end
end
context 'with a block' do
it 'returns self' do
vector.repeated_combination(2) {}.should be(vector)
end
end
context 'with a negative argument' do
it 'yields nothing and returns self' do
result = []
vector.repeated_combination(-1) { |obj| result << obj }.should be(vector)
result.should eql([])
end
end
context 'with a zero argument' do
it 'yields an empty array' do
result = []
vector.repeated_combination(0) { |obj| result << obj }
result.should eql([[]])
end
end
context 'with a argument of 1' do
it 'yields each item in the vector, as single-item vectors' do
result = []
vector.repeated_combination(1) { |obj| result << obj }
result.should eql([[1],[2],[3],[4]])
end
end
context 'on an empty vector, with an argument greater than zero' do
it 'yields nothing' do
result = []
V.empty.repeated_combination(1) { |obj| result << obj }
result.should eql([])
end
end
context 'with a positive argument, greater than 1' do
it 'yields all combinations of the given size (where a single element can appear more than once in a row)' do
vector.repeated_combination(2).to_a.should == [[1,1], [1,2], [1,3], [1,4], [2,2], [2,3], [2,4], [3,3], [3,4], [4,4]]
vector.repeated_combination(3).to_a.should == [[1,1,1], [1,1,2], [1,1,3], [1,1,4],
[1,2,2], [1,2,3], [1,2,4], [1,3,3], [1,3,4], [1,4,4], [2,2,2], [2,2,3],
[2,2,4], [2,3,3], [2,3,4], [2,4,4], [3,3,3], [3,3,4], [3,4,4], [4,4,4]]
V[1,2,3].repeated_combination(3).to_a.should == [[1,1,1], [1,1,2],
[1,1,3], [1,2,2], [1,2,3], [1,3,3], [2,2,2], [2,2,3], [2,3,3], [3,3,3]]
end
end
it 'leaves the original unmodified' do
vector.repeated_combination(2) {}
vector.should eql(V[1,2,3,4])
end
it 'behaves like Array#repeated_combination' do
0.upto(5) do |comb_size|
array = 10.times.map { rand(1000) }
V.new(array).repeated_combination(comb_size).to_a.should == array.repeated_combination(comb_size).to_a
end
array = 18.times.map { rand(1000) }
V.new(array).repeated_combination(2).to_a.should == array.repeated_combination(2).to_a
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/compact_spec.rb 0000644 0001750 0001750 00000001327 14201005456 024631 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#compact' do
it 'returns a new Vector with all nils removed' do
V[1, nil, 2, nil].compact.should eql(V[1, 2])
V[1, 2, 3].compact.should eql(V[1, 2, 3])
V[nil].compact.should eql(V.empty)
end
context 'on an empty vector' do
it 'returns self' do
V.empty.compact.should be(V.empty)
end
end
it "doesn't remove false" do
V[false].compact.should eql(V[false])
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(V)
instance = subclass[1, nil, 2]
instance.compact.class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/zip_spec.rb 0000644 0001750 0001750 00000003445 14201005456 024010 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#zip' do
let(:vector) { V[1,2,3,4] }
context 'with a block' do
it 'yields arrays of one corresponding element from each input sequence' do
result = []
vector.zip(['a', 'b', 'c', 'd']) { |obj| result << obj }
result.should eql([[1,'a'], [2,'b'], [3,'c'], [4,'d']])
end
it 'fills in the missing values with nils' do
result = []
vector.zip(['a', 'b']) { |obj| result << obj }
result.should eql([[1,'a'], [2,'b'], [3,nil], [4,nil]])
end
it 'returns nil' do
vector.zip([2,3,4]) {}.should be_nil
end
it 'can handle multiple inputs, of different classes' do
result = []
vector.zip(V[2,3,4,5], [5,6,7,8]) { |obj| result << obj }
result.should eql([[1,2,5], [2,3,6], [3,4,7], [4,5,8]])
end
end
context 'without a block' do
it 'returns a vector of arrays (one corresponding element from each input sequence)' do
vector.zip([2,3,4,5]).should eql(V[[1,2], [2,3], [3,4], [4,5]])
end
end
[10, 31, 32, 33, 1000, 1023, 1024, 1025].each do |size|
context "on #{size}-item vectors" do
it 'behaves like Array#zip' do
array = (rand(9)+1).times.map { size.times.map { rand(10000) }}
vectors = array.map { |a| V.new(a) }
result = vectors.first.zip(*vectors.drop(1))
result.class.should be(Immutable::Vector)
result.should == array[0].zip(*array.drop(1))
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass.new([1,2,3])
instance.zip([4,5,6]).class.should be(subclass)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/drop_while_spec.rb 0000644 0001750 0001750 00000002716 14201005456 025342 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#drop_while' do
[
[[], []],
[['A'], []],
[%w[A B C], ['C']],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
describe 'with a block' do
let(:result) { vector.drop_while { |item| item < 'C' } }
it 'preserves the original' do
result
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
result.should eql(V[*expected])
end
end
describe 'without a block' do
it 'returns an Enumerator' do
vector.drop_while.class.should be(Enumerator)
vector.drop_while.each { |item| item < 'C' }.should eql(V[*expected])
end
end
end
end
context 'on an empty vector' do
it 'returns an empty vector' do
V.empty.drop_while { false }.should eql(V.empty)
end
end
it 'returns an empty vector if block is always true' do
V.new(1..32).drop_while { true }.should eql(V.empty)
V.new(1..100).drop_while { true }.should eql(V.empty)
end
it 'stops dropping items if block returns nil' do
V[1, 2, 3, nil, 4, 5].drop_while { |x| x }.should eql(V[nil, 4, 5])
end
it 'stops dropping items if block returns false' do
V[1, 2, 3, false, 4, 5].drop_while { |x| x }.should eql(V[false, 4, 5])
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/fill_spec.rb 0000644 0001750 0001750 00000005402 14201005456 024127 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#fill' do
let(:vector) { V[1, 2, 3, 4, 5, 6] }
it 'can replace a range of items at the beginning of a vector' do
vector.fill(:a, 0, 3).should eql(V[:a, :a, :a, 4, 5, 6])
end
it 'can replace a range of items in the middle of a vector' do
vector.fill(:a, 3, 2).should eql(V[1, 2, 3, :a, :a, 6])
end
it 'can replace a range of items at the end of a vector' do
vector.fill(:a, 4, 2).should eql(V[1, 2, 3, 4, :a, :a])
end
it 'can replace all the items in a vector' do
vector.fill(:a, 0, 6).should eql(V[:a, :a, :a, :a, :a, :a])
end
it 'can fill past the end of the vector' do
vector.fill(:a, 3, 6).should eql(V[1, 2, 3, :a, :a, :a, :a, :a, :a])
end
context 'with 1 argument' do
it 'replaces all the items in the vector by default' do
vector.fill(:a).should eql(V[:a, :a, :a, :a, :a, :a])
end
end
context 'with 2 arguments' do
it 'replaces up to the end of the vector by default' do
vector.fill(:a, 4).should eql(V[1, 2, 3, 4, :a, :a])
end
end
context 'when index and length are 0' do
it 'leaves the vector unmodified' do
vector.fill(:a, 0, 0).should eql(vector)
end
end
context 'when expanding a vector past boundary where vector trie needs to deepen' do
it 'works the same' do
vector.fill(:a, 32, 3).size.should == 35
vector.fill(:a, 32, 3).to_a.size.should == 35
end
end
[1000, 1023, 1024, 1025, 2000].each do |size|
context "on a #{size}-item vector" do
it 'works the same' do
array = (0..size).to_a
vector = V.new(array)
[[:a, 0, 5], [:b, 31, 2], [:c, 32, 60], [:d, 1000, 20], [:e, 1024, 33], [:f, 1200, 35]].each do |obj, index, length|
next if index > size
vector = vector.fill(obj, index, length)
array.fill(obj, index, length)
vector.size.should == array.size
ary = vector.to_a
ary.size.should == vector.size
ary.should eql(array)
end
end
end
end
it 'behaves like Array#fill, on a variety of inputs' do
50.times do
array = rand(100).times.map { rand(1000) }
index = rand(array.size)
length = rand(50)
V.new(array).fill(:a, index, length).should == array.fill(:a, index, length)
end
10.times do
array = rand(100).times.map { rand(10000) }
length = rand(100)
V.new(array).fill(:a, array.size, length).should == array.fill(:a, array.size, length)
end
10.times do
array = rand(100).times.map { rand(10000) }
V.new(array).fill(:a).should == array.fill(:a)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/maximum_spec.rb 0000644 0001750 0001750 00000001432 14201005456 024655 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#max' do
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].max { |maximum, item| maximum.length <=> item.length }.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'San'],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].max.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/insert_spec.rb 0000644 0001750 0001750 00000004042 14201005456 024504 0 ustar boutil boutil require 'spec_helper'
require 'pry'
describe Immutable::Vector do
describe '#insert' do
let(:original) { V[1, 2, 3] }
it 'can add items at the beginning of a vector' do
vector = original.insert(0, :a, :b)
vector.size.should be(5)
vector.at(0).should be(:a)
vector.at(2).should be(1)
end
it 'can add items in the middle of a vector' do
vector = original.insert(1, :a, :b, :c)
vector.size.should be(6)
vector.to_a.should == [1, :a, :b, :c, 2, 3]
end
it 'can add items at the end of a vector' do
vector = original.insert(3, :a, :b, :c)
vector.size.should be(6)
vector.to_a.should == [1, 2, 3, :a, :b, :c]
end
it 'can add items past the end of a vector' do
vector = original.insert(6, :a, :b)
vector.size.should be(8)
vector.to_a.should == [1, 2, 3, nil, nil, nil, :a, :b]
end
it 'accepts a negative index, which counts back from the end of the vector' do
vector = original.insert(-2, :a)
vector.size.should be(4)
vector.to_a.should == [1, :a, 2, 3]
end
it 'raises IndexError if a negative index is too great' do
expect { original.insert(-4, :a) }.to raise_error(IndexError)
end
it 'works when adding an item past boundary when vector trie needs to deepen' do
vector = original.insert(32, :a, :b)
vector.size.should == 34
vector.to_a.size.should == 34
end
it 'works when adding to an empty Vector' do
V.empty.insert(0, :a).should eql(V[:a])
end
it 'has the right size and contents after many insertions' do
array = (1..4000).to_a # we use an Array as standard of correctness
vector = Immutable::Vector.new(array)
100.times do
items = rand(10).times.map { rand(10000) }
index = rand(vector.size)
vector = vector.insert(index, *items)
array.insert(index, *items)
vector.size.should == array.size
ary = vector.to_a
ary.size.should == vector.size
ary.should eql(array)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/length_spec.rb 0000644 0001750 0001750 00000001641 14201005456 024463 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#length' do
let(:length) { vector.length }
shared_examples 'checking size' do
it 'returns the values' do
expect(length).to eq(size)
end
end
context 'with an empty vector' do
let(:values) { [] }
let(:size) { 0 }
include_examples 'checking size'
end
context 'with a single item vector' do
let(:values) { %w[A] }
let(:size) { 1 }
include_examples 'checking size'
end
context 'with a multi-item vector' do
let(:values) { %w[A B] }
let(:size) { 2 }
include_examples 'checking size'
end
[31, 32, 33, 1023, 1024, 1025].each do |size|
context "with a #{size}-item vector" do
let(:values) { (1..size).to_a }
let(:size) { size }
include_examples 'checking size'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/compare_spec.rb 0000644 0001750 0001750 00000001276 14201005456 024634 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#<=>' do
[
[[], [1]],
[[1], [2]],
[[1], [1, 2]],
[[2, 3, 4], [3, 4, 5]],
[[[0]], [[1]]]
].each do |items1, items2|
describe "with #{items1} and #{items2}" do
it 'returns -1' do
(V.new(items1) <=> V.new(items2)).should be(-1)
end
end
describe "with #{items2} and #{items1}" do
it 'returns 1' do
(V.new(items2) <=> V.new(items1)).should be(1)
end
end
describe "with #{items1} and #{items1}" do
it 'returns 0' do
(V.new(items1) <=> V.new(items1)).should be(0)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/first_spec.rb 0000644 0001750 0001750 00000000557 14201005456 024336 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#first' do
[
[[], nil],
[['A'], 'A'],
[%w[A B C], 'A'],
[(1..32), 1],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].first.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/combination_spec.rb 0000644 0001750 0001750 00000004450 14201005456 025505 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#combination' do
let(:vector) { V[1,2,3,4] }
context 'with a block' do
it 'returns self' do
vector.combination(2) {}.should be(vector)
end
end
context 'with no block' do
it 'returns an Enumerator' do
vector.combination(2).class.should be(Enumerator)
vector.combination(2).to_a.should == vector.to_a.combination(2).to_a
end
end
context 'when passed an argument which is out of bounds' do
it 'yields nothing and returns self' do
vector.combination(5) { fail }.should be(vector)
vector.combination(-1) { fail }.should be(vector)
end
end
context 'when passed an argument zero' do
it 'yields an empty array' do
result = []
vector.combination(0) { |obj| result << obj }
result.should eql([[]])
end
end
context "when passed an argument equal to the vector's length" do
it 'yields self as an array' do
result = []
vector.combination(4) { |obj| result << obj }
result.should eql([vector.to_a])
end
end
context 'when passed an argument 1' do
it 'yields each item in the vector, as single-item vectors' do
result = []
vector.combination(1) { |obj| result << obj }
result.should eql([[1], [2], [3], [4]])
end
end
context 'when passed another integral argument' do
it 'yields all combinations of the given length' do
result = []
vector.combination(3) { |obj| result << obj }
result.should eql([[1,2,3], [1,2,4], [1,3,4], [2,3,4]])
end
end
context 'on an empty vector' do
it 'works the same' do
V.empty.combination(0).to_a.should == [[]]
V.empty.combination(1).to_a.should == []
end
end
it 'works on many combinations of input' do
0.upto(5) do |comb_size|
array = 12.times.map { rand(1000) }
V.new(array).combination(comb_size).to_a.should == array.combination(comb_size).to_a
end
array = 20.times.map { rand(1000) }
V.new(array).combination(2).to_a.should == array.combination(2).to_a
end
it 'leaves the original unmodified' do
vector.combination(2) {}
vector.should eql(V[1,2,3,4])
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/count_spec.rb 0000644 0001750 0001750 00000000670 14201005456 024333 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#count' do
it 'returns the number of elements' do
V[:a, :b, :c].count.should == 3
end
it 'returns the number of elements that equal the argument' do
V[:a, :b, :b, :c].count(:b).should == 2
end
it 'returns the number of element for which the block evaluates to true' do
V[:a, :b, :c].count { |s| s != :b }.should == 2
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/set_spec.rb 0000644 0001750 0001750 00000012472 14201005456 024001 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[*values] }
describe '#set' do
context 'when empty' do
let(:vector) { V.empty }
it 'raises an error for index -1' do
expect { vector.set(-1, :a) }.to raise_error
end
it 'allows indexes 0 and 1 to be set' do
vector.set(0, :a).should eql(V[:a])
vector.set(1, :a).should eql(V[nil, :a])
end
end
context 'when not empty' do
let(:vector) { V['A', 'B', 'C'] }
context 'with a block' do
context 'and a positive index' do
context 'within the absolute bounds of the vector' do
it 'passes the current value to the block' do
vector.set(1) { |value| value.should == 'B' }
end
it 'replaces the value with the result of the block' do
result = vector.set(1) { |value| 'FLIBBLE' }
result.should eql(V['A', 'FLIBBLE', 'C'])
end
it 'supports to_proc methods' do
result = vector.set(1, &:downcase)
result.should eql(V['A', 'b', 'C'])
end
end
context 'just past the end of the vector' do
it 'passes nil to the block and adds a new value' do
result = vector.set(3) { |value| value.should be_nil; 'D' }
result.should eql(V['A', 'B', 'C', 'D'])
end
end
context 'further outside the bounds of the vector' do
it 'passes nil to the block, fills up missing nils, and adds a new value' do
result = vector.set(5) { |value| value.should be_nil; 'D' }
result.should eql(V['A', 'B', 'C', nil, nil, 'D'])
end
end
end
context 'and a negative index' do
context 'within the absolute bounds of the vector' do
it 'passes the current value to the block' do
vector.set(-2) { |value| value.should == 'B' }
end
it 'replaces the value with the result of the block' do
result = vector.set(-2) { |value| 'FLIBBLE' }
result.should eql(V['A', 'FLIBBLE', 'C'])
end
it 'supports to_proc methods' do
result = vector.set(-2, &:downcase)
result.should eql(V['A', 'b', 'C'])
end
end
context 'outside the absolute bounds of the vector' do
it 'raises an error' do
expect { vector.set(-vector.size.next) {} }.to raise_error
end
end
end
end
context 'with a value' do
context 'and a positive index' do
context 'within the absolute bounds of the vector' do
let(:set) { vector.set(1, 'FLIBBLE') }
it 'preserves the original' do
vector.should eql(V['A', 'B', 'C'])
end
it 'sets the new value at the specified index' do
set.should eql(V['A', 'FLIBBLE', 'C'])
end
end
context 'just past the end of the vector' do
it 'adds a new value' do
result = vector.set(3, 'FLIBBLE')
result.should eql(V['A', 'B', 'C', 'FLIBBLE'])
end
end
context 'outside the absolute bounds of the vector' do
it 'fills up with nils' do
result = vector.set(5, 'FLIBBLE')
result.should eql(V['A', 'B', 'C', nil, nil, 'FLIBBLE'])
end
end
end
context 'with a negative index' do
let(:set) { vector.set(-2, 'FLIBBLE') }
it 'preserves the original' do
set
vector.should eql(V['A', 'B', 'C'])
end
it 'sets the new value at the specified index' do
set.should eql(V['A', 'FLIBBLE', 'C'])
end
end
context 'outside the absolute bounds of the vector' do
it 'raises an error' do
expect { vector.set(-vector.size.next, 'FLIBBLE') }.to raise_error
end
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass[1,2,3]
instance.set(1, 2.5).class.should be(subclass)
end
end
[10, 31, 32, 33, 1000, 1023, 1024, 1025, 2000].each do |size|
context "on a #{size}-item vector" do
it 'works correctly' do
array = (1..size).to_a
vector = V.new(array)
[0, 1, 10, 31, 32, 33, 100, 500, 1000, 1023, 1024, 1025, 1998, 1999].select { |n| n < size }.each do |i|
value = rand(10000)
array[i] = value
vector = vector.set(i, value)
vector[i].should be(value)
end
0.upto(size-1) do |i|
vector.get(i).should == array[i]
end
end
end
end
context 'with an identical value to an existing item' do
[1, 2, 5, 31,32, 33, 100, 200].each do |size|
context "on a #{size}-item vector" do
let(:array) { (0...size).map { |x| x * x} }
let(:vector) { V.new(array) }
it 'returns self' do
(0...size).each do |index|
vector.set(index, index * index).should equal(vector)
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/reduce_spec.rb 0000644 0001750 0001750 00000002774 14201005456 024461 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:reduce, :inject].each do |method|
describe "##{method}" do
[
[[], 10, 10],
[[1], 10, 9],
[[1, 2, 3], 10, 4],
].each do |values, initial, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
describe "with an initial value of #{initial}" do
describe 'and a block' do
it "returns #{expected.inspect}" do
vector.send(method, initial) { |memo, item| memo - item }.should == expected
end
end
end
end
end
[
[[], nil],
[[1], 1],
[[1, 2, 3], -4],
].each do |values, expected|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
describe 'with no initial value' do
describe 'and a block' do
it "returns #{expected.inspect}" do
vector.send(method) { |memo, item| memo - item }.should == expected
end
end
end
end
end
describe 'with no block and a symbol argument' do
it 'uses the symbol as the name of a method to reduce with' do
V[1, 2, 3].send(method, :+).should == 6
end
end
describe 'with no block and a string argument' do
it 'uses the string as the name of a method to reduce with' do
V[1, 2, 3].send(method, '+').should == 6
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/shift_spec.rb 0000644 0001750 0001750 00000001067 14201005456 024321 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#shift' do
[
[[], []],
[['A'], []],
[%w[A B C], %w[B C]],
[1..31, 2..31],
[1..32, 2..32],
[1..33, 2..33]
].each do |values, expected|
context "on #{values.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.shift
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.shift.should eql(V[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/sum_spec.rb 0000644 0001750 0001750 00000000527 14201005456 024010 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#sum' do
[
[[], 0],
[[2], 2],
[[1, 3, 5, 7, 11], 27],
].each do |values, expected|
describe "on #{values.inspect}" do
it "returns #{expected.inspect}" do
V[*values].sum.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/rindex_spec.rb 0000644 0001750 0001750 00000001753 14201005456 024477 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#rindex' do
let(:vector) { V[1,2,3,3,2,1] }
context 'when passed an object present in the vector' do
it 'returns the last index where the object is present' do
vector.rindex(1).should be(5)
vector.rindex(2).should be(4)
vector.rindex(3).should be(3)
end
end
context 'when passed an object not present in the vector' do
it 'returns nil' do
vector.rindex(0).should be_nil
vector.rindex(nil).should be_nil
vector.rindex('string').should be_nil
end
end
context 'with a block' do
it 'returns the last index of an object which the predicate is true for' do
vector.rindex { |n| n > 2 }.should be(3)
end
end
context 'without an argument OR block' do
it 'returns an Enumerator' do
vector.rindex.class.should be(Enumerator)
vector.rindex.each { |n| n > 2 }.should be(3)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/map_spec.rb 0000644 0001750 0001750 00000002606 14201005456 023761 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:map, :collect].each do |method|
describe "##{method}" do
context 'when empty' do
let(:vector) { V.empty }
it 'returns self' do
vector.send(method) {}.should equal(vector)
end
end
context 'when not empty' do
let(:vector) { V['A', 'B', 'C'] }
context 'with a block' do
it 'preserves the original values' do
vector.send(method, &:downcase)
vector.should eql(V['A', 'B', 'C'])
end
it 'returns a new vector with the mapped values' do
vector.send(method, &:downcase).should eql(V['a', 'b', 'c'])
end
end
context 'with no block' do
it 'returns an Enumerator' do
vector.send(method).class.should be(Enumerator)
vector.send(method).each(&:downcase).should eql(V['a', 'b', 'c'])
end
end
end
context 'from a subclass' do
it 'returns an instance of the subclass' do
subclass = Class.new(Immutable::Vector)
instance = subclass[1,2,3]
instance.map { |x| x + 1 }.class.should be(subclass)
end
end
context 'on a large vector' do
it 'works' do
V.new(1..2000).map { |x| x * 2 }.should eql(V.new((1..2000).map { |x| x * 2}))
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/reverse_each_spec.rb 0000644 0001750 0001750 00000001554 14201005456 025640 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#reverse_each' do
[2, 31, 32, 33, 1000, 1024, 1025, 2000].each do |size|
context "on a #{size}-item vector" do
let(:vector) { V[1..size] }
context 'with a block (internal iteration)' do
it 'returns self' do
vector.reverse_each {}.should be(vector)
end
it 'yields all items in the opposite order as #each' do
result = []
vector.reverse_each { |item| result << item }
result.should eql(vector.to_a.reverse)
end
end
context 'with no block' do
it 'returns an Enumerator' do
result = vector.reverse_each
result.class.should be(Enumerator)
result.to_a.should eql(vector.to_a.reverse)
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/assoc_spec.rb 0000644 0001750 0001750 00000002364 14201005456 024315 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
let(:vector) { V[[:a, 3], [:b, 2], [:c, 1]] }
describe '#assoc' do
it 'searches for a 2-element array with a given 1st item' do
vector.assoc(:b).should == [:b, 2]
end
it 'returns nil if a matching 1st item is not found' do
vector.assoc(:d).should be_nil
end
it 'uses #== to compare 1st items with provided object' do
vector.assoc(EqualNotEql.new).should_not be_nil
vector.assoc(EqlNotEqual.new).should be_nil
end
it 'skips elements which are not indexable' do
V[false, true, nil].assoc(:b).should be_nil
V[[1,2], nil].assoc(3).should be_nil
end
end
describe '#rassoc' do
it 'searches for a 2-element array with a given 2nd item' do
vector.rassoc(1).should == [:c, 1]
end
it 'returns nil if a matching 2nd item is not found' do
vector.rassoc(4).should be_nil
end
it 'uses #== to compare 2nd items with provided object' do
vector.rassoc(EqualNotEql.new).should_not be_nil
vector.rassoc(EqlNotEqual.new).should be_nil
end
it 'skips elements which are not indexable' do
V[false, true, nil].rassoc(:b).should be_nil
V[[1,2], nil].rassoc(3).should be_nil
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/unshift_spec.rb 0000644 0001750 0001750 00000001271 14201005456 024661 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#unshift' do
[
[[], 'A', ['A']],
[['A'], 'B', %w[B A]],
[['A'], 'A', %w[A A]],
[%w[A B C], 'D', %w[D A B C]],
[1..31, 0, 0..31],
[1..32, 0, 0..32],
[1..33, 0, 0..33]
].each do |values, new_value, expected|
context "on #{values.inspect} with #{new_value.inspect}" do
let(:vector) { V[*values] }
it 'preserves the original' do
vector.unshift(new_value)
vector.should eql(V[*values])
end
it "returns #{expected.inspect}" do
vector.unshift(new_value).should eql(V[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/bsearch_spec.rb 0000644 0001750 0001750 00000003647 14201005456 024621 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#bsearch' do
let(:vector) { V[5,10,20,30] }
context 'with a block which returns false for elements below desired position, and true for those at/above' do
it 'returns the first element for which the predicate is true' do
vector.bsearch { |x| x > 10 }.should be(20)
vector.bsearch { |x| x > 1 }.should be(5)
vector.bsearch { |x| x > 25 }.should be(30)
end
context 'if the block always returns false' do
it 'returns nil' do
vector.bsearch { false }.should be_nil
end
end
context 'if the block always returns true' do
it 'returns the first element' do
vector.bsearch { true }.should be(5)
end
end
end
context 'with a block which returns a negative number for elements below desired position, zero for the right element, and positive for those above' do
it 'returns the element for which the block returns zero' do
vector.bsearch { |x| x <=> 10 }.should be(10)
end
context 'if the block always returns positive' do
it 'returns nil' do
vector.bsearch { 1 }.should be_nil
end
end
context 'if the block always returns negative' do
it 'returns nil' do
vector.bsearch { -1 }.should be_nil
end
end
context 'if the block returns sometimes positive, sometimes negative, but never zero' do
it 'returns nil' do
vector.bsearch { |x| x <=> 11 }.should be_nil
end
end
context 'if not passed a block' do
it 'returns an Enumerator' do
enum = vector.bsearch
enum.should be_a(Enumerator)
enum.each { |x| x <=> 10 }.should == 10
end
end
end
context 'on an empty vector' do
it 'returns nil' do
V.empty.bsearch { |x| x > 5 }.should be_nil
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/copying_spec.rb 0000644 0001750 0001750 00000000561 14201005456 024652 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
[:dup, :clone].each do |method|
[
[],
['A'],
%w[A B C],
(1..32),
].each do |values|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
it 'returns self' do
vector.send(method).should equal(vector)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/partition_spec.rb 0000644 0001750 0001750 00000002702 14201005456 025212 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#partition' do
[
[[], [], []],
[[1], [1], []],
[[1, 2], [1], [2]],
[[1, 2, 3], [1, 3], [2]],
[[1, 2, 3, 4], [1, 3], [2, 4]],
[[2, 3, 4], [3], [2, 4]],
[[3, 4], [3], [4]],
[[4], [], [4]],
].each do |values, expected_matches, expected_remainder|
describe "on #{values.inspect}" do
let(:vector) { V[*values] }
describe 'with a block' do
let(:result) { vector.partition(&:odd?) }
let(:matches) { result.first }
let(:remainder) { result.last }
it 'preserves the original' do
result
vector.should eql(V[*values])
end
it 'returns a frozen array with two items' do
result.class.should be(Array)
result.should be_frozen
result.size.should be(2)
end
it 'correctly identifies the matches' do
matches.should eql(V[*expected_matches])
end
it 'correctly identifies the remainder' do
remainder.should eql(V[*expected_remainder])
end
end
describe 'without a block' do
it 'returns an Enumerator' do
vector.partition.class.should be(Enumerator)
vector.partition.each(&:odd?).should eql([V.new(expected_matches), V.new(expected_remainder)])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/to_set_spec.rb 0000644 0001750 0001750 00000000606 14201005456 024477 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#to_set' do
[
[],
['A'],
%w[A B C],
(1..10),
(1..32),
(1..33),
(1..1000)
].each do |values|
describe "on #{values.inspect}" do
it 'returns a set with the same values' do
V[*values].to_set.should eql(S[*values])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/repeated_permutation_spec.rb 0000644 0001750 0001750 00000006521 14201005456 027424 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#repeated_permutation' do
let(:vector) { V[1,2,3,4] }
context 'without a block' do
context 'and without argument' do
it 'returns an Enumerator of all repeated permutations' do
vector.repeated_permutation.class.should be(Enumerator)
vector.repeated_permutation.to_a.sort.should eql(vector.to_a.repeated_permutation(4).to_a.sort)
end
end
context 'with an integral argument' do
it 'returns an Enumerator of all repeated permutations of the given length' do
vector.repeated_permutation(2).class.should be(Enumerator)
vector.repeated_permutation(2).to_a.sort.should eql(vector.to_a.repeated_permutation(2).to_a.sort)
vector.repeated_permutation(3).class.should be(Enumerator)
vector.repeated_permutation(3).to_a.sort.should eql(vector.to_a.repeated_permutation(3).to_a.sort)
end
end
end
context 'with a block' do
it 'returns self' do
vector.repeated_permutation {}.should be(vector)
end
context 'on an empty vector' do
it 'yields the empty permutation' do
yielded = []
V.empty.repeated_permutation { |obj| yielded << obj }
yielded.should eql([[]])
end
end
context 'with an argument of zero' do
it 'yields the empty permutation' do
yielded = []
vector.repeated_permutation(0) { |obj| yielded << obj }
yielded.should eql([[]])
end
end
context 'with no argument' do
it 'yields all repeated permutations' do
yielded = []
V[1,2,3].repeated_permutation { |obj| yielded << obj }
yielded.sort.should eql([[1,1,1], [1,1,2], [1,1,3], [1,2,1], [1,2,2],
[1,2,3], [1,3,1], [1,3,2], [1,3,3], [2,1,1], [2,1,2], [2,1,3], [2,2,1],
[2,2,2], [2,2,3], [2,3,1], [2,3,2], [2,3,3], [3,1,1], [3,1,2], [3,1,3],
[3,2,1], [3,2,2], [3,2,3], [3,3,1], [3,3,2], [3,3,3]])
end
end
context 'with a positive integral argument' do
it 'yields all repeated permutations of the given length' do
yielded = []
vector.repeated_permutation(2) { |obj| yielded << obj }
yielded.sort.should eql([[1,1], [1,2], [1,3], [1,4], [2,1], [2,2], [2,3], [2,4],
[3,1], [3,2], [3,3], [3,4], [4,1], [4,2], [4,3], [4,4]])
end
end
end
it 'handles duplicate elements correctly' do
V[10,11,10].repeated_permutation(2).sort.should eql([[10, 10], [10, 10],
[10, 10], [10, 10], [10, 11], [10, 11], [11, 10], [11, 10], [11, 11]])
end
it 'allows permutations larger than the number of elements' do
V[1,2].repeated_permutation(3).sort.should eql(
[[1, 1, 1], [1, 1, 2], [1, 2, 1],
[1, 2, 2], [2, 1, 1], [2, 1, 2],
[2, 2, 1], [2, 2, 2]])
end
it 'leaves the original unmodified' do
vector.repeated_permutation(2) {}
vector.should eql(V[1,2,3,4])
end
it 'behaves like Array#repeated_permutation' do
10.times do
array = rand(8).times.map { rand(10000) }
vector = V.new(array)
perm_size = array.size == 0 ? 0 : rand(array.size)
array.repeated_permutation(perm_size).to_a.should == vector.repeated_permutation(perm_size).to_a
end
end
end
end
immutable-ruby-master/spec/lib/immutable/vector/permutation_spec.rb 0000644 0001750 0001750 00000005661 14201005456 025557 0 ustar boutil boutil require 'spec_helper'
describe Immutable::Vector do
describe '#permutation' do
let(:vector) { V[1,2,3,4] }
context 'without a block or arguments' do
it 'returns an Enumerator of all permutations' do
vector.permutation.class.should be(Enumerator)
vector.permutation.to_a.should eql(vector.to_a.permutation.to_a)
end
end
context 'without a block, but with integral argument' do
it 'returns an Enumerator of all permutations of given length' do
vector.permutation(2).class.should be(Enumerator)
vector.permutation(2).to_a.should eql(vector.to_a.permutation(2).to_a)
vector.permutation(3).class.should be(Enumerator)
vector.permutation(3).to_a.should eql(vector.to_a.permutation(3).to_a)
end
end
context 'with a block' do
it 'returns self' do
vector.permutation {}.should be(vector)
end
context 'and no argument' do
it 'yields all permutations' do
yielded = []
vector.permutation { |obj| yielded << obj }
yielded.sort.should eql([[1,2,3,4], [1,2,4,3], [1,3,2,4], [1,3,4,2],
[1,4,2,3], [1,4,3,2], [2,1,3,4], [2,1,4,3], [2,3,1,4], [2,3,4,1],
[2,4,1,3], [2,4,3,1], [3,1,2,4], [3,1,4,2], [3,2,1,4], [3,2,4,1],
[3,4,1,2], [3,4,2,1], [4,1,2,3], [4,1,3,2], [4,2,1,3], [4,2,3,1],
[4,3,1,2], [4,3,2,1]])
end
end
context 'and an integral argument' do
it 'yields all permutations of the given length' do
yielded = []
vector.permutation(2) { |obj| yielded << obj }
yielded.sort.should eql([[1,2], [1,3], [1,4], [2,1], [2,3], [2,4], [3,1],
[3,2], [3,4], [4,1], [4,2], [4,3]])
end
end
end
context 'on an empty vector' do
it 'yields the empty permutation' do
yielded = []
V.empty.permutation { |obj| yielded << obj }
yielded.should eql([[]])
end
end
context 'with an argument of zero' do
it 'yields the empty permutation' do
yielded = []
vector.permutation(0) { |obj| yielded << obj }
yielded.should eql([[]])
end
end
context 'with a length greater than the size of the vector' do
it 'yields no permutations' do
vector.permutation(5) { |obj| fail }
end
end
it 'handles duplicate elements correctly' do
V[1,2,3,1].permutation(2).sort.should eql([[1,1], [1,1], [1,2], [1,2],
[1,3], [1,3], [2,1],[2,1],[2,3], [3,1],[3,1],[3,2]])
end
it 'leaves the original unmodified' do
vector.permutation(2) {}
vector.should eql(V[1,2,3,4])
end
it 'behaves like Array#permutation' do
10.times do
array = rand(8).times.map { rand(10000) }
vector = V.new(array)
perm_size = array.size == 0 ? 0 : rand(array.size)
array.permutation(perm_size).to_a.should == vector.permutation(perm_size).to_a
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/ 0000755 0001750 0001750 00000000000 14201005456 021312 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/list/to_ary_spec.rb 0000644 0001750 0001750 00000001546 14201005456 024154 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
let(:list) { L['A', 'B', 'C', 'D'] }
describe '#to_ary' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.to_ary }.should_not raise_error
end
end
context 'enables implicit conversion to' do
it 'block parameters' do
def func(&block)
yield(list)
end
func do |a, b, *c|
expect(a).to eq('A')
expect(b).to eq('B')
expect(c).to eq(%w[C D])
end
end
it 'method arguments' do
def func(a, b, *c)
expect(a).to eq('A')
expect(b).to eq('B')
expect(c).to eq(%w[C D])
end
func(*list)
end
it 'works with splat' do
array = *list
expect(array).to eq(%w[A B C D])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/at_spec.rb 0000644 0001750 0001750 00000001252 14201005456 023255 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#at' do
context 'on a really big list' do
let(:list) { BigList }
it "doesn't run out of stack" do
-> { list.at(STACK_OVERFLOW_DEPTH) }.should_not raise_error
end
end
[
[[], 10, nil],
[['A'], 10, nil],
[%w[A B C], 0, 'A'],
[%w[A B C], 2, 'C'],
[%w[A B C], -1, 'C'],
[%w[A B C], -2, 'B'],
[%w[A B C], -4, nil]
].each do |values, number, expected|
describe "#{values.inspect} with #{number}" do
it "returns #{expected.inspect}" do
L[*values].at(number).should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/delete_at_spec.rb 0000644 0001750 0001750 00000000741 14201005456 024601 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#delete_at' do
let(:list) { L[1,2,3,4,5] }
it 'removes the element at the specified index' do
list.delete_at(0).should eql(L[2,3,4,5])
list.delete_at(2).should eql(L[1,2,4,5])
list.delete_at(-1).should eql(L[1,2,3,4])
end
it 'makes no modification if the index is out of range' do
list.delete_at(5).should eql(list)
list.delete_at(-6).should eql(list)
end
end
end
immutable-ruby-master/spec/lib/immutable/list/size_spec.rb 0000644 0001750 0001750 00000001076 14201005456 023627 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:size, :length].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.size }.should_not raise_error
end
end
[
[[], 0],
[['A'], 1],
[%w[A B C], 3],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].send(method).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/construction_spec.rb 0000644 0001750 0001750 00000006257 14201005456 025415 0 ustar boutil boutil require 'spec_helper'
describe Immutable do
describe '.list' do
context 'with no arguments' do
it 'always returns the same instance' do
L.empty.should equal(L.empty)
end
it 'returns an empty list' do
L.empty.should be_empty
end
end
context 'with a number of items' do
it 'always returns a different instance' do
L['A', 'B', 'C'].should_not equal(L['A', 'B', 'C'])
end
it 'is the same as repeatedly using #cons' do
L['A', 'B', 'C'].should eql(L.empty.cons('C').cons('B').cons('A'))
end
end
end
describe '.stream' do
context 'with no block' do
it 'returns an empty list' do
Immutable.stream.should eql(L.empty)
end
end
context 'with a block' do
let(:list) { count = 0; Immutable.stream { count += 1 }}
it 'repeatedly calls the block' do
list.take(5).should eql(L[1, 2, 3, 4, 5])
end
end
end
describe '.interval' do
context 'for numbers' do
it 'is equivalent to a list with explicit values' do
Immutable.interval(98, 102).should eql(L[98, 99, 100, 101, 102])
end
end
context 'for strings' do
it 'is equivalent to a list with explicit values' do
Immutable.interval('A', 'AA').should eql(L['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA'])
end
end
end
describe '.repeat' do
it 'returns an infinite list with specified value for each element' do
Immutable.repeat('A').take(5).should eql(L['A', 'A', 'A', 'A', 'A'])
end
end
describe '.replicate' do
it 'returns a list with the specified value repeated the specified number of times' do
Immutable.replicate(5, 'A').should eql(L['A', 'A', 'A', 'A', 'A'])
end
end
describe '.iterate' do
it 'returns an infinite list where the first item is calculated by applying the block on the initial argument, the second item by applying the function on the previous result and so on' do
Immutable.iterate(1) { |item| item * 2 }.take(10).should eql(L[1, 2, 4, 8, 16, 32, 64, 128, 256, 512])
end
end
describe '.enumerate' do
let(:enum) do
Enumerator.new do |yielder|
yielder << 1
yielder << 2
yielder << 3
raise 'list fully realized'
end
end
let(:list) { Immutable.enumerate(enum) }
it 'returns a list based on the values yielded from the enumerator' do
expect(list.take(2)).to eq L[1, 2]
end
it 'realizes values as they are needed' do
# this example shows that Lists are not as lazy as they could be
# if Lists were fully lazy, you would have to take(4) to hit the exception
expect { list.take(3).to_a }.to raise_exception(RuntimeError)
end
end
describe '[]' do
it 'takes a variable number of items and returns a list' do
list = Immutable::List[1,2,3]
list.should be_kind_of(Immutable::List)
list.size.should be(3)
list.to_a.should == [1,2,3]
end
it 'returns an empty list when called without arguments' do
L[].should be_kind_of(Immutable::List)
L[].should be_empty
end
end
end
immutable-ruby-master/spec/lib/immutable/list/drop_spec.rb 0000644 0001750 0001750 00000001267 14201005456 023623 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#drop' do
it 'is lazy' do
-> { Immutable.stream { fail }.drop(1) }.should_not raise_error
end
[
[[], 10, []],
[['A'], 10, []],
[['A'], -1, ['A']],
[%w[A B C], 0, %w[A B C]],
[%w[A B C], 2, ['C']],
].each do |values, number, expected|
context "with #{number} from #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.drop(number)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.drop(number).should == L[*expected]
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/pop_spec.rb 0000644 0001750 0001750 00000000721 14201005456 023447 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
let(:list) { L[*values] }
describe '#pop' do
let(:pop) { list.pop }
context 'with an empty list' do
let(:values) { [] }
it 'returns an empty list' do
expect(pop).to eq(L.empty)
end
end
context 'with a list with a few items' do
let(:values) { %w[a b c] }
it 'removes the last item' do
expect(pop).to eq(L['a', 'b'])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/init_spec.rb 0000644 0001750 0001750 00000001155 14201005456 023616 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#init' do
it 'is lazy' do
-> { Immutable.stream { false }.init }.should_not raise_error
end
[
[[], []],
[['A'], []],
[%w[A B C], %w[A B]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.init
list.should eql(L[*values])
end
it "returns the list without the last element: #{expected.inspect}" do
list.init.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/multithreading_spec.rb 0000644 0001750 0001750 00000002345 14201005456 025675 0 ustar boutil boutil require 'spec_helper'
require 'concurrent/atomics'
describe Immutable::List do
it 'ensures each node of a lazy list will only be realized on ONE thread, even when accessed by multiple threads' do
counter = Concurrent::Atom.new(0)
list = (1..10000).to_list.map { |x| counter.swap { |count| count + 1 }; x * 2 }
threads = 10.times.collect do
Thread.new do
node = list
node = node.tail until node.empty?
end
end
threads.each(&:join)
counter.value.should == 10000
list.sum.should == 100010000
end
it "doesn't go into an infinite loop if lazy list block raises an exception" do
list = (1..10).to_list.map { raise 'Oops!' }
threads = 10.times.collect do
Thread.new do
-> { list.head }.should raise_error(RuntimeError)
end
end
threads.each(&:join)
end
it "doesn't give horrendously bad performance if thread realizing the list sleeps" do
start = Time.now
list = (1..100).to_list.map { |x| sleep(0.001); x * 2 }
threads = 10.times.collect do
Thread.new do
node = list
node = node.tail until node.empty?
end
end
threads.each(&:join)
elapsed = Time.now - start
elapsed.should_not > 0.3
end
end
immutable-ruby-master/spec/lib/immutable/list/chunk_spec.rb 0000644 0001750 0001750 00000001152 14201005456 023760 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#chunk' do
it 'is lazy' do
-> { Immutable.stream { fail }.chunk(2) }.should_not raise_error
end
[
[[], []],
[['A'], [L['A']]],
[%w[A B C], [L['A', 'B'], L['C']]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.chunk(2)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.chunk(2).should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/reject_spec.rb 0000644 0001750 0001750 00000002304 14201005456 024124 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:reject, :delete_if].each do |method|
describe "##{method}" do
it 'is lazy' do
-> { Immutable.stream { fail }.send(method) { |item| false } }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[%w[A b C], %w[A C]],
[%w[a b c], []],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
list.send(method) { |item| item == item.downcase }.should eql(L[*expected])
end
it 'is lazy' do
count = 0
list.send(method) do |item|
count += 1
false
end
count.should <= 1
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.send(method).class.should be(Enumerator)
list.send(method).each { |item| item == item.downcase }.should eql(L[*expected])
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/flatten_spec.rb 0000644 0001750 0001750 00000001232 14201005456 024304 0 ustar boutil boutil require 'spec_helper'
describe Immutable do
describe '#flatten' do
it 'is lazy' do
-> { Immutable.stream { fail }.flatten }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[['A', L['B'], 'C'], %w[A B C]],
[[L['A'], L['B'], L['C']], %w[A B C]],
].each do |values, expected|
context "on #{values}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.flatten
list.should eql(L[*values])
end
it 'returns an empty list' do
list.flatten.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/reverse_spec.rb 0000644 0001750 0001750 00000001406 14201005456 024325 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#reverse' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.reverse }.should_not raise_error
end
end
it 'is lazy' do
-> { Immutable.stream { fail }.reverse }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[C B A]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.reverse(&:downcase)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.reverse(&:downcase).should == L[*expected]
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/tails_spec.rb 0000644 0001750 0001750 00000001163 14201005456 023766 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#tails' do
it 'is lazy' do
-> { Immutable.stream { fail }.tails }.should_not raise_error
end
[
[[], []],
[['A'], [L['A']]],
[%w[A B C], [L['A', 'B', 'C'], L['B', 'C'], L['C']]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.tails
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.tails.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/take_while_spec.rb 0000644 0001750 0001750 00000002205 14201005456 024764 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#take_while' do
it 'is lazy' do
-> { Immutable.stream { fail }.take_while { false } }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
list.take_while { |item| item < 'C' }.should eql(L[*expected])
end
it 'preserves the original' do
list.take_while { |item| item < 'C' }
list.should eql(L[*values])
end
it 'is lazy' do
count = 0
list.take_while do |item|
count += 1
true
end
count.should <= 1
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.take_while.class.should be(Enumerator)
list.take_while.each { |item| item < 'C' }.should eql(L[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/merge_spec.rb 0000644 0001750 0001750 00000002536 14201005456 023756 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
context 'without a comparator' do
context 'on an empty list' do
subject { L.empty }
it 'returns an empty list' do
subject.merge.should be_empty
end
end
context 'on a single list' do
let(:list) { L[1, 2, 3] }
subject { L[list] }
it 'returns the list' do
subject.merge.should == list
end
end
context 'with multiple lists' do
subject { L[L[3, 6, 7, 8], L[1, 2, 4, 5, 9]] }
it 'merges the lists based on natural sort order' do
subject.merge.should == L[1, 2, 3, 4, 5, 6, 7, 8, 9]
end
end
end
context 'with a comparator' do
context 'on an empty list' do
subject { L.empty }
it 'returns an empty list' do
subject.merge { |a, b| fail('should never be called') }.should be_empty
end
end
context 'on a single list' do
let(:list) { L[1, 2, 3] }
subject { L[list] }
it 'returns the list' do
subject.merge { |a, b| fail('should never be called') }.should == list
end
end
context 'with multiple lists' do
subject { L[L[8, 7, 6, 3], L[9, 5, 4, 2, 1]] }
it 'merges the lists based on the specified comparator' do
subject.merge { |a, b| b <=> a }.should == L[9, 8, 7, 6, 5, 4, 3, 2, 1]
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/transpose_spec.rb 0000644 0001750 0001750 00000001331 14201005456 024665 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#transpose' do
it 'takes a list of lists and returns a list of all the first elements, all the 2nd elements, and so on' do
L[L[1, 'a'], L[2, 'b'], L[3, 'c']].transpose.should eql(L[L[1, 2, 3], L['a', 'b', 'c']])
L[L[1, 2, 3], L['a', 'b', 'c']].transpose.should eql(L[L[1, 'a'], L[2, 'b'], L[3, 'c']])
L[].transpose.should eql(L[])
L[L[]].transpose.should eql(L[])
L[L[], L[]].transpose.should eql(L[])
L[L[0]].transpose.should eql(L[L[0]])
L[L[0], L[1]].transpose.should eql(L[L[0, 1]])
end
it 'only goes as far as the shortest list' do
L[L[1,2,3], L[2]].transpose.should eql(L[L[1,2]])
end
end
end
immutable-ruby-master/spec/lib/immutable/list/sample_spec.rb 0000644 0001750 0001750 00000000531 14201005456 024131 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#sample' do
let(:list) { (1..10).to_list }
it 'returns a randomly chosen item' do
chosen = 100.times.map { list.sample }
chosen.each { |item| list.include?(item).should == true }
list.each { |item| chosen.include?(item).should == true }
end
end
end
immutable-ruby-master/spec/lib/immutable/list/any_spec.rb 0000644 0001750 0001750 00000002326 14201005456 023443 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#any?' do
context 'on a really big list' do
let(:list) { BigList }
it "doesn't run out of stack" do
-> { list.any? { false } }.should_not raise_error
end
end
context 'when empty' do
it 'with a block returns false' do
L.empty.any? {}.should == false
end
it 'with no block returns false' do
L.empty.any?.should == false
end
end
context 'when not empty' do
context 'with a block' do
let(:list) { L['A', 'B', 'C', nil] }
['A', 'B', 'C', nil].each do |value|
it "returns true if the block ever returns true (#{value.inspect})" do
list.any? { |item| item == value }.should == true
end
end
it 'returns false if the block always returns false' do
list.any? { |item| item == 'D' }.should == false
end
end
context 'with no block' do
it 'returns true if any value is truthy' do
L[nil, false, 'A', true].any?.should == true
end
it 'returns false if all values are falsey' do
L[nil, false].any?.should == false
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/ltlt_spec.rb 0000644 0001750 0001750 00000000667 14201005456 023641 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#<<' do
it 'adds an item onto the end of a list' do
list = L['a', 'b']
(list << 'c').should eql(L['a', 'b', 'c'])
list.should eql(L['a', 'b'])
end
context 'on an empty list' do
it 'returns a list with one item' do
list = L.empty
(list << 'c').should eql(L['c'])
list.should eql(L.empty)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/minimum_spec.rb 0000644 0001750 0001750 00000001647 14201005456 024334 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#min' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.min }.should_not raise_error
end
end
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ni'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].min { |minimum, item| minimum.length <=> item.length }.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].min.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/inspect_spec.rb 0000644 0001750 0001750 00000001332 14201005456 024315 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#inspect' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.inspect }.should_not raise_error
end
end
[
[[], 'Immutable::List[]'],
[['A'], 'Immutable::List["A"]'],
[%w[A B C], 'Immutable::List["A", "B", "C"]']
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it "returns #{expected.inspect}" do
list.inspect.should == expected
end
it "returns a string which can be eval'd to get an equivalent object" do
eval(list.inspect).should eql(list)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/product_spec.rb 0000644 0001750 0001750 00000000764 14201005456 024340 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#product' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.product }.should_not raise_error
end
end
[
[[], 1],
[[2], 2],
[[1, 3, 5, 7, 11], 1155],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].product.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/flat_map_spec.rb 0000644 0001750 0001750 00000002444 14201005456 024440 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
let(:list) { L[*values] }
describe '#flat_map' do
let(:block) { ->(item) { [item, item + 1, item * item] } }
let(:flat_map) { list.flat_map(&block) }
let(:flattened_list) { L[*flattened_values] }
shared_examples 'checking flattened result' do
it 'returns the flattened values as a Immutable::List' do
expect(flat_map).to eq(flattened_list)
end
it 'returns a Immutable::List' do
expect(flat_map).to be_a(Immutable::List)
end
end
context 'with an empty list' do
let(:values) { [] }
let(:flattened_values) { [] }
include_examples 'checking flattened result'
end
context 'with a block that returns an empty list' do
let(:block) { ->(item) { [] } }
let(:values) { [1, 2, 3] }
let(:flattened_values) { [] }
include_examples 'checking flattened result'
end
context 'with a list of one item' do
let(:values) { [7] }
let(:flattened_values) { [7, 8, 49] }
include_examples 'checking flattened result'
end
context 'with a list of multiple items' do
let(:values) { [1, 2, 3] }
let(:flattened_values) { [1, 2, 1, 2, 3, 4, 3, 4, 9] }
include_examples 'checking flattened result'
end
end
end
immutable-ruby-master/spec/lib/immutable/list/find_spec.rb 0000644 0001750 0001750 00000002215 14201005456 023571 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:find, :detect].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.send(method) { false } }.should_not raise_error
end
end
[
[[], 'A', nil],
[[], nil, nil],
[['A'], 'A', 'A'],
[['A'], 'B', nil],
[['A'], nil, nil],
[['A', 'B', nil], 'A', 'A'],
[['A', 'B', nil], 'B', 'B'],
[['A', 'B', nil], nil, nil],
[['A', 'B', nil], 'C', nil],
].each do |values, item, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
list.send(method) { |x| x == item }.should == expected
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.send(method).class.should be(Enumerator)
list.send(method).each { |x| x == item }.should == expected
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/empty_spec.rb 0000644 0001750 0001750 00000001003 14201005456 024001 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#empty?' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.select(&:nil?).empty? }.should_not raise_error
end
end
[
[[], true],
[['A'], false],
[%w[A B C], false],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].empty?.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/to_a_spec.rb 0000644 0001750 0001750 00000001647 14201005456 023603 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:to_a, :entries].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.to_a }.should_not raise_error
end
end
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it "returns #{values.inspect}" do
list.send(method).should == values
end
it 'leaves the original unchanged' do
list.send(method)
list.should eql(L[*values])
end
it 'returns a mutable array' do
result = list.send(method)
expect(result.last).to_not eq('The End')
result << 'The End'
result.last.should == 'The End'
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/each_spec.rb 0000644 0001750 0001750 00000001645 14201005456 023557 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#each' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.each { |item| } }.should_not raise_error
end
end
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it 'iterates over the items in order' do
yielded = []
list.each { |item| yielded << item }
yielded.should == values
end
it 'returns nil' do
list.each { |item| item }.should be_nil
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.each.class.should be(Enumerator)
Immutable::List[*list.each].should eql(list)
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/intersperse_spec.rb 0000644 0001750 0001750 00000001207 14201005456 025214 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#intersperse' do
it 'is lazy' do
-> { Immutable.stream { fail }.intersperse('') }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], ['A', '|', 'B', '|', 'C']]
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.intersperse('|')
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.intersperse('|').should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/all_spec.rb 0000644 0001750 0001750 00000002504 14201005456 023422 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#all?' do
context 'on a really big list' do
let(:list) { BigList }
it "doesn't run out of stack" do
-> { list.all? }.should_not raise_error
end
end
context 'when empty' do
it 'with a block returns true' do
L.empty.all? {}.should == true
end
it 'with no block returns true' do
L.empty.all?.should == true
end
end
context 'when not empty' do
context 'with a block' do
let(:list) { L['A', 'B', 'C'] }
context 'if the block always returns true' do
it 'returns true' do
list.all? { |item| true }.should == true
end
end
context 'if the block ever returns false' do
it 'returns false' do
list.all? { |item| item == 'D' }.should == false
end
end
end
context 'with no block' do
context 'if all values are truthy' do
it 'returns true' do
L[true, 'A'].all?.should == true
end
end
[nil, false].each do |value|
context "if any value is #{value.inspect}" do
it 'returns false' do
L[value, true, 'A'].all?.should == false
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/last_spec.rb 0000644 0001750 0001750 00000000751 14201005456 023617 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#last' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.last }.should_not raise_error
end
end
[
[[], nil],
[['A'], 'A'],
[%w[A B C], 'C'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].last.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/delete_spec.rb 0000644 0001750 0001750 00000001064 14201005456 024114 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#delete' do
it 'removes elements that are #== to the argument' do
L[1,2,3].delete(1).should eql(L[2,3])
L[1,2,3].delete(2).should eql(L[1,3])
L[1,2,3].delete(3).should eql(L[1,2])
L[1,2,3].delete(0).should eql(L[1,2,3])
L['a','b','a','c','a','a','d'].delete('a').should eql(L['b','c','d'])
L[EqualNotEql.new, EqualNotEql.new].delete(:something).should eql(L[])
L[EqlNotEqual.new, EqlNotEqual.new].delete(:something).should_not be_empty
end
end
end
immutable-ruby-master/spec/lib/immutable/list/slice_spec.rb 0000644 0001750 0001750 00000024060 14201005456 023752 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
let(:list) { L[1,2,3,4] }
let(:big) { (1..10000).to_list }
[:slice, :[]].each do |method|
describe "##{method}" do
context 'when passed a positive integral index' do
it 'returns the element at that index' do
list.send(method, 0).should be(1)
list.send(method, 1).should be(2)
list.send(method, 2).should be(3)
list.send(method, 3).should be(4)
list.send(method, 4).should be(nil)
list.send(method, 10).should be(nil)
big.send(method, 0).should be(1)
big.send(method, 9999).should be(10000)
end
it 'leaves the original unchanged' do
list.should eql(L[1,2,3,4])
end
end
context 'when passed a negative integral index' do
it 'returns the element which is number (index.abs) counting from the end of the list' do
list.send(method, -1).should be(4)
list.send(method, -2).should be(3)
list.send(method, -3).should be(2)
list.send(method, -4).should be(1)
list.send(method, -5).should be(nil)
list.send(method, -10).should be(nil)
big.send(method, -1).should be(10000)
big.send(method, -10000).should be(1)
end
end
context 'when passed a positive integral index and count' do
it "returns 'count' elements starting from 'index'" do
list.send(method, 0, 0).should eql(L.empty)
list.send(method, 0, 1).should eql(L[1])
list.send(method, 0, 2).should eql(L[1,2])
list.send(method, 0, 4).should eql(L[1,2,3,4])
list.send(method, 0, 6).should eql(L[1,2,3,4])
list.send(method, 0, -1).should be_nil
list.send(method, 0, -2).should be_nil
list.send(method, 0, -4).should be_nil
list.send(method, 2, 0).should eql(L.empty)
list.send(method, 2, 1).should eql(L[3])
list.send(method, 2, 2).should eql(L[3,4])
list.send(method, 2, 4).should eql(L[3,4])
list.send(method, 2, -1).should be_nil
list.send(method, 4, 0).should eql(L.empty)
list.send(method, 4, 2).should eql(L.empty)
list.send(method, 4, -1).should be_nil
list.send(method, 5, 0).should be_nil
list.send(method, 5, 2).should be_nil
list.send(method, 5, -1).should be_nil
list.send(method, 6, 0).should be_nil
list.send(method, 6, 2).should be_nil
list.send(method, 6, -1).should be_nil
big.send(method, 0, 3).should eql(L[1,2,3])
big.send(method, 1023, 4).should eql(L[1024,1025,1026,1027])
big.send(method, 1024, 4).should eql(L[1025,1026,1027,1028])
end
it 'leaves the original unchanged' do
list.should eql(L[1,2,3,4])
end
end
context 'when passed a negative integral index and count' do
it "returns 'count' elements, starting from index which is number 'index.abs' counting from the end of the array" do
list.send(method, -1, 0).should eql(L.empty)
list.send(method, -1, 1).should eql(L[4])
list.send(method, -1, 2).should eql(L[4])
list.send(method, -1, -1).should be_nil
list.send(method, -2, 0).should eql(L.empty)
list.send(method, -2, 1).should eql(L[3])
list.send(method, -2, 2).should eql(L[3,4])
list.send(method, -2, 4).should eql(L[3,4])
list.send(method, -2, -1).should be_nil
list.send(method, -4, 0).should eql(L.empty)
list.send(method, -4, 1).should eql(L[1])
list.send(method, -4, 2).should eql(L[1,2])
list.send(method, -4, 4).should eql(L[1,2,3,4])
list.send(method, -4, 6).should eql(L[1,2,3,4])
list.send(method, -4, -1).should be_nil
list.send(method, -5, 0).should be_nil
list.send(method, -5, 1).should be_nil
list.send(method, -5, 10).should be_nil
list.send(method, -5, -1).should be_nil
big.send(method, -1, 1).should eql(L[10000])
big.send(method, -1, 2).should eql(L[10000])
big.send(method, -6, 2).should eql(L[9995,9996])
end
end
context 'when passed a Range' do
it 'returns the elements whose indexes are within the given Range' do
list.send(method, 0..-1).should eql(L[1,2,3,4])
list.send(method, 0..-10).should eql(L.empty)
list.send(method, 0..0).should eql(L[1])
list.send(method, 0..1).should eql(L[1,2])
list.send(method, 0..2).should eql(L[1,2,3])
list.send(method, 0..3).should eql(L[1,2,3,4])
list.send(method, 0..4).should eql(L[1,2,3,4])
list.send(method, 0..10).should eql(L[1,2,3,4])
list.send(method, 2..-10).should eql(L.empty)
list.send(method, 2..0).should eql(L.empty)
list.send(method, 2..2).should eql(L[3])
list.send(method, 2..3).should eql(L[3,4])
list.send(method, 2..4).should eql(L[3,4])
list.send(method, 3..0).should eql(L.empty)
list.send(method, 3..3).should eql(L[4])
list.send(method, 3..4).should eql(L[4])
list.send(method, 4..0).should eql(L.empty)
list.send(method, 4..4).should eql(L.empty)
list.send(method, 4..5).should eql(L.empty)
list.send(method, 5..0).should be_nil
list.send(method, 5..5).should be_nil
list.send(method, 5..6).should be_nil
big.send(method, 159..162).should eql(L[160,161,162,163])
big.send(method, 160..162).should eql(L[161,162,163])
big.send(method, 161..162).should eql(L[162,163])
big.send(method, 9999..10100).should eql(L[10000])
big.send(method, 10000..10100).should eql(L.empty)
big.send(method, 10001..10100).should be_nil
list.send(method, 0...-1).should eql(L[1,2,3])
list.send(method, 0...-10).should eql(L.empty)
list.send(method, 0...0).should eql(L.empty)
list.send(method, 0...1).should eql(L[1])
list.send(method, 0...2).should eql(L[1,2])
list.send(method, 0...3).should eql(L[1,2,3])
list.send(method, 0...4).should eql(L[1,2,3,4])
list.send(method, 0...10).should eql(L[1,2,3,4])
list.send(method, 2...-10).should eql(L.empty)
list.send(method, 2...0).should eql(L.empty)
list.send(method, 2...2).should eql(L.empty)
list.send(method, 2...3).should eql(L[3])
list.send(method, 2...4).should eql(L[3,4])
list.send(method, 3...0).should eql(L.empty)
list.send(method, 3...3).should eql(L.empty)
list.send(method, 3...4).should eql(L[4])
list.send(method, 4...0).should eql(L.empty)
list.send(method, 4...4).should eql(L.empty)
list.send(method, 4...5).should eql(L.empty)
list.send(method, 5...0).should be_nil
list.send(method, 5...5).should be_nil
list.send(method, 5...6).should be_nil
big.send(method, 159...162).should eql(L[160,161,162])
big.send(method, 160...162).should eql(L[161,162])
big.send(method, 161...162).should eql(L[162])
big.send(method, 9999...10100).should eql(L[10000])
big.send(method, 10000...10100).should eql(L.empty)
big.send(method, 10001...10100).should be_nil
list.send(method, -1..-1).should eql(L[4])
list.send(method, -1...-1).should eql(L.empty)
list.send(method, -1..3).should eql(L[4])
list.send(method, -1...3).should eql(L.empty)
list.send(method, -1..4).should eql(L[4])
list.send(method, -1...4).should eql(L[4])
list.send(method, -1..10).should eql(L[4])
list.send(method, -1...10).should eql(L[4])
list.send(method, -1..0).should eql(L.empty)
list.send(method, -1..-4).should eql(L.empty)
list.send(method, -1...-4).should eql(L.empty)
list.send(method, -1..-6).should eql(L.empty)
list.send(method, -1...-6).should eql(L.empty)
list.send(method, -2..-2).should eql(L[3])
list.send(method, -2...-2).should eql(L.empty)
list.send(method, -2..-1).should eql(L[3,4])
list.send(method, -2...-1).should eql(L[3])
list.send(method, -2..10).should eql(L[3,4])
list.send(method, -2...10).should eql(L[3,4])
big.send(method, -1..-1).should eql(L[10000])
big.send(method, -1..9999).should eql(L[10000])
big.send(method, -1...9999).should eql(L.empty)
big.send(method, -2...9999).should eql(L[9999])
big.send(method, -2..-1).should eql(L[9999,10000])
list.send(method, -4..-4).should eql(L[1])
list.send(method, -4..-2).should eql(L[1,2,3])
list.send(method, -4...-2).should eql(L[1,2])
list.send(method, -4..-1).should eql(L[1,2,3,4])
list.send(method, -4...-1).should eql(L[1,2,3])
list.send(method, -4..3).should eql(L[1,2,3,4])
list.send(method, -4...3).should eql(L[1,2,3])
list.send(method, -4..4).should eql(L[1,2,3,4])
list.send(method, -4...4).should eql(L[1,2,3,4])
list.send(method, -4..0).should eql(L[1])
list.send(method, -4...0).should eql(L.empty)
list.send(method, -4..1).should eql(L[1,2])
list.send(method, -4...1).should eql(L[1])
list.send(method, -5..-5).should be_nil
list.send(method, -5...-5).should be_nil
list.send(method, -5..-4).should be_nil
list.send(method, -5..-1).should be_nil
list.send(method, -5..10).should be_nil
big.send(method, -10001..-1).should be_nil
end
it 'leaves the original unchanged' do
list.should eql(L[1,2,3,4])
end
end
end
context 'when passed a subclass of Range' do
it 'works the same as with a Range' do
subclass = Class.new(Range)
list.send(method, subclass.new(1,2)).should eql(L[2,3])
list.send(method, subclass.new(-3,-1,true)).should eql(L[2,3])
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/join_spec.rb 0000644 0001750 0001750 00000002664 14201005456 023620 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#join' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.join }.should_not raise_error
end
end
context 'with a separator' do
[
[[], ''],
[['A'], 'A'],
[%w[A B C], 'A|B|C']
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.join('|')
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.join('|').should == expected
end
end
end
end
context 'without a separator' do
[
[[], ''],
[['A'], 'A'],
[%w[A B C], 'ABC']
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.join
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.join.should == expected
end
end
end
end
context 'without a separator (with global default separator set)' do
before { $, = '**' }
let(:list) { L['A', 'B', 'C'] }
after { $, = nil }
it 'uses the default global separator' do
list.join.should == 'A**B**C'
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/split_at_spec.rb 0000644 0001750 0001750 00000002141 14201005456 024466 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#split_at' do
it 'is lazy' do
-> { Immutable.stream { fail }.split_at(1) }.should_not raise_error
end
[
[[], [], []],
[[1], [1], []],
[[1, 2], [1, 2], []],
[[1, 2, 3], [1, 2], [3]],
[[1, 2, 3, 4], [1, 2], [3, 4]],
].each do |values, expected_prefix, expected_remainder|
context "on #{values.inspect}" do
let(:list) { L[*values] }
let(:result) { list.split_at(2) }
let(:prefix) { result.first }
let(:remainder) { result.last }
it 'preserves the original' do
result
list.should eql(L[*values])
end
it 'returns a frozen array with two items' do
result.class.should be(Array)
result.should be_frozen
result.size.should be(2)
end
it 'correctly identifies the matches' do
prefix.should eql(L[*expected_prefix])
end
it 'correctly identifies the remainder' do
remainder.should eql(L[*expected_remainder])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/each_with_index_spec.rb 0000644 0001750 0001750 00000001420 14201005456 025770 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#each_with_index' do
context 'with no block' do
let(:list) { L['A', 'B', 'C'] }
it 'returns an Enumerator' do
list.each_with_index.class.should be(Enumerator)
list.each_with_index.to_a.should == [['A', 0], ['B', 1], ['C', 2]]
end
end
context 'with a block' do
let(:list) { Immutable.interval(1, 1025) }
it 'returns self' do
list.each_with_index { |item, index| item }.should be(list)
end
it 'iterates over the items in order, yielding item and index' do
yielded = []
list.each_with_index { |item, index| yielded << [item, index] }
yielded.should == (1..list.size).zip(0..list.size.pred)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/add_spec.rb 0000644 0001750 0001750 00000001131 14201005456 023375 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#add' do
[
[[], 'A', ['A']],
[['A'], 'B', %w[B A]],
[['A'], 'A', %w[A A]],
[%w[A B C], 'D', %w[D A B C]],
].each do |values, new_value, expected|
context "on #{values.inspect} with #{new_value.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.add(new_value)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.add(new_value).should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/find_all_spec.rb 0000644 0001750 0001750 00000003257 14201005456 024430 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
let(:list) { L[*values] }
let(:found_list) { L[*found_values] }
describe '#find_all' do
it 'is lazy' do
expect { Immutable.stream { fail }.find_all { |item| false } }.to_not raise_error
end
shared_examples 'checking values' do
context 'with a block' do
let(:find_all) { list.find_all { |item| item == item.upcase } }
it 'preserves the original' do
expect(list).to eq(L[*values])
end
it 'returns the found list' do
expect(find_all).to eq(found_list)
end
end
context 'without a block' do
let(:find_all) { list.find_all }
it 'returns an Enumerator' do
expect(find_all.class).to be(Enumerator)
expect(find_all.each { |item| item == item.upcase }).to eq(found_list)
end
end
end
context 'with an empty array' do
let(:values) { [] }
let(:found_values) { [] }
include_examples 'checking values'
end
context 'with a single item array' do
let(:values) { ['A'] }
let(:found_values) { ['A'] }
include_examples 'checking values'
end
context 'with a multi-item array' do
let(:values) { %w[A B] }
let(:found_values) { %w[A B] }
include_examples 'checking values'
end
context 'with a multi-item single find_allable array' do
let(:values) { %w[A b] }
let(:found_values) { ['A'] }
include_examples 'checking values'
end
context 'with a multi-item multi-find_allable array' do
let(:values) { %w[a b] }
let(:found_values) { [] }
include_examples 'checking values'
end
end
end
immutable-ruby-master/spec/lib/immutable/list/head_spec.rb 0000644 0001750 0001750 00000000646 14201005456 023560 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:head, :first].each do |method|
describe "##{method}" do
[
[[], nil],
[['A'], 'A'],
[%w[A B C], 'A'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].send(method).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/grep_spec.rb 0000644 0001750 0001750 00000002126 14201005456 023607 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#grep' do
it 'is lazy' do
-> { Immutable.stream { fail }.grep(Object) { |item| item } }.should_not raise_error
end
context 'without a block' do
[
[[], []],
[['A'], ['A']],
[[1], []],
[['A', 2, 'C'], %w[A C]],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].grep(String).should eql(L[*expected])
end
end
end
end
context 'with a block' do
[
[[], []],
[['A'], ['a']],
[[1], []],
[['A', 2, 'C'], %w[a c]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.grep(String, &:downcase)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.grep(String, &:downcase).should eql(L[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/take_spec.rb 0000644 0001750 0001750 00000001257 14201005456 023602 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#take' do
it 'is lazy' do
-> { Immutable.stream { fail }.take(1) }.should_not raise_error
end
[
[[], 10, []],
[['A'], 10, ['A']],
[['A'], -1, []],
[%w[A B C], 0, []],
[%w[A B C], 2, %w[A B]],
].each do |values, number, expected|
context "#{number} from #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.take(number)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.take(number).should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/find_index_spec.rb 0000644 0001750 0001750 00000001674 14201005456 024770 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:find_index, :index].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.send(method) { |item| false } }.should_not raise_error
end
end
[
[[], 'A', nil],
[[], nil, nil],
[['A'], 'A', 0],
[['A'], 'B', nil],
[['A'], nil, nil],
[['A', 'B', nil], 'A', 0],
[['A', 'B', nil], 'B', 1],
[['A', 'B', nil], nil, 2],
[['A', 'B', nil], 'C', nil],
[[2], 2, 0],
[[2], 2.0, 0],
[[2.0], 2.0, 0],
[[2.0], 2, 0],
].each do |values, item, expected|
context "looking for #{item.inspect} in #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].send(method) { |x| x == item }.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/select_spec.rb 0000644 0001750 0001750 00000003267 14201005456 024140 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
let(:list) { L[*values] }
let(:selected_list) { L[*selected_values] }
describe '#select' do
it 'is lazy' do
expect { Immutable.stream { fail }.select { |item| false } }.to_not raise_error
end
shared_examples 'checking values' do
context 'with a block' do
let(:select) { list.select { |item| item == item.upcase } }
it 'preserves the original' do
expect(list).to eq(L[*values])
end
it 'returns the selected list' do
expect(select).to eq(selected_list)
end
end
context 'without a block' do
let(:select) { list.select }
it 'returns an Enumerator' do
expect(select.class).to be(Enumerator)
expect(select.each { |item| item == item.upcase }).to eq(selected_list)
end
end
end
context 'with an empty array' do
let(:values) { [] }
let(:selected_values) { [] }
include_examples 'checking values'
end
context 'with a single item array' do
let(:values) { ['A'] }
let(:selected_values) { ['A'] }
include_examples 'checking values'
end
context 'with a multi-item array' do
let(:values) { %w[A B] }
let(:selected_values) { %w[A B] }
include_examples 'checking values'
end
context 'with a multi-item single selectable array' do
let(:values) { %w[A b] }
let(:selected_values) { ['A'] }
include_examples 'checking values'
end
context 'with a multi-item multi-selectable array' do
let(:values) { %w[a b] }
let(:selected_values) { [] }
include_examples 'checking values'
end
end
end
immutable-ruby-master/spec/lib/immutable/list/uniq_spec.rb 0000644 0001750 0001750 00000001452 14201005456 023627 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#uniq' do
it 'is lazy' do
-> { Immutable.stream { fail }.uniq }.should_not raise_error
end
context 'when passed a block' do
it 'uses the block to identify duplicates' do
L['a', 'A', 'b'].uniq(&:upcase).should eql(Immutable::List['a', 'b'])
end
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[%w[A B A C C], %w[A B C]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.uniq
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.uniq.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/sorting_spec.rb 0000644 0001750 0001750 00000002325 14201005456 024340 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[
[:sort, ->(left, right) { left.length <=> right.length }],
[:sort_by, ->(item) { item.length }],
].each do |method, comparator|
describe "##{method}" do
it 'is lazy' do
-> { Immutable.stream { fail }.send(method, &comparator) }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[Ichi Ni San], %w[Ni San Ichi]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it 'preserves the original' do
list.send(method, &comparator)
list.should == L[*values]
end
it "returns #{expected.inspect}" do
list.send(method, &comparator).should == L[*expected]
end
end
context 'without a block' do
it 'preserves the original' do
list.send(method)
list.should eql(L[*values])
end
it "returns #{expected.sort.inspect}" do
list.send(method).should == L[*expected.sort]
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/eql_spec.rb 0000644 0001750 0001750 00000004065 14201005456 023437 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#eql?' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.eql?(Immutable.interval(0, STACK_OVERFLOW_DEPTH)) }.should_not raise_error
end
end
end
shared_examples 'equal using eql?' do |a, b|
specify "#{a.inspect} should eql? #{b.inspect}" do
expect(a).to eql b
end
specify "#{a.inspect} should == #{b.inspect}" do
expect(a).to eq b
end
end
shared_examples 'not equal using eql?' do |a, b|
specify "#{a.inspect} should not eql? #{b.inspect}" do
expect(a).to_not eql b
end
end
shared_examples 'equal using ==' do |a, b|
specify "#{a.inspect} should == #{b.inspect}" do
expect(a).to eq b
end
end
shared_examples 'not equal using ==' do |a, b|
specify "#{a.inspect} should not == #{b.inspect}" do
expect(a).to_not eq b
end
end
include_examples 'equal using ==' , L['A', 'B', 'C'], %w[A B C]
include_examples 'not equal using eql?' , L['A', 'B', 'C'], %w[A B C]
include_examples 'not equal using ==' , L['A', 'B', 'C'], Object.new
include_examples 'not equal using eql?' , L['A', 'B', 'C'], Object.new
include_examples 'equal using ==' , L.empty, []
include_examples 'not equal using eql?' , L.empty, []
include_examples 'equal using eql?' , L.empty, L.empty
include_examples 'not equal using eql?' , L.empty, L[nil]
include_examples 'not equal using eql?' , L['A'], L.empty
include_examples 'equal using eql?' , L['A'], L['A']
include_examples 'not equal using eql?' , L['A'], L['B']
include_examples 'not equal using eql?' , L['A', 'B'], L['A']
include_examples 'equal using eql?' , L['A', 'B', 'C'], L['A', 'B', 'C']
include_examples 'not equal using eql?' , L['C', 'A', 'B'], L['A', 'B', 'C']
include_examples 'equal using ==' , L['A'], ['A']
include_examples 'equal using ==' , ['A'], L['A']
include_examples 'not equal using eql?' , L['A'], ['A']
include_examples 'not equal using eql?' , ['A'], L['A']
end
immutable-ruby-master/spec/lib/immutable/list/rotate_spec.rb 0000644 0001750 0001750 00000002042 14201005456 024145 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#rotate' do
let(:list) { L[1,2,3,4,5] }
context 'when passed no argument' do
it 'returns a new list with the first element moved to the end' do
list.rotate.should eql(L[2,3,4,5,1])
end
end
context 'with an integral argument n' do
it 'returns a new list with the first (n % size) elements moved to the end' do
list.rotate(2).should eql(L[3,4,5,1,2])
list.rotate(3).should eql(L[4,5,1,2,3])
list.rotate(4).should eql(L[5,1,2,3,4])
list.rotate(5).should eql(L[1,2,3,4,5])
list.rotate(-1).should eql(L[5,1,2,3,4])
end
end
context 'with a non-numeric argument' do
it 'raises a TypeError' do
-> { list.rotate('hello') }.should raise_error(TypeError)
end
end
context 'with an argument of zero (or one evenly divisible by list length)' do
it 'it returns self' do
list.rotate(0).should be(list)
list.rotate(5).should be(list)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/include_spec.rb 0000644 0001750 0001750 00000001652 14201005456 024300 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:include?, :member?].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.send(method, nil) }.should_not raise_error
end
end
[
[[], 'A', false],
[[], nil, false],
[['A'], 'A', true],
[['A'], 'B', false],
[['A'], nil, false],
[['A', 'B', nil], 'A', true],
[['A', 'B', nil], 'B', true],
[['A', 'B', nil], nil, true],
[['A', 'B', nil], 'C', false],
[[2], 2, true],
[[2], 2.0, true],
[[2.0], 2.0, true],
[[2.0], 2, true],
].each do |values, item, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].send(method, item).should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/group_by_spec.rb 0000644 0001750 0001750 00000002144 14201005456 024500 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:group_by, :group].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.send(method) }.should_not raise_error
end
end
context 'with a block' do
[
[[], []],
[[1], [true => L[1]]],
[[1, 2, 3, 4], [true => L[3, 1], false => L[4, 2]]],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].send(method, &:odd?).should eql(H[*expected])
end
end
end
end
context 'without a block' do
[
[[], []],
[[1], [1 => L[1]]],
[[1, 2, 3, 4], [1 => L[1], 2 => L[2], 3 => L[3], 4 => L[4]]],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].send(method).should eql(H[*expected])
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/clear_spec.rb 0000644 0001750 0001750 00000000673 14201005456 023745 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#clear' do
[
[],
['A'],
%w[A B C],
].each do |values|
describe "on #{values}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.clear
list.should eql(L[*values])
end
it 'returns an empty list' do
list.clear.should equal(L.empty)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/break_spec.rb 0000644 0001750 0001750 00000003502 14201005456 023735 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#break' do
it 'is lazy' do
-> { Immutable.stream { fail }.break { |item| false } }.should_not raise_error
end
[
[[], [], []],
[[1], [1], []],
[[1, 2], [1, 2], []],
[[1, 2, 3], [1, 2], [3]],
[[1, 2, 3, 4], [1, 2], [3, 4]],
[[2, 3, 4], [2], [3, 4]],
[[3, 4], [], [3, 4]],
[[4], [], [4]],
].each do |values, expected_prefix, expected_remainder|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
let(:result) { list.break { |item| item > 2 }}
let(:prefix) { result.first }
let(:remainder) { result.last }
it 'preserves the original' do
result
list.should eql(L[*values])
end
it 'returns a frozen array with two items' do
result.class.should be(Array)
result.should be_frozen
result.size.should be(2)
end
it 'correctly identifies the prefix' do
prefix.should eql(L[*expected_prefix])
end
it 'correctly identifies the remainder' do
remainder.should eql(L[*expected_remainder])
end
end
context 'without a block' do
let(:result) { list.break }
let(:prefix) { result.first }
let(:remainder) { result.last }
it 'returns a frozen array with two items' do
result.class.should be(Array)
result.should be_frozen
result.size.should be(2)
end
it 'returns self as the prefix' do
prefix.should equal(list)
end
it 'leaves the remainder empty' do
remainder.should be_empty
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/tail_spec.rb 0000644 0001750 0001750 00000001213 14201005456 023577 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#tail' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.select(&:nil?).tail }.should_not raise_error
end
end
[
[[], []],
[['A'], []],
[%w[A B C], %w[B C]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.tail
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.tail.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/merge_by_spec.rb 0000644 0001750 0001750 00000002334 14201005456 024444 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
context 'without a comparator' do
context 'on an empty list' do
it 'returns an empty list' do
L.empty.merge_by.should be_empty
end
end
context 'on a single list' do
let(:list) { L[1, 2, 3] }
it 'returns the list' do
L[list].merge_by.should eql(list)
end
end
context 'with multiple lists' do
subject { L[L[3, 6, 7, 8], L[1, 2, 4, 5, 9]] }
it 'merges the lists based on natural sort order' do
subject.merge_by.should == L[1, 2, 3, 4, 5, 6, 7, 8, 9]
end
end
end
context 'with a comparator' do
context 'on an empty list' do
it 'returns an empty list' do
L.empty.merge_by { |item| fail('should never be called') }.should be_empty
end
end
context 'on a single list' do
let(:list) { L[1, 2, 3] }
it 'returns the list' do
L[list].merge_by(&:-@).should == L[1, 2, 3]
end
end
context 'with multiple lists' do
subject { L[L[8, 7, 6, 3], L[9, 5, 4, 2, 1]] }
it 'merges the lists based on the specified transformer' do
subject.merge_by(&:-@).should == L[9, 8, 7, 6, 5, 4, 3, 2, 1]
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/span_spec.rb 0000644 0001750 0001750 00000004700 14201005456 023613 0 ustar boutil boutil require 'spec_helper'
describe 'List#span' do
it 'is lazy' do
-> { Immutable.stream { |item| fail }.span { true } }.should_not raise_error
end
describe <<-DESC do
given a predicate (in the form of a block), splits the list into two lists
(returned as an array) such that elements in the first list (the prefix) are
taken from the head of the list while the predicate is satisfied, and elements
in the second list (the remainder) are the remaining elements from the list
once the predicate is not satisfied. For example:
DESC
[
[[], [], []],
[[1], [1], []],
[[1, 2], [1, 2], []],
[[1, 2, 3], [1, 2], [3]],
[[1, 2, 3, 4], [1, 2], [3, 4]],
[[2, 3, 4], [2], [3, 4]],
[[3, 4], [], [3, 4]],
[[4], [], [4]],
].each do |values, expected_prefix, expected_remainder|
context "given the list #{values.inspect}" do
let(:list) { L[*values] }
context 'and a predicate that returns true for values <= 2' do
let(:result) { list.span { |item| item <= 2 }}
let(:prefix) { result.first }
let(:remainder) { result.last }
it 'preserves the original' do
result
list.should eql(L[*values])
end
it "returns the prefix as #{expected_prefix.inspect}" do
prefix.should eql(L[*expected_prefix])
end
it "returns the remainder as #{expected_remainder.inspect}" do
remainder.should eql(L[*expected_remainder])
end
it 'calls the block only once for each element' do
count = 0
result = list.span { |item| count += 1; item <= 2 }
# force realization of lazy lists
result.first.size.should == expected_prefix.size
result.last.size.should == expected_remainder.size
# it may not need to call the block on every element, just up to the
# point where the block first returns a false value
count.should <= values.size
end
end
context 'without a predicate' do
it 'returns a frozen array' do
list.span.class.should be(Array)
list.span.should be_frozen
end
it 'returns self as the prefix' do
list.span.first.should equal(list)
end
it 'returns an empty list as the remainder' do
list.span.last.should be_empty
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/to_list_spec.rb 0000644 0001750 0001750 00000000513 14201005456 024325 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#to_list' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'returns self' do
list.to_list.should equal(list)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/union_spec.rb 0000644 0001750 0001750 00000001467 14201005456 024011 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:union, :|].each do |method|
describe "##{method}" do
it 'is lazy' do
-> { Immutable.stream { fail }.union(Immutable.stream { fail }) }.should_not raise_error
end
[
[[], [], []],
[['A'], [], ['A']],
[%w[A B C], [], %w[A B C]],
[%w[A A], ['A'], ['A']],
].each do |a, b, expected|
context "returns #{expected.inspect}" do
let(:list_a) { L[*a] }
let(:list_b) { L[*b] }
it "for #{a.inspect} and #{b.inspect}" do
list_a.send(method, list_b).should eql(L[*expected])
end
it "for #{b.inspect} and #{a.inspect}" do
list_b.send(method, list_a).should eql(L[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/compact_spec.rb 0000644 0001750 0001750 00000001375 14201005456 024305 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#compact' do
it 'is lazy' do
-> { Immutable.stream { fail }.compact }.should_not raise_error
end
[
[[], []],
[['A'], ['A']],
[%w[A B C], %w[A B C]],
[[nil], []],
[[nil, 'B'], ['B']],
[['A', nil], ['A']],
[[nil, nil], []],
[['A', nil, 'C'], %w[A C]],
[[nil, 'B', nil], ['B']],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.compact
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.compact.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/zip_spec.rb 0000644 0001750 0001750 00000001214 14201005456 023451 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#zip' do
it 'is lazy' do
-> { Immutable.stream { fail }.zip(Immutable.stream { fail }) }.should_not raise_error
end
[
[[], [], []],
[['A'], ['aye'], [L['A', 'aye']]],
[['A'], [], [L['A', nil]]],
[[], ['A'], [L[nil, 'A']]],
[%w[A B C], %w[aye bee see], [L['A', 'aye'], L['B', 'bee'], L['C', 'see']]],
].each do |left, right, expected|
context "on #{left.inspect} and #{right.inspect}" do
it "returns #{expected.inspect}" do
L[*left].zip(L[*right]).should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/none_spec.rb 0000644 0001750 0001750 00000002300 14201005456 023603 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#none?' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.none? { false } }.should_not raise_error
end
end
context 'when empty' do
it 'with a block returns true' do
L.empty.none? {}.should == true
end
it 'with no block returns true' do
L.empty.none?.should == true
end
end
context 'when not empty' do
context 'with a block' do
let(:list) { L['A', 'B', 'C', nil] }
['A', 'B', 'C', nil].each do |value|
it "returns false if the block ever returns true (#{value.inspect})" do
list.none? { |item| item == value }.should == false
end
end
it 'returns true if the block always returns false' do
list.none? { |item| item == 'D' }.should == true
end
end
context 'with no block' do
it 'returns false if any value is truthy' do
L[nil, false, true, 'A'].none?.should == false
end
it 'returns true if all values are falsey' do
L[nil, false].none?.should == true
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/drop_while_spec.rb 0000644 0001750 0001750 00000001750 14201005456 025010 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#drop_while' do
it 'is lazy' do
-> { Immutable.stream { fail }.drop_while { false } }.should_not raise_error
end
[
[[], []],
[['A'], []],
[%w[A B C], ['C']],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it 'preserves the original' do
list.drop_while { |item| item < 'C' }
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.drop_while { |item| item < 'C' }.should eql(L[*expected])
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.drop_while.class.should be(Enumerator)
list.drop_while.each { false }.should eql(list)
list.drop_while.each { true }.should be_empty
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/fill_spec.rb 0000644 0001750 0001750 00000002536 14201005456 023605 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#fill' do
let(:list) { L[1, 2, 3, 4, 5, 6] }
it 'can replace a range of items at the beginning of a list' do
list.fill(:a, 0, 3).should eql(L[:a, :a, :a, 4, 5, 6])
end
it 'can replace a range of items in the middle of a list' do
list.fill(:a, 3, 2).should eql(L[1, 2, 3, :a, :a, 6])
end
it 'can replace a range of items at the end of a list' do
list.fill(:a, 4, 2).should eql(L[1, 2, 3, 4, :a, :a])
end
it 'can replace all the items in a list' do
list.fill(:a, 0, 6).should eql(L[:a, :a, :a, :a, :a, :a])
end
it 'can fill past the end of the list' do
list.fill(:a, 3, 6).should eql(L[1, 2, 3, :a, :a, :a, :a, :a, :a])
end
context 'with 1 argument' do
it 'replaces all the items in the list by default' do
list.fill(:a).should eql(L[:a, :a, :a, :a, :a, :a])
end
end
context 'with 2 arguments' do
it 'replaces up to the end of the list by default' do
list.fill(:a, 4).should eql(L[1, 2, 3, 4, :a, :a])
end
end
context 'when index and length are 0' do
it 'leaves the list unmodified' do
list.fill(:a, 0, 0).should eql(list)
end
end
it 'is lazy' do
-> { Immutable.stream { fail }.fill(:a, 0, 1) }.should_not raise_error
end
end
end
immutable-ruby-master/spec/lib/immutable/list/maximum_spec.rb 0000644 0001750 0001750 00000001650 14201005456 024330 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#max' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.max }.should_not raise_error
end
end
context 'with a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'Ichi'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].max { |maximum, item| maximum.length <=> item.length }.should == expected
end
end
end
end
context 'without a block' do
[
[[], nil],
[['A'], 'A'],
[%w[Ichi Ni San], 'San'],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].max.should == expected
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/cons_spec.rb 0000644 0001750 0001750 00000001134 14201005456 023612 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#cons' do
[
[[], 'A', ['A']],
[['A'], 'B', %w[B A]],
[['A'], 'A', %w[A A]],
[%w[A B C], 'D', %w[D A B C]],
].each do |values, new_value, expected|
context "on #{values.inspect} with #{new_value.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.cons(new_value)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.cons(new_value).should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/cadr_spec.rb 0000644 0001750 0001750 00000001634 14201005456 023566 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[
[[], :car, nil],
[['A'], :car, 'A'],
[%w[A B C], :car, 'A'],
[%w[A B C], :cadr, 'B'],
[%w[A B C], :caddr, 'C'],
[%w[A B C], :cadddr, nil],
[%w[A B C], :caddddr, nil],
[[], :cdr, L.empty],
[['A'], :cdr, L.empty],
[%w[A B C], :cdr, L['B', 'C']],
[%w[A B C], :cddr, L['C']],
[%w[A B C], :cdddr, L.empty],
[%w[A B C], :cddddr, L.empty],
].each do |values, method, expected|
describe "##{method}" do
it 'is responded to' do
L.empty.respond_to?(method).should == true
end
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.send(method)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.send(method).should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/insert_spec.rb 0000644 0001750 0001750 00000002417 14201005456 024161 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#insert' do
let(:original) { L[1, 2, 3] }
it 'can add items at the beginning of a list' do
list = original.insert(0, :a, :b)
list.size.should be(5)
list.at(0).should be(:a)
list.at(2).should be(1)
end
it 'can add items in the middle of a list' do
list = original.insert(1, :a, :b, :c)
list.size.should be(6)
list.to_a.should == [1, :a, :b, :c, 2, 3]
end
it 'can add items at the end of a list' do
list = original.insert(3, :a, :b, :c)
list.size.should be(6)
list.to_a.should == [1, 2, 3, :a, :b, :c]
end
it 'can add items past the end of a list' do
list = original.insert(6, :a, :b)
list.size.should be(8)
list.to_a.should == [1, 2, 3, nil, nil, nil, :a, :b]
end
it 'accepts a negative index, which counts back from the end of the list' do
list = original.insert(-2, :a)
list.size.should be(4)
list.to_a.should == [1, :a, 2, 3]
end
it 'raises IndexError if a negative index is too great' do
expect { original.insert(-4, :a) }.to raise_error(IndexError)
end
it 'is lazy' do
-> { Immutable.stream { fail }.insert(0, :a) }.should_not raise_error
end
end
end
immutable-ruby-master/spec/lib/immutable/list/compare_spec.rb 0000644 0001750 0001750 00000001221 14201005456 024273 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#<=>' do
[
[[], [1]],
[[1], [2]],
[[1], [1, 2]],
[[2, 3, 4], [3, 4, 5]]
].each do |items1, items2|
context "with #{items1} and #{items2}" do
it 'returns -1' do
(L[*items1] <=> L[*items2]).should be(-1)
end
end
context "with #{items2} and #{items1}" do
it 'returns 1' do
(L[*items2] <=> L[*items1]).should be(1)
end
end
context "with #{items1} and #{items1}" do
it 'returns 0' do
(L[*items1] <=> L[*items1]).should be(0)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/append_spec.rb 0000644 0001750 0001750 00000001773 14201005456 024130 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:append, :concat, :+].each do |method|
describe "##{method}" do
it 'is lazy' do
-> { Immutable.stream { fail }.append(Immutable.stream { fail }) }.should_not raise_error
end
[
[[], [], []],
[['A'], [], ['A']],
[[], ['A'], ['A']],
[%w[A B], %w[C D], %w[A B C D]],
].each do |left_values, right_values, expected|
context "on #{left_values.inspect} and #{right_values.inspect}" do
let(:left) { L[*left_values] }
let(:right) { L[*right_values] }
let(:result) { left.append(right) }
it 'preserves the left' do
result
left.should eql(L[*left_values])
end
it 'preserves the right' do
result
right.should eql(L[*right_values])
end
it "returns #{expected.inspect}" do
result.should eql(L[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/combination_spec.rb 0000644 0001750 0001750 00000001757 14201005456 025165 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#combination' do
it 'is lazy' do
-> { Immutable.stream { fail }.combination(2) }.should_not raise_error
end
[
[%w[A B C D], 1, [L['A'], L['B'], L['C'], L['D']]],
[%w[A B C D], 2, [L['A','B'], L['A','C'], L['A','D'], L['B','C'], L['B','D'], L['C','D']]],
[%w[A B C D], 3, [L['A','B','C'], L['A','B','D'], L['A','C','D'], L['B','C','D']]],
[%w[A B C D], 4, [L['A', 'B', 'C', 'D']]],
[%w[A B C D], 0, [EmptyList]],
[%w[A B C D], 5, []],
[[], 0, [EmptyList]],
[[], 1, []],
].each do |values, number, expected|
context "on #{values.inspect} in groups of #{number}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.combination(number)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.combination(number).should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/inits_spec.rb 0000644 0001750 0001750 00000001163 14201005456 024000 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#inits' do
it 'is lazy' do
-> { Immutable.stream { fail }.inits }.should_not raise_error
end
[
[[], []],
[['A'], [L['A']]],
[%w[A B C], [L['A'], L['A', 'B'], L['A', 'B', 'C']]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'preserves the original' do
list.inits
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.inits.should eql(L[*expected])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/subsequences_spec.rb 0000644 0001750 0001750 00000001401 14201005456 025352 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#subsequences' do
let(:list) { L[1,2,3,4,5] }
it 'yields all sublists with 1 or more consecutive items' do
result = []
list.subsequences { |l| result << l }
result.size.should == (5 + 4 + 3 + 2 + 1)
result.sort.should == [[1], [1,2], [1,2,3], [1,2,3,4], [1,2,3,4,5],
[2], [2,3], [2,3,4], [2,3,4,5], [3], [3,4], [3,4,5], [4], [4,5], [5]]
end
context 'with no block' do
it 'returns an Enumerator' do
list.subsequences.class.should be(Enumerator)
list.subsequences.to_a.sort.should == [[1], [1,2], [1,2,3], [1,2,3,4], [1,2,3,4,5],
[2], [2,3], [2,3,4], [2,3,4,5], [3], [3,4], [3,4,5], [4], [4,5], [5]]
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/index_spec.rb 0000644 0001750 0001750 00000001453 14201005456 023763 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#index' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.index(nil) }.should_not raise_error
end
end
[
[[], 'A', nil],
[[], nil, nil],
[['A'], 'A', 0],
[['A'], 'B', nil],
[['A'], nil, nil],
[['A', 'B', nil], 'A', 0],
[['A', 'B', nil], 'B', 1],
[['A', 'B', nil], nil, 2],
[['A', 'B', nil], 'C', nil],
[[2], 2, 0],
[[2], 2.0, 0],
[[2.0], 2.0, 0],
[[2.0], 2, 0],
].each do |values, item, expected|
context "looking for #{item.inspect} in #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].index(item).should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/one_spec.rb 0000644 0001750 0001750 00000002364 14201005456 023437 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#one?' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.one? { false } }.should_not raise_error
end
end
context 'when empty' do
it 'with a block returns false' do
L.empty.one? {}.should == false
end
it 'with no block returns false' do
L.empty.one?.should == false
end
end
context 'when not empty' do
context 'with a block' do
let(:list) { L['A', 'B', 'C'] }
it 'returns false if the block returns true more than once' do
list.one? { |item| true }.should == false
end
it 'returns false if the block never returns true' do
list.one? { |item| false }.should == false
end
it 'returns true if the block only returns true once' do
list.one? { |item| item == 'A' }.should == true
end
end
context 'with no block' do
it 'returns false if more than one value is truthy' do
L[nil, true, 'A'].one?.should == false
end
it 'returns true if only one value is truthy' do
L[nil, true, false].one?.should == true
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/count_spec.rb 0000644 0001750 0001750 00000001423 14201005456 024001 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#count' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.count }.should_not raise_error
end
end
[
[[], 0],
[[1], 1],
[[1, 2], 1],
[[1, 2, 3], 2],
[[1, 2, 3, 4], 2],
[[1, 2, 3, 4, 5], 3],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it "returns #{expected.inspect}" do
list.count(&:odd?).should == expected
end
end
context 'without a block' do
it 'returns length' do
list.count.should == list.length
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/reduce_spec.rb 0000644 0001750 0001750 00000002770 14201005456 024126 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:reduce, :inject].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.send(method, &:+) }.should_not raise_error
end
end
[
[[], 10, 10],
[[1], 10, 9],
[[1, 2, 3], 10, 4],
].each do |values, initial, expected|
context "on #{values.inspect}" do
context "with an initial value of #{initial} and a block" do
it "returns #{expected.inspect}" do
L[*values].send(method, initial) { |memo, item| memo - item }.should == expected
end
end
end
end
[
[[], nil],
[[1], 1],
[[1, 2, 3], -4],
].each do |values, expected|
context "on #{values.inspect}" do
context 'with no initial value and a block' do
it "returns #{expected.inspect}" do
L[*values].send(method) { |memo, item| memo - item }.should == expected
end
end
end
end
context 'with no block and a symbol argument' do
it 'uses the symbol as the name of a method to reduce with' do
L[1, 2, 3].send(method, :+).should == 6
end
end
context 'with no block and a string argument' do
it 'uses the string as the name of a method to reduce with' do
L[1, 2, 3].send(method, '+').should == 6
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/sum_spec.rb 0000644 0001750 0001750 00000000746 14201005456 023464 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#sum' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.sum }.should_not raise_error
end
end
[
[[], 0],
[[2], 2],
[[1, 3, 5, 7, 11], 27],
].each do |values, expected|
context "on #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].sum.should == expected
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/cycle_spec.rb 0000644 0001750 0001750 00000001170 14201005456 023747 0 ustar boutil boutil require 'spec_helper'
describe Immutable do
describe '#cycle' do
it 'is lazy' do
-> { Immutable.stream { fail }.cycle }.should_not raise_error
end
context 'with an empty list' do
it 'returns an empty list' do
L.empty.cycle.should be_empty
end
end
context 'with a non-empty list' do
let(:list) { L['A', 'B', 'C'] }
it 'preserves the original' do
list.cycle
list.should == L['A', 'B', 'C']
end
it 'infinitely cycles through all values' do
list.cycle.take(7).should == L['A', 'B', 'C', 'A', 'B', 'C', 'A']
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/map_spec.rb 0000644 0001750 0001750 00000002257 14201005456 023434 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:map, :collect].each do |method|
describe "##{method}" do
it 'is lazy' do
-> { Immutable.stream { fail }.map { |item| item } }.should_not raise_error
end
[
[[], []],
[['A'], ['a']],
[%w[A B C], %w[a b c]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it 'preserves the original' do
list.send(method, &:downcase)
list.should eql(L[*values])
end
it "returns #{expected.inspect}" do
list.send(method, &:downcase).should eql(L[*expected])
end
it 'is lazy' do
count = 0
list.send(method) { |item| count += 1 }
count.should <= 1
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.send(method).class.should be(Enumerator)
list.send(method).each(&:downcase).should eql(L[*expected])
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/each_slice_spec.rb 0000644 0001750 0001750 00000002567 14201005456 024742 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:each_chunk, :each_slice].each do |method|
describe "##{method}" do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.send(method, 1) { |item| } }.should_not raise_error
end
end
[
[[], []],
[['A'], [L['A']]],
[%w[A B C], [L['A', 'B'], L['C']]],
].each do |values, expected|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
it 'preserves the original' do
list.should eql(L[*values])
end
it 'iterates over the items in order' do
yielded = []
list.send(method, 2) { |item| yielded << item }
yielded.should eql(expected)
end
it 'returns self' do
list.send(method, 2) { |item| item }.should be(list)
end
end
context 'without a block' do
it 'preserves the original' do
list.send(method, 2)
list.should eql(L[*values])
end
it 'returns an Enumerator' do
list.send(method, 2).class.should be(Enumerator)
list.send(method, 2).to_a.should eql(expected)
end
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/hash_spec.rb 0000644 0001750 0001750 00000000760 14201005456 023577 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#hash' do
context 'on a really big list' do
it "doesn't run out of stack" do
-> { BigList.hash }.should_not raise_error
end
end
context 'on an empty list' do
it 'returns 0' do
expect(L.empty.hash).to eq(0)
end
end
it 'values are sufficiently distributed' do
(1..4000).each_slice(4).map { |a, b, c, d| L[a, b, c, d].hash }.uniq.size.should == 1000
end
end
end
immutable-ruby-master/spec/lib/immutable/list/indices_spec.rb 0000644 0001750 0001750 00000003151 14201005456 024267 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#indices' do
context 'when called with a block' do
it 'is lazy' do
count = 0
Immutable.stream { count += 1 }.indices { |item| true }
count.should <= 1
end
context "on a large list which doesn't contain desired item" do
it "doesn't blow the stack" do
-> { BigList.indices { |x| x < 0 }.size }.should_not raise_error
end
end
[
[[], 'A', []],
[['A'], 'B', []],
[%w[A B A], 'B', [1]],
[%w[A B A], 'A', [0, 2]],
[[2], 2, [0]],
[[2], 2.0, [0]],
[[2.0], 2.0, [0]],
[[2.0], 2, [0]],
].each do |values, item, expected|
context "looking for #{item.inspect} in #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].indices { |x| x == item }.should eql(L[*expected])
end
end
end
end
context 'when called with a single argument' do
it 'is lazy' do
count = 0
Immutable.stream { count += 1 }.indices(nil)
count.should <= 1
end
[
[[], 'A', []],
[['A'], 'B', []],
[%w[A B A], 'B', [1]],
[%w[A B A], 'A', [0, 2]],
[[2], 2, [0]],
[[2], 2.0, [0]],
[[2.0], 2.0, [0]],
[[2.0], 2, [0]],
].each do |values, item, expected|
context "looking for #{item.inspect} in #{values.inspect}" do
it "returns #{expected.inspect}" do
L[*values].indices(item).should eql(L[*expected])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/copying_spec.rb 0000644 0001750 0001750 00000000531 14201005456 024320 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
[:dup, :clone].each do |method|
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
let(:list) { L[*values] }
it 'returns self' do
list.send(method).should equal(list)
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/partition_spec.rb 0000644 0001750 0001750 00000007277 14201005456 024677 0 ustar boutil boutil require 'spec_helper'
require 'thread'
describe Immutable::List do
describe '#partition' do
it 'is lazy' do
-> { Immutable.stream { fail }.partition }.should_not raise_error
end
it 'calls the passed block only once for each item' do
count = 0
a,b = L[1, 2, 3].partition { |item| count += 1; item.odd? }
(a.size + b.size).should be(3) # force realization of lazy lists
count.should be(3)
end
# note: Lists are not as lazy as they could be!
# they always realize elements a bit ahead of the current one
it 'returns a lazy list of items for which predicate is true' do
count = 0
a,b = L[1, 2, 3, 4].partition { |item| count += 1; item.odd? }
a.take(1).should == [1]
count.should be(3) # would be 1 if lists were lazier
a.take(2).should == [1, 3]
count.should be(4) # would be 3 if lists were lazier
end
it 'returns a lazy list of items for which predicate is false' do
count = 0
a,b = L[1, 2, 3, 4].partition { |item| count += 1; item.odd? }
b.take(1).should == [2]
count.should be(4) # would be 2 if lists were lazier
b.take(2).should == [2, 4]
count.should be(4)
end
it 'calls the passed block only once for each item, even with multiple threads' do
mutex = Mutex.new
yielded = [] # record all the numbers yielded to the block, to make sure each is yielded only once
list = Immutable.iterate(0) do |n|
sleep(rand / 500) # give another thread a chance to get in
mutex.synchronize { yielded << n }
sleep(rand / 500)
n + 1
end
left, right = list.partition(&:odd?)
10.times.collect do |i|
Thread.new do
# half of the threads will consume the "left" lazy list, while half consume
# the "right" lazy list
# make sure that only one thread will run the above "iterate" block at a
# time, regardless
if i % 2 == 0
left.take(100).sum.should == 10000
else
right.take(100).sum.should == 9900
end
end
end.each(&:join)
# if no threads "stepped on" each other, the following should be true
# make some allowance for "lazy" lists which actually realize a little bit ahead:
(200..203).include?(yielded.size).should == true
yielded.should == (0..(yielded.size-1)).to_a
end
[
[[], [], []],
[[1], [1], []],
[[1, 2], [1], [2]],
[[1, 2, 3], [1, 3], [2]],
[[1, 2, 3, 4], [1, 3], [2, 4]],
[[2, 3, 4], [3], [2, 4]],
[[3, 4], [3], [4]],
[[4], [], [4]],
].each do |values, expected_matches, expected_remainder|
context "on #{values.inspect}" do
let(:list) { L[*values] }
context 'with a block' do
let(:result) { list.partition(&:odd?) }
let(:matches) { result.first }
let(:remainder) { result.last }
it 'preserves the original' do
list.should eql(L[*values])
end
it 'returns a frozen array with two items' do
result.class.should be(Array)
result.should be_frozen
result.size.should be(2)
end
it 'correctly identifies the matches' do
matches.should eql(L[*expected_matches])
end
it 'correctly identifies the remainder' do
remainder.should eql(L[*expected_remainder])
end
end
context 'without a block' do
it 'returns an Enumerator' do
list.partition.class.should be(Enumerator)
list.partition.each(&:odd?).should eql([L[*expected_matches], L[*expected_remainder]])
end
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/to_set_spec.rb 0000644 0001750 0001750 00000000506 14201005456 024147 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#to_set' do
[
[],
['A'],
%w[A B C],
].each do |values|
context "on #{values.inspect}" do
it 'returns a set with the same values' do
L[*values].to_set.should eql(S[*values])
end
end
end
end
end
immutable-ruby-master/spec/lib/immutable/list/permutation_spec.rb 0000644 0001750 0001750 00000003116 14201005456 025221 0 ustar boutil boutil require 'spec_helper'
describe Immutable::List do
describe '#permutation' do
let(:list) { L[1,2,3,4] }
context 'with no block' do
it 'returns an Enumerator' do
list.permutation.class.should be(Enumerator)
list.permutation.to_a.sort.should == [1,2,3,4].permutation.to_a.sort
end
end
context 'with no argument' do
it 'yields all permutations of the list' do
perms = list.permutation.to_a
perms.size.should be(24)
perms.sort.should == [1,2,3,4].permutation.to_a.sort
perms.each { |item| item.should be_kind_of(Immutable::List) }
end
end
context 'with a length argument' do
it 'yields all N-size permutations of the list' do
perms = list.permutation(2).to_a
perms.size.should be(12)
perms.sort.should == [1,2,3,4].permutation(2).to_a.sort
perms.each { |item| item.should be_kind_of(Immutable::List) }
end
end
context 'with a length argument greater than length of list' do
it 'yields nothing' do
list.permutation(5).to_a.should be_empty
end
end
context 'with a length argument of 0' do
it 'yields an empty list' do
perms = list.permutation(0).to_a
perms.size.should be(1)
perms[0].should be_kind_of(Immutable::List)
perms[0].should be_empty
end
end
context 'with a block' do
it 'returns the original list' do
list.permutation(0) {}.should be(list)
list.permutation(1) {}.should be(list)
list.permutation {}.should be(list)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/nested/ 0000755 0001750 0001750 00000000000 14201005456 021621 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/nested/construction_spec.rb 0000644 0001750 0001750 00000007254 14201005456 025722 0 ustar boutil boutil require 'spec_helper'
require 'set'
describe Immutable do
expectations = [
# [Ruby, Immutable]
[ { 'a' => 1,
'b' => [2, {'c' => 3}, 4],
'd' => ::Set.new([5, 6, 7]),
'e' => {'f' => 8, 'g' => 9},
'h' => Regexp.new('ijk') },
Immutable::Hash[
'a' => 1,
'b' => Immutable::Vector[2, Immutable::Hash['c' => 3], 4],
'd' => Immutable::Set[5, 6, 7],
'e' => Immutable::Hash['f' => 8, 'g' => 9],
'h' => Regexp.new('ijk') ] ],
[ {}, Immutable::Hash[] ],
[ {'a' => 1, 'b' => 2, 'c' => 3}, Immutable::Hash['a' => 1, 'b' => 2, 'c' => 3] ],
[ [], Immutable::Vector[] ],
[ [1, 2, 3], Immutable::Vector[1, 2, 3] ],
[ ::Set.new, Immutable::Set[] ],
[ ::Set.new([1, 2, 3]), Immutable::Set[1, 2, 3] ],
[ 42, 42 ],
[ STDOUT, STDOUT ],
# Struct conversion is one-way (from Ruby core Struct to Immutable::Hash), not back again!
[ Struct::Customer.new, Immutable::Hash[name: nil, address: nil], true ],
[ Struct::Customer.new('Dave', '123 Main'), Immutable::Hash[name: 'Dave', address: '123 Main'], true ]
]
describe '.from' do
expectations.each do |input, expected_result|
context "with #{input.inspect} as input" do
it "should return #{expected_result.inspect}" do
Immutable.from(input).should eql(expected_result)
end
end
end
context 'with mixed object' do
it 'should return Immutable data' do
input = {
'a' => 'b',
'c' => {'d' => 'e'},
'f' => Immutable::Vector['g', 'h', []],
'i' => Immutable::Hash['j' => {}, 'k' => Immutable::Set[[], {}]] }
expected_result = Immutable::Hash[
'a' => 'b',
'c' => Immutable::Hash['d' => 'e'],
'f' => Immutable::Vector['g', 'h', Immutable::EmptyVector],
'i' => Immutable::Hash['j' => Immutable::EmptyHash, 'k' => Immutable::Set[Immutable::EmptyVector, Immutable::EmptyHash]] ]
Immutable.from(input).should eql(expected_result)
end
end
end
describe '.to_ruby' do
expectations.each do |expected_result, input, one_way|
next if one_way
context "with #{input.inspect} as input" do
it "should return #{expected_result.inspect}" do
Immutable.to_ruby(input).should eql(expected_result)
end
end
end
context 'with Immutable::Deque[] as input' do
it 'should return []' do
Immutable.to_ruby(Immutable::Deque[]).should eql([])
end
end
context 'with Immutable::Deque[Immutable::Hash["a" => 1]] as input' do
it 'should return [{"a" => 1}]' do
Immutable.to_ruby(Immutable::Deque[Immutable::Hash['a' => 1]]).should eql([{'a' => 1}])
end
end
context 'with Immutable::SortedSet[] as input' do
it 'should return ::SortedSet.new' do
Immutable.to_ruby(Immutable::SortedSet[]).should == ::SortedSet.new
end
end
context 'with Immutable::SortedSet[1, 2, 3] as input' do
it 'should return ::SortedSet.new' do
Immutable.to_ruby(Immutable::SortedSet[1, 2, 3]).should == ::SortedSet.new([1, 2, 3])
end
end
context 'with mixed object' do
it 'should return Ruby data structures' do
input = Immutable::Hash[
'a' => 'b',
'c' => {'d' => 'e'},
'f' => Immutable::Vector['g', 'h'],
'i' => {'j' => Immutable::EmptyHash, 'k' => Set.new([Immutable::EmptyVector, Immutable::EmptyHash])}]
expected_result = {
'a' => 'b',
'c' => {'d' => 'e'},
'f' => ['g', 'h'],
'i' => {'j' => {}, 'k' => Set.new([[], {}])} }
Immutable.to_ruby(input).should eql(expected_result)
end
end
end
end
immutable-ruby-master/spec/lib/immutable/core_ext/ 0000755 0001750 0001750 00000000000 14201005456 022147 5 ustar boutil boutil immutable-ruby-master/spec/lib/immutable/core_ext/array_spec.rb 0000644 0001750 0001750 00000000365 14201005456 024630 0 ustar boutil boutil require 'spec_helper'
describe Array do
let(:array) { %w[A B C] }
describe '#to_list' do
let(:to_list) { array.to_list }
it 'returns an equivalent Immutable list' do
expect(to_list).to eq(L['A', 'B', 'C'])
end
end
end
immutable-ruby-master/spec/lib/immutable/core_ext/enumerable_spec.rb 0000644 0001750 0001750 00000001020 14201005456 025616 0 ustar boutil boutil require 'spec_helper'
describe Enumerable do
class TestEnumerable
include Enumerable
def initialize(*values)
@values = values
end
def each(&block)
@values.each(&block)
end
end
let(:enumerable) { TestEnumerable.new('A', 'B', 'C') }
describe '#to_list' do
let(:to_list) { enumerable.to_list }
it 'returns an equivalent list' do
expect(to_list).to eq(L['A', 'B', 'C'])
end
it 'works on Ranges' do
expect((1..3).to_list).to eq(L[1, 2, 3])
end
end
end
immutable-ruby-master/spec/lib/immutable/core_ext/io_spec.rb 0000644 0001750 0001750 00000001061 14201005456 024113 0 ustar boutil boutil require 'spec_helper'
describe IO do
describe '#to_list' do
let(:list) { L["A\n", "B\n", "C\n"] }
let(:to_list) { io.to_list }
after(:each) do
io.close
end
context 'with a File' do
let(:io) { File.new(fixture_path('io_spec.txt')) }
it 'returns an equivalent list' do
expect(to_list).to eq(list)
end
end
context 'with a StringIO' do
let(:io) { StringIO.new(fixture('io_spec.txt')) }
it 'returns an equivalent list' do
expect(to_list).to eq(list)
end
end
end
end
immutable-ruby-master/spec/lib/load_spec.rb 0000644 0001750 0001750 00000002570 14201005456 020642 0 ustar boutil boutil # It should be possible to require any one Immutable structure,
# without loading all the others
immutable_lib_dir = File.join(File.dirname(__FILE__), '..', '..', 'lib')
describe :Immutable do
describe :Hash do
it 'can be loaded separately' do
system(%{ruby -e "$:.unshift('#{immutable_lib_dir}'); require 'immutable/hash'; Immutable::Hash.new"}).should be(true)
end
end
describe :Set do
it 'can be loaded separately' do
system(%{ruby -e "$:.unshift('#{immutable_lib_dir}'); require 'immutable/set'; Immutable::Set.new"}).should be(true)
end
end
describe :Vector do
it 'can be loaded separately' do
system(%{ruby -e "$:.unshift('#{immutable_lib_dir}'); require 'immutable/vector'; Immutable::Vector.new"}).should be(true)
end
end
describe :List do
it 'can be loaded separately' do
system(%{ruby -e "$:.unshift('#{immutable_lib_dir}'); require 'immutable/list'; Immutable::List[]"}).should be(true)
end
end
describe :SortedSet do
it 'can be loaded separately' do
system(%{ruby -e "$:.unshift('#{immutable_lib_dir}'); require 'immutable/sorted_set'; Immutable::SortedSet.new"}).should be(true)
end
end
describe :Deque do
it 'can be loaded separately' do
system(%{ruby -e "$:.unshift('#{immutable_lib_dir}'); require 'immutable/deque'; Immutable::Deque.new"}).should be(true)
end
end
end
immutable-ruby-master/Gemfile 0000644 0001750 0001750 00000000156 14201005456 016155 0 ustar boutil boutil #!/usr/bin/env ruby
source 'https://rubygems.org/'
# Dependencies are specified in immutable.gemspec
gemspec
immutable-ruby-master/.ruby-gemset 0000644 0001750 0001750 00000000012 14201005456 017115 0 ustar boutil boutil immutable
immutable-ruby-master/lib/ 0000755 0001750 0001750 00000000000 14201005456 015426 5 ustar boutil boutil immutable-ruby-master/lib/immutable.rb 0000644 0001750 0001750 00000000362 14201005456 017733 0 ustar boutil boutil require 'immutable/core_ext'
require 'immutable/list'
require 'immutable/deque'
require 'immutable/hash'
require 'immutable/set'
require 'immutable/vector'
require 'immutable/sorted_set'
require 'immutable/nested'
require 'immutable/version'
immutable-ruby-master/lib/immutable/ 0000755 0001750 0001750 00000000000 14201005456 017405 5 ustar boutil boutil immutable-ruby-master/lib/immutable/enumerable.rb 0000644 0001750 0001750 00000012303 14201005456 022050 0 ustar boutil boutil module Immutable
# Helper module for immutable-ruby's sequential collections
#
# Classes including `Immutable::Enumerable` must implement:
#
# - `#each` (just like `::Enumerable`).
# - `#select`, which takes a block, and returns an instance of the same class
# with only the items for which the block returns a true value
module Enumerable
include ::Enumerable
# Return a new collection with all the elements for which the block returns false.
def reject
return enum_for(:reject) if not block_given?
select { |item| !yield(item) }
end
alias delete_if reject
# Return a new collection with all `nil` elements removed.
def compact
select { |item| !item.nil? }
end
# Search the collection for elements which are `#===` to `item`. Yield them to
# the optional code block if provided, and return them as a new collection.
def grep(pattern, &block)
result = select { |item| pattern === item }
result = result.map(&block) if block_given?
result
end
# Search the collection for elements which are not `#===` to `item`. Yield
# them to the optional code block if provided, and return them as a new
# collection.
def grep_v(pattern, &block)
result = select { |item| !(pattern === item) }
result = result.map(&block) if block_given?
result
end
# Yield all integers from 0 up to, but not including, the number of items in
# this collection. For collections which provide indexed access, these are all
# the valid, non-negative indices into the collection.
def each_index(&block)
return enum_for(:each_index) unless block_given?
0.upto(size-1, &block)
self
end
# Multiply all the items (presumably numeric) in this collection together.
def product
reduce(1, &:*)
end
# Add up all the items (presumably numeric) in this collection.
def sum
reduce(0, &:+)
end
# Return 2 collections, the first containing all the elements for which the block
# evaluates to true, the second containing the rest.
def partition
return enum_for(:partition) if not block_given?
a,b = super
[self.class.new(a), self.class.new(b)].freeze
end
# Groups the collection into sub-collections by the result of yielding them to
# the block. Returns a {Hash} where the keys are return values from the block,
# and the values are sub-collections. All the sub-collections are built up from
# `empty_group`, which should respond to `#add` by returning a new collection
# with an added element.
def group_by_with(empty_group, &block)
block ||= lambda { |item| item }
reduce(Immutable::EmptyHash) do |hash, item|
key = block.call(item)
group = hash.get(key) || empty_group
hash.put(key, group.add(item))
end
end
protected :group_by_with
# Groups the collection into sub-collections by the result of yielding them to
# the block. Returns a {Hash} where the keys are return values from the block,
# and the values are sub-collections (of the same type as this one).
def group_by(&block)
group_by_with(self.class.empty, &block)
end
# Compare with `other`, and return 0, 1, or -1 if it is (respectively) equal to,
# greater than, or less than this collection.
def <=>(other)
return 0 if equal?(other)
enum1, enum2 = to_enum, other.to_enum
loop do
item1 = enum1.next
item2 = enum2.next
comp = (item1 <=> item2)
return comp if comp != 0
end
size1, size2 = size, other.size
return 0 if size1 == size2
size1 > size2 ? 1 : -1
end
# Return true if `other` contains the same elements, in the same order.
# @return [Boolean]
def ==(other)
eql?(other) || (other.respond_to?(:to_ary) && to_ary == other.to_ary)
end
# Convert all the elements into strings and join them together, separated by
# `separator`. By default, the `separator` is `$,`, the global default string
# separator, which is normally `nil`.
def join(separator = $,)
result = ''
if separator
each_with_index { |obj, i| result << separator if i > 0; result << obj.to_s }
else
each { |obj| result << obj.to_s }
end
result
end
# Convert this collection to a {Set}.
def to_set
Immutable::Set.new(self)
end
# Convert this collection to a programmer-readable `String` representation.
def inspect
result = "#{self.class}["
each_with_index { |obj, i| result << ', ' if i > 0; result << obj.inspect }
result << ']'
end
# @private
def pretty_print(pp)
pp.group(1, "#{self.class}[", ']') do
pp.breakable ''
pp.seplist(self) { |obj| obj.pretty_print(pp) }
end
end
alias to_ary to_a
alias index find_index
## Compatibility fixes
if RUBY_ENGINE == 'rbx'
# Rubinius implements Enumerable#sort_by using Enumerable#map
# Because we do our own, custom implementations of #map, that doesn't work well
# @private
def sort_by(&block)
result = to_a
result.frozen? ? result.sort_by(&block) : result.sort_by!(&block)
end
end
end
end
immutable-ruby-master/lib/immutable/set.rb 0000644 0001750 0001750 00000044631 14201005456 020535 0 ustar boutil boutil require 'immutable/undefined'
require 'immutable/enumerable'
require 'immutable/hash'
require 'immutable/trie'
require 'immutable/sorted_set'
require 'set'
module Immutable
# `Immutable::Set` is a collection of unordered values with no duplicates. Testing whether
# an object is present in the `Set` can be done in constant time. `Set` is also `Enumerable`, so you can
# iterate over the members of the set with {#each}, transform them with {#map}, filter
# them with {#select}, and so on. Some of the `Enumerable` methods are overridden to
# return `immutable-ruby` collections.
#
# Like the `Set` class in Ruby's standard library, which we will call RubySet,
# `Immutable::Set` defines equivalency of objects using `#hash` and `#eql?`. No two
# objects with the same `#hash` code, and which are also `#eql?`, can coexist in the
# same `Set`. If one is already in the `Set`, attempts to add another one will have
# no effect.
#
# `Set`s have no natural ordering and cannot be compared using `#<=>`. However, they
# define {#<}, {#>}, {#<=}, and {#>=} as shorthand for {#proper_subset?},
# {#proper_superset?}, {#subset?}, and {#superset?} respectively.
#
# The basic set-theoretic operations {#union}, {#intersection}, {#difference}, and
# {#exclusion} work with any `Enumerable` object.
#
# A `Set` can be created in either of the following ways:
#
# Immutable::Set.new([1, 2, 3]) # any Enumerable can be used to initialize
# Immutable::Set['A', 'B', 'C', 'D']
#
# The latter 2 forms of initialization can be used with your own, custom subclasses
# of `Immutable::Set`.
#
# Unlike RubySet, all methods which you might expect to "modify" an `Immutable::Set`
# actually return a new set and leave the existing one unchanged.
#
# @example
# set1 = Immutable::Set[1, 2] # => Immutable::Set[1, 2]
# set2 = Immutable::Set[1, 2] # => Immutable::Set[1, 2]
# set1 == set2 # => true
# set3 = set1.add("foo") # => Immutable::Set[1, 2, "foo"]
# set3 - set2 # => Immutable::Set["foo"]
# set3.subset?(set1) # => false
# set1.subset?(set3) # => true
#
class Set
include Immutable::Enumerable
class << self
# Create a new `Set` populated with the given items.
# @return [Set]
def [](*items)
items.empty? ? empty : new(items)
end
# Return an empty `Set`. If used on a subclass, returns an empty instance
# of that class.
#
# @return [Set]
def empty
@empty ||= new
end
# "Raw" allocation of a new `Set`. Used internally to create a new
# instance quickly after obtaining a modified {Trie}.
#
# @return [Set]
# @private
def alloc(trie = EmptyTrie)
allocate.tap { |s| s.instance_variable_set(:@trie, trie) }.freeze
end
end
def initialize(items=[])
@trie = Trie.new(0)
items.each { |item| @trie.put!(item, nil) }
freeze
end
# Return `true` if this `Set` contains no items.
# @return [Boolean]
def empty?
@trie.empty?
end
# Return the number of items in this `Set`.
# @return [Integer]
def size
@trie.size
end
alias length size
# Return a new `Set` with `item` added. If `item` is already in the set,
# return `self`.
#
# @example
# Immutable::Set[1, 2, 3].add(4) # => Immutable::Set[1, 2, 4, 3]
# Immutable::Set[1, 2, 3].add(2) # => Immutable::Set[1, 2, 3]
#
# @param item [Object] The object to add
# @return [Set]
def add(item)
include?(item) ? self : self.class.alloc(@trie.put(item, nil))
end
alias << add
# If `item` is not a member of this `Set`, return a new `Set` with `item` added.
# Otherwise, return `false`.
#
# @example
# Immutable::Set[1, 2, 3].add?(4) # => Immutable::Set[1, 2, 4, 3]
# Immutable::Set[1, 2, 3].add?(2) # => false
#
# @param item [Object] The object to add
# @return [Set, false]
def add?(item)
!include?(item) && add(item)
end
# Return a new `Set` with `item` removed. If `item` is not a member of the set,
# return `self`.
#
# @example
# Immutable::Set[1, 2, 3].delete(1) # => Immutable::Set[2, 3]
# Immutable::Set[1, 2, 3].delete(99) # => Immutable::Set[1, 2, 3]
#
# @param item [Object] The object to remove
# @return [Set]
def delete(item)
trie = @trie.delete(item)
new_trie(trie)
end
# If `item` is a member of this `Set`, return a new `Set` with `item` removed.
# Otherwise, return `false`.
#
# @example
# Immutable::Set[1, 2, 3].delete?(1) # => Immutable::Set[2, 3]
# Immutable::Set[1, 2, 3].delete?(99) # => false
#
# @param item [Object] The object to remove
# @return [Set, false]
def delete?(item)
include?(item) && delete(item)
end
# Call the block once for each item in this `Set`. No specific iteration order
# is guaranteed, but the order will be stable for any particular `Set`. If
# no block is given, an `Enumerator` is returned instead.
#
# @example
# Immutable::Set["Dog", "Elephant", "Lion"].each { |e| puts e }
# Elephant
# Dog
# Lion
# # => Immutable::Set["Dog", "Elephant", "Lion"]
#
# @yield [item] Once for each item.
# @return [self, Enumerator]
def each
return to_enum if not block_given?
@trie.each { |key, _| yield(key) }
self
end
# Call the block once for each item in this `Set`. Iteration order will be
# the opposite of {#each}. If no block is given, an `Enumerator` is
# returned instead.
#
# @example
# Immutable::Set["Dog", "Elephant", "Lion"].reverse_each { |e| puts e }
# Lion
# Dog
# Elephant
# # => Immutable::Set["Dog", "Elephant", "Lion"]
#
# @yield [item] Once for each item.
# @return [self]
def reverse_each
return enum_for(:reverse_each) if not block_given?
@trie.reverse_each { |key, _| yield(key) }
self
end
# Return a new `Set` with all the items for which the block returns true.
#
# @example
# Immutable::Set["Elephant", "Dog", "Lion"].select { |e| e.size >= 4 }
# # => Immutable::Set["Elephant", "Lion"]
# @yield [item] Once for each item.
# @return [Set]
def select
return enum_for(:select) unless block_given?
trie = @trie.select { |key, _| yield(key) }
new_trie(trie)
end
alias find_all select
alias keep_if select
# Call the block once for each item in this `Set`. All the values returned
# from the block will be gathered into a new `Set`. If no block is given,
# an `Enumerator` is returned instead.
#
# @example
# Immutable::Set["Cat", "Elephant", "Dog", "Lion"].map { |e| e.size }
# # => Immutable::Set[8, 4, 3]
#
# @yield [item] Once for each item.
# @return [Set]
def map
return enum_for(:map) if not block_given?
return self if empty?
self.class.new(super)
end
alias collect map
# Return `true` if the given item is present in this `Set`. More precisely,
# return `true` if an object with the same `#hash` code, and which is also `#eql?`
# to the given object is present.
#
# @example
# Immutable::Set["A", "B", "C"].include?("B") # => true
# Immutable::Set["A", "B", "C"].include?("Z") # => false
#
# @param object [Object] The object to check for
# @return [Boolean]
def include?(object)
@trie.key?(object)
end
alias member? include?
# Return a member of this `Set`. The member chosen will be the first one which
# would be yielded by {#each}. If the set is empty, return `nil`.
#
# @example
# Immutable::Set["A", "B", "C"].first # => "C"
#
# @return [Object]
def first
(entry = @trie.at(0)) && entry[0]
end
# Return a {SortedSet} which contains the same items as this `Set`, ordered by
# the given comparator block.
#
# @example
# Immutable::Set["Elephant", "Dog", "Lion"].sort
# # => Immutable::SortedSet["Dog", "Elephant", "Lion"]
# Immutable::Set["Elephant", "Dog", "Lion"].sort { |a,b| a.size <=> b.size }
# # => Immutable::SortedSet["Dog", "Lion", "Elephant"]
#
# @yield [a, b] Any number of times with different pairs of elements.
# @yieldreturn [Integer] Negative if the first element should be sorted
# lower, positive if the latter element, or 0 if
# equal.
# @return [SortedSet]
def sort(&comparator)
SortedSet.new(to_a, &comparator)
end
# Return a {SortedSet} which contains the same items as this `Set`, ordered
# by mapping each item through the provided block to obtain sort keys, and
# then sorting the keys.
#
# @example
# Immutable::Set["Elephant", "Dog", "Lion"].sort_by { |e| e.size }
# # => Immutable::SortedSet["Dog", "Lion", "Elephant"]
#
# @yield [item] Once for each item to create the set, and then potentially
# again depending on what operations are performed on the
# returned {SortedSet}. As such, it is recommended that the
# block be a pure function.
# @yieldreturn [Object] sort key for the item
# @return [SortedSet]
def sort_by(&mapper)
SortedSet.new(to_a, &mapper)
end
# Return a new `Set` which contains all the members of both this `Set` and `other`.
# `other` can be any `Enumerable` object.
#
# @example
# Immutable::Set[1, 2] | Immutable::Set[2, 3] # => Immutable::Set[1, 2, 3]
#
# @param other [Enumerable] The collection to merge with
# @return [Set]
def union(other)
if other.is_a?(Immutable::Set)
if other.size > size
small_set_pairs = @trie
large_set_trie = other.instance_variable_get(:@trie)
else
small_set_pairs = other.instance_variable_get(:@trie)
large_set_trie = @trie
end
else
if other.respond_to?(:lazy)
small_set_pairs = other.lazy.map { |e| [e, nil] }
else
small_set_pairs = other.map { |e| [e, nil] }
end
large_set_trie = @trie
end
trie = large_set_trie.bulk_put(small_set_pairs)
new_trie(trie)
end
alias | union
alias + union
alias merge union
# Return a new `Set` which contains all the items which are members of both
# this `Set` and `other`. `other` can be any `Enumerable` object.
#
# @example
# Immutable::Set[1, 2] & Immutable::Set[2, 3] # => Immutable::Set[2]
#
# @param other [Enumerable] The collection to intersect with
# @return [Set]
def intersection(other)
if other.size < @trie.size
if other.is_a?(Immutable::Set)
trie = other.instance_variable_get(:@trie).select { |key, _| include?(key) }
else
trie = Trie.new(0)
other.each { |obj| trie.put!(obj, nil) if include?(obj) }
end
else
trie = @trie.select { |key, _| other.include?(key) }
end
new_trie(trie)
end
alias & intersection
# Return a new `Set` with all the items in `other` removed. `other` can be
# any `Enumerable` object.
#
# @example
# Immutable::Set[1, 2] - Immutable::Set[2, 3] # => Immutable::Set[1]
#
# @param other [Enumerable] The collection to subtract from this set
# @return [Set]
def difference(other)
trie = if (@trie.size <= other.size) && (other.is_a?(Immutable::Set) || (defined?(::Set) && other.is_a?(::Set)))
@trie.select { |key, _| !other.include?(key) }
else
@trie.bulk_delete(other)
end
new_trie(trie)
end
alias subtract difference
alias - difference
# Return a new `Set` which contains all the items which are members of this
# `Set` or of `other`, but not both. `other` can be any `Enumerable` object.
#
# @example
# Immutable::Set[1, 2] ^ Immutable::Set[2, 3] # => Immutable::Set[1, 3]
#
# @param other [Enumerable] The collection to take the exclusive disjunction of
# @return [Set]
def exclusion(other)
((self | other) - (self & other))
end
alias ^ exclusion
# Return `true` if all items in this `Set` are also in `other`.
#
# @example
# Immutable::Set[2, 3].subset?(Immutable::Set[1, 2, 3]) # => true
#
# @param other [Set]
# @return [Boolean]
def subset?(other)
return false if other.size < size
# This method has the potential to be very slow if 'other' is a large Array, so to avoid that,
# we convert those Arrays to Sets before checking presence of items
# Time to convert Array -> Set is linear in array.size
# Time to check for presence of all items in an Array is proportional to set.size * array.size
# Note that both sides of that equation have array.size -- hence those terms cancel out,
# and the break-even point is solely dependent on the size of this collection
# After doing some benchmarking to estimate the constants, it appears break-even is at ~190 items
# We also check other.size, to avoid the more expensive #is_a? checks in cases where it doesn't matter
#
if other.size >= 150 && @trie.size >= 190 && !(other.is_a?(Immutable::Set) || other.is_a?(::Set))
other = ::Set.new(other)
end
all? { |item| other.include?(item) }
end
alias <= subset?
# Return `true` if all items in `other` are also in this `Set`.
#
# @example
# Immutable::Set[1, 2, 3].superset?(Immutable::Set[2, 3]) # => true
#
# @param other [Set]
# @return [Boolean]
def superset?(other)
other.subset?(self)
end
alias >= superset?
# Returns `true` if `other` contains all the items in this `Set`, plus at least
# one item which is not in this set.
#
# @example
# Immutable::Set[2, 3].proper_subset?(Immutable::Set[1, 2, 3]) # => true
# Immutable::Set[1, 2, 3].proper_subset?(Immutable::Set[1, 2, 3]) # => false
#
# @param other [Set]
# @return [Boolean]
def proper_subset?(other)
return false if other.size <= size
# See comments above
if other.size >= 150 && @trie.size >= 190 && !(other.is_a?(Immutable::Set) || other.is_a?(::Set))
other = ::Set.new(other)
end
all? { |item| other.include?(item) }
end
alias < proper_subset?
# Returns `true` if this `Set` contains all the items in `other`, plus at least
# one item which is not in `other`.
#
# @example
# Immutable::Set[1, 2, 3].proper_superset?(Immutable::Set[2, 3]) # => true
# Immutable::Set[1, 2, 3].proper_superset?(Immutable::Set[1, 2, 3]) # => false
#
# @param other [Set]
# @return [Boolean]
def proper_superset?(other)
other.proper_subset?(self)
end
alias > proper_superset?
# Return `true` if this `Set` and `other` do not share any items.
#
# @example
# Immutable::Set[1, 2].disjoint?(Immutable::Set[8, 9]) # => true
#
# @param other [Set]
# @return [Boolean]
def disjoint?(other)
if other.size <= size
other.each { |item| return false if include?(item) }
else
# See comment on #subset?
if other.size >= 150 && @trie.size >= 190 && !(other.is_a?(Immutable::Set) || other.is_a?(::Set))
other = ::Set.new(other)
end
each { |item| return false if other.include?(item) }
end
true
end
# Return `true` if this `Set` and `other` have at least one item in common.
#
# @example
# Immutable::Set[1, 2].intersect?(Immutable::Set[2, 3]) # => true
#
# @param other [Set]
# @return [Boolean]
def intersect?(other)
!disjoint?(other)
end
# Recursively insert the contents of any nested `Set`s into this `Set`, and
# remove them.
#
# @example
# Immutable::Set[Immutable::Set[1, 2], Immutable::Set[3, 4]].flatten
# # => Immutable::Set[1, 2, 3, 4]
#
# @return [Set]
def flatten
reduce(self.class.empty) do |set, item|
next set.union(item.flatten) if item.is_a?(Set)
set.add(item)
end
end
alias group group_by
alias classify group_by
# Return a randomly chosen item from this `Set`. If the set is empty, return `nil`.
#
# @example
# Immutable::Set[1, 2, 3, 4, 5].sample # => 3
#
# @return [Object]
def sample
empty? ? nil : @trie.at(rand(size))[0]
end
# Return an empty `Set` instance, of the same class as this one. Useful if you
# have multiple subclasses of `Set` and want to treat them polymorphically.
#
# @return [Set]
def clear
self.class.empty
end
# Return true if `other` has the same type and contents as this `Set`.
#
# @param other [Object] The object to compare with
# @return [Boolean]
def eql?(other)
return true if other.equal?(self)
return false if not instance_of?(other.class)
other_trie = other.instance_variable_get(:@trie)
return false if @trie.size != other_trie.size
@trie.each do |key, _|
return false if !other_trie.key?(key)
end
true
end
alias == eql?
# See `Object#hash`.
# @return [Integer]
def hash
reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
end
# Return `self`. Since this is an immutable object duplicates are
# equivalent.
# @return [Set]
def dup
self
end
alias clone dup
undef :"<=>" # Sets are not ordered, so Enumerable#<=> will give a meaningless result
undef :each_index # Set members cannot be accessed by 'index', so #each_index is not meaningful
# Return `self`.
#
# @return [self]
def to_set
self
end
# @private
def marshal_dump
output = {}
each do |key|
output[key] = nil
end
output
end
# @private
def marshal_load(dictionary)
@trie = dictionary.reduce(EmptyTrie) do |trie, key_value|
trie.put(key_value.first, nil)
end
end
private
def new_trie(trie)
if trie.empty?
self.class.empty
elsif trie.equal?(@trie)
self
else
self.class.alloc(trie)
end
end
end
# The canonical empty `Set`. Returned by `Set[]` when
# invoked with no arguments; also returned by `Set.empty`. Prefer using this
# one rather than creating many empty sets using `Set.new`.
#
# @private
EmptySet = Immutable::Set.empty
end
immutable-ruby-master/lib/immutable/version.rb 0000644 0001750 0001750 00000000251 14201005456 021415 0 ustar boutil boutil module Immutable
# Current released gem version. Note that master will often have the same
# value as a release gem but with different code.
VERSION = '0.1.0'
end
immutable-ruby-master/lib/immutable/hash.rb 0000644 0001750 0001750 00000076657 14201005456 020702 0 ustar boutil boutil require 'immutable/undefined'
require 'immutable/enumerable'
require 'immutable/trie'
require 'immutable/set'
require 'immutable/vector'
module Immutable
# An `Immutable::Hash` maps a set of unique keys to corresponding values, much
# like a dictionary maps from words to definitions. Given a key, it can store
# and retrieve an associated value in constant time. If an existing key is
# stored again, the new value will replace the old. It behaves much like
# Ruby's built-in Hash, which we will call RubyHash for clarity. Like
# RubyHash, two keys that are `#eql?` to each other and have the same
# `#hash` are considered identical in an `Immutable::Hash`.
#
# An `Immutable::Hash` can be created in a couple of ways:
#
# Immutable::Hash.new(font_size: 10, font_family: 'Arial')
# Immutable::Hash[first_name: 'John', last_name: 'Smith']
#
# Any `Enumerable` object which yields two-element `[key, value]` arrays
# can be used to initialize an `Immutable::Hash`:
#
# Immutable::Hash.new([[:first_name, 'John'], [:last_name, 'Smith']])
#
# Key/value pairs can be added using {#put}. A new hash is returned and the
# existing one is left unchanged:
#
# hash = Immutable::Hash[a: 100, b: 200]
# hash.put(:c, 500) # => Immutable::Hash[:a => 100, :b => 200, :c => 500]
# hash # => Immutable::Hash[:a => 100, :b => 200]
#
# {#put} can also take a block, which is used to calculate the value to be
# stored.
#
# hash.put(:a) { |current| current + 200 } # => Immutable::Hash[:a => 300, :b => 200]
#
# Since it is immutable, all methods which you might expect to "modify" a
# `Immutable::Hash` actually return a new hash and leave the existing one
# unchanged. This means that the `hash[key] = value` syntax from RubyHash
# *cannot* be used with `Immutable::Hash`.
#
# Nested data structures can easily be updated using {#update_in}:
#
# hash = Immutable::Hash["a" => Immutable::Vector[Immutable::Hash["c" => 42]]]
# hash.update_in("a", 0, "c") { |value| value + 5 }
# # => Immutable::Hash["a" => Immutable::Hash["b" => Immutable::Hash["c" => 47]]]
#
# While an `Immutable::Hash` can iterate over its keys or values, it does not
# guarantee any specific iteration order (unlike RubyHash). Methods like
# {#flatten} do not guarantee the order of returned key/value pairs.
#
# Like RubyHash, an `Immutable::Hash` can have a default block which is used
# when looking up a key that does not exist. Unlike RubyHash, the default
# block will only be passed the missing key, without the hash itself:
#
# hash = Immutable::Hash.new { |missing_key| missing_key * 10 }
# hash[5] # => 50
class Hash
include Immutable::Enumerable
class << self
# Create a new `Hash` populated with the given key/value pairs.
#
# @example
# Immutable::Hash["A" => 1, "B" => 2] # => Immutable::Hash["A" => 1, "B" => 2]
# Immutable::Hash[["A", 1], ["B", 2]] # => Immutable::Hash["A" => 1, "B" => 2]
#
# @param pairs [::Enumerable] initial content of hash. An empty hash is returned if not provided.
# @return [Hash]
def [](pairs = nil)
(pairs.nil? || pairs.empty?) ? empty : new(pairs)
end
# Return an empty `Hash`. If used on a subclass, returns an empty instance
# of that class.
#
# @return [Hash]
def empty
@empty ||= new
end
# "Raw" allocation of a new `Hash`. Used internally to create a new
# instance quickly after obtaining a modified {Trie}.
#
# @return [Hash]
# @private
def alloc(trie = EmptyTrie, block = nil)
obj = allocate
obj.instance_variable_set(:@trie, trie)
obj.instance_variable_set(:@default, block)
obj.freeze
end
end
# @param pairs [::Enumerable] initial content of hash. An empty hash is returned if not provided.
# @yield [key] Optional _default block_ to be stored and used to calculate the default value of a missing key. It will not be yielded during this method. It will not be preserved when marshalling.
# @yieldparam key Key that was not present in the hash.
def initialize(pairs = nil, &block)
@trie = pairs ? Trie[pairs] : EmptyTrie
@default = block
freeze
end
# Return the default block if there is one. Otherwise, return `nil`.
#
# @return [Proc]
def default_proc
@default
end
# Return the number of key/value pairs in this `Hash`.
#
# @example
# Immutable::Hash["A" => 1, "B" => 2, "C" => 3].size # => 3
#
# @return [Integer]
def size
@trie.size
end
alias length size
# Return `true` if this `Hash` contains no key/value pairs.
#
# @return [Boolean]
def empty?
@trie.empty?
end
# Return `true` if the given key object is present in this `Hash`. More precisely,
# return `true` if a key with the same `#hash` code, and which is also `#eql?`
# to the given key object is present.
#
# @example
# Immutable::Hash["A" => 1, "B" => 2, "C" => 3].key?("B") # => true
#
# @param key [Object] The key to check for
# @return [Boolean]
def key?(key)
@trie.key?(key)
end
alias has_key? key?
alias include? key?
alias member? key?
# Return `true` if this `Hash` has one or more keys which map to the provided value.
#
# @example
# Immutable::Hash["A" => 1, "B" => 2, "C" => 3].value?(2) # => true
#
# @param value [Object] The value to check for
# @return [Boolean]
def value?(value)
each { |k,v| return true if value == v }
false
end
alias has_value? value?
# Retrieve the value corresponding to the provided key object. If not found, and
# this `Hash` has a default block, the default block is called to provide the
# value. Otherwise, return `nil`.
#
# @example
# h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
# h["B"] # => 2
# h.get("B") # => 2
# h.get("Elephant") # => nil
#
# # Immutable Hash with a default proc:
# h = Immutable::Hash.new("A" => 1, "B" => 2, "C" => 3) { |key| key.size }
# h.get("B") # => 2
# h.get("Elephant") # => 8
#
# @param key [Object] The key to look up
# @return [Object]
def get(key)
entry = @trie.get(key)
if entry
entry[1]
elsif @default
@default.call(key)
end
end
alias [] get
# Retrieve the value corresponding to the given key object, or use the provided
# default value or block, or otherwise raise a `KeyError`.
#
# @overload fetch(key)
# Retrieve the value corresponding to the given key, or raise a `KeyError`
# if it is not found.
# @param key [Object] The key to look up
# @overload fetch(key) { |key| ... }
# Retrieve the value corresponding to the given key, or call the optional
# code block (with the missing key) and get its return value.
# @yield [key] The key which was not found
# @yieldreturn [Object] Object to return since the key was not found
# @param key [Object] The key to look up
# @overload fetch(key, default)
# Retrieve the value corresponding to the given key, or else return
# the provided `default` value.
# @param key [Object] The key to look up
# @param default [Object] Object to return if the key is not found
#
# @example
# h = Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
# h.fetch("B") # => 2
# h.fetch("Elephant") # => KeyError: key not found: "Elephant"
#
# # with a default value:
# h.fetch("B", 99) # => 2
# h.fetch("Elephant", 99) # => 99
#
# # with a block:
# h.fetch("B") { |key| key.size } # => 2
# h.fetch("Elephant") { |key| key.size } # => 8
#
# @return [Object]
def fetch(key, default = Undefined)
entry = @trie.get(key)
if entry
entry[1]
elsif block_given?
yield(key)
elsif default != Undefined
default
else
raise KeyError, "key not found: #{key.inspect}"
end
end
# Return a new `Hash` with the existing key/value associations, plus an association
# between the provided key and value. If an equivalent key is already present, its
# associated value will be replaced with the provided one.
#
# If the `value` argument is missing, but an optional code block is provided,
# it will be passed the existing value (or `nil` if there is none) and what it
# returns will replace the existing value. This is useful for "transforming"
# the value associated with a certain key.
#
# Avoid mutating objects which are used as keys. `String`s are an exception:
# unfrozen `String`s which are used as keys are internally duplicated and
# frozen. This matches RubyHash's behaviour.
#
# @example
# h = Immutable::Hash["A" => 1, "B" => 2]
# h.put("C", 3)
# # => Immutable::Hash["A" => 1, "B" => 2, "C" => 3]
# h.put("B") { |value| value * 10 }
# # => Immutable::Hash["A" => 1, "B" => 20]
#
# @param key [Object] The key to store
# @param value [Object] The value to associate it with
# @yield [value] The previously stored value, or `nil` if none.
# @yieldreturn [Object] The new value to store
# @return [Hash]
def put(key, value = yield(get(key)))
new_trie = @trie.put(key, value)
if new_trie.equal?(@trie)
self
else
self.class.alloc(new_trie, @default)
end
end
# @private
# @raise NoMethodError
def []=(*)
raise NoMethodError, "Immutable::Hash doesn't support `[]='; use `put' instead"
end
# Return a new `Hash` with a deeply nested value modified to the result of
# the given code block. When traversing the nested `Hash`es and `Vector`s,
# non-existing keys are created with empty `Hash` values.
#
# The code block receives the existing value of the deeply nested key (or
# `nil` if it doesn't exist). This is useful for "transforming" the value
# associated with a certain key.
#
# Note that the original `Hash` and sub-`Hash`es and sub-`Vector`s are left
# unmodified; new data structure copies are created along the path wherever
# needed.
#
# @example
# hash = Immutable::Hash["a" => Immutable::Hash["b" => Immutable::Hash["c" => 42]]]
# hash.update_in("a", "b", "c") { |value| value + 5 }
# # => Immutable::Hash["a" => Immutable::Hash["b" => Immutable::Hash["c" => 47]]]
#
# @param key_path [::Array