Unnatural
A natural sort for Ruby.
Unnatural defines a natural sort as one where:
- comparison is case-insensitive
- consecutive sequences of digits are compared according to their numeric value (not their ascii values)
Unnatural does not (currently) provide support for:
- non-ASCII-compatible encoding
- any number representation other than simple decimal integers
- whitespace insensitivity (i.e., one space and two spaces can be considered as different)
Unnatural provides four algorithms, all of which use Ruby's built-in quicksort as the fundamental sort algorithm. All four modules provide module methods .sort for simply sorting an enumerable, and .compare for spaceship-operator-style comparison.
Unnatural::Fast
Compares strings byte-by-byte. Comparison function implemented in C. Much faster than any of the pure Ruby options. The default, except on JRuby. Not available on JRuby.
Unnatural::Scan
Compares strings using a StringScanner. Pure ruby. Tends to be outperformed by Unnatural::Substitution and Unnatural::Split when sorting short strings via the global sort function, but its comparison function is the fastest of the pure-ruby algorithms.
Unnatural::Split
Compares strings by spliting them into arrays of alternating string and integer values. Pure Ruby. Tends to be outperformed by the others.
Unnatural::Substitution
Compares strings by zero-padding integer sequences such that all are the same length. Pure Ruby. Tends to be outperformed by Unnatural::Scan on longer strings. The default on JRuby.
Installation
Add this line to your application's Gemfile:
gem 'unnatural'
And then execute:
$ bundle
Or install it yourself as:
$ gem install unnatural
Usage
Sorting an enumerable of strings:
require 'unnatural'
sorted = Unnatural.sort(some_array_of_strings)
Defining the comparison method for a class explicitly:
require 'unnatural'
class User
def <=>(other)
Unnatural.compare(name, other.name)
end
end
Or by defining #to_str and using Unnatural as a mix-in:
# this is equivalent to the last example
class User
include Unnatural
def to_str
name
end
end
The default can be changed throughout an application:
# use Scan instead of Fast
# (or, if on JRruby, use Scan instead of Substitution)
Unnatural.algorithm = Unnatural::Scan
Or you can use the .compare and .sort functions for an algorithm's module directly:
sorted_short_strings = Unnatural::Substitution.sort(some_short_strings)
sorted_long_strings = Unnatural::Scan.sort(some_long_strings)
class User
def <=>(other)
Unnatural::Scan.compare(name, other.name)
end
end
See Also
There are two other natural sort gems:
https://github.com/dogweather/naturally
https://github.com/johnnyshields/naturalsort
Unnatural took test cases from each one.
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/bjmllr/unnatural. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.