https://github.com/alexb52/grizzly-rb
The Ruby library you will love to hate
https://github.com/alexb52/grizzly-rb
array collection library list ruby
Last synced: over 1 year ago
JSON representation
The Ruby library you will love to hate
- Host: GitHub
- URL: https://github.com/alexb52/grizzly-rb
- Owner: AlexB52
- License: mit
- Created: 2020-09-27T00:19:42.000Z (almost 6 years ago)
- Default Branch: main
- Last Pushed: 2023-05-17T09:51:47.000Z (about 3 years ago)
- Last Synced: 2025-03-11T21:11:17.070Z (over 1 year ago)
- Topics: array, collection, library, list, ruby
- Language: Ruby
- Homepage:
- Size: 436 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
:anger: **DISCLAIMER** :anger:
Reading this README isn't for the faint of heart.
The library isn't meant to replace the Array and the purpose isn't to use it in production. Although you could use it in projects, every part of your body will tell you not to. It feels dirty, it feels **grisly**, yet it now exists, it's there and works as expected.
You will love to hate it.
# Grizzly library
The Grizzly library is an attempt to end the predominance of the Array in Ruby by providing a collection that casts itself back while matching the whole Array interface. The work came after reading [Steve Klabnik's warning](https://steveklabnik.com/writing/beware-subclassing-ruby-core-classes) & [gist](https://gist.github.com/steveklabnik/6071687) about subclassing Ruby core classes.
We're testing the library against the [Ruby/Spec](https://github.com/ruby/spec) and covers most of the Array methods.
The library provides four classes/modules:
* Grizzly::Collection (Array subclass)
* Grizzly::Enumerable (Enumerable extension)
* Grizzly::Enumerator (Enumerator decorator)
* Grizzly::LazyEnumerator (Enumerator::Lazy decorator)
You can find them in the lib folder.
**The Grizzly::Collection is a subclass of Array that works.**
## Usage
For an extensive use of the library you can see this [file](examples/transactions.rb)
```ruby
require "grizzly"
Mark = Struct.new(:score)
class MarkCollection < Grizzly::Collection
def average_score
sum(&:score) / size.to_f
end
end
marks = MarkCollection.new (0..100).to_a.map { |i| Mark.new(i) }
marks.select { |mark| mark.score.even? }.
average_score
# => 50.0
marks.select { |mark| mark.score.even? }.
reject { |mark| mark.score <= 80 }.
average_score
# => 91.0
```
### Gotchas
`Grizzly::Collection` methods try their best to return what you would expect. That said there are some methods with special behaviour.
* `#map` returns an instance of the subclass and not an Array.
* `#to_a` returns an Array
* `#transpose`, `#product`, `#zip`, `#partition`, `#group_by`: check their implementation and specs as they return subgroups
* `#grep` and `#grep_v` methods are not supported and will raise: See issue https://github.com/AlexB52/grizzly-rb/issues/8
## Ruby support
Ruby 2.7+
## Roadmap
- [X] Array
- [X] Enumerable
- [X] Enumerator
- [X] Lazy Enumerator
- [X] Benchmarks
## Benchmark
You can run the benchmark with `ruby benchmark.rb`
The benchmark runs over increments of list with 10\*\*n items for a total of 5_000_000 iterations.
### Conclusions
This library initialize a new collection everytime the Array method returns.
Chaining methods with Grizzly::Collection is:
* really expensive for list with a small number of items. <= 10
* less of a problem with lists over 100 items
### Raw Results
```
=== One method ===
{ |list| list.select(&:odd?) }
user system total real
List of length 1 iterated over 5000000 times - Array 1.465777 0.010639 1.476416 ( 1.484419)
List of length 1 iterated over 5000000 times - Grizzly::Collection 4.173212 0.025837 4.199049 ( 4.219159)
user system total real
List of length 10 iterated over 500000 times - Array 0.449475 0.002248 0.451723 ( 0.453940)
List of length 10 iterated over 500000 times - Grizzly::Collection 0.848438 0.006855 0.855293 ( 0.858316)
user system total real
List of length 100 iterated over 50000 times - Array 0.342236 0.003515 0.345751 ( 0.347207)
List of length 100 iterated over 50000 times - Grizzly::Collection 0.389331 0.005771 0.395102 ( 0.396907)
user system total real
List of length 1000 iterated over 5000 times - Array 0.367041 0.013971 0.381012 ( 0.384799)
List of length 1000 iterated over 5000 times - Grizzly::Collection 0.338568 0.007703 0.346271 ( 0.347265)
user system total real
List of length 10000 iterated over 500 times - Array 0.332582 0.008056 0.340638 ( 0.341963)
List of length 10000 iterated over 500 times - Grizzly::Collection 0.338311 0.016007 0.354318 ( 0.356256)
=== Two chained methods ===
{ |list| list.select(&:odd?).reject(&:odd?) }
user system total real
List of length 1 iterated over 5000000 times - Array 2.087311 0.016413 2.103724 ( 2.114187)
List of length 1 iterated over 5000000 times - Grizzly::Collection 8.177386 0.051953 8.229339 ( 8.265598)
user system total real
List of length 10 iterated over 500000 times - Array 0.649130 0.002928 0.652058 ( 0.654708)
List of length 10 iterated over 500000 times - Grizzly::Collection 1.408604 0.009925 1.418529 ( 1.424733)
user system total real
List of length 100 iterated over 50000 times - Array 0.503027 0.001814 0.504841 ( 0.506741)
List of length 100 iterated over 50000 times - Grizzly::Collection 0.623167 0.005466 0.628633 ( 0.632303)
user system total real
List of length 1000 iterated over 5000 times - Array 0.486371 0.003466 0.489837 ( 0.491048)
List of length 1000 iterated over 5000 times - Grizzly::Collection 0.500942 0.005642 0.506584 ( 0.509051)
user system total real
List of length 10000 iterated over 500 times - Array 0.492759 0.008542 0.501301 ( 0.503459)
List of length 10000 iterated over 500 times - Grizzly::Collection 0.514448 0.014804 0.529252 ( 0.531968)
=== Chained enumerators ===
{ |list| list.select.each.select.reject(&:odd?) }
user system total real
List of length 1 iterated over 5000000 times - Array 5.537677 0.066783 5.604460 ( 5.630154)
List of length 1 iterated over 5000000 times - Grizzly::Collection 30.203623 0.230334 30.433957 ( 30.573476)
user system total real
List of length 10 iterated over 500000 times - Array 1.060200 0.008406 1.068606 ( 1.073304)
List of length 10 iterated over 500000 times - Grizzly::Collection 3.674943 0.029664 3.704607 ( 3.721847)
user system total real
List of length 100 iterated over 50000 times - Array 0.570368 0.003019 0.573387 ( 0.575771)
List of length 100 iterated over 50000 times - Grizzly::Collection 0.895747 0.005782 0.901529 ( 0.906251)
user system total real
List of length 1000 iterated over 5000 times - Array 0.518924 0.003155 0.522079 ( 0.524788)
List of length 1000 iterated over 5000 times - Grizzly::Collection 0.553667 0.004346 0.558013 ( 0.560381)
user system total real
List of length 10000 iterated over 500 times - Array 0.518883 0.010600 0.529483 ( 0.531777)
List of length 10000 iterated over 500 times - Grizzly::Collection 0.528470 0.014786 0.543256 ( 0.545524)
```
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'grizzly-rb', require: 'grizzly'
```
And then execute:
$ bundle install
Or install it yourself as:
$ gem install grizzly-rb
## Development
```bash
# Setup dependencies: bundler, mspec and ruby-spec
$ bin/setup
# Run all specs
$ bin/test
```
### Prototype with console
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/grizzly-rb.
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).