Class: NaturalSort::Key
- Inherits:
-
Object
- Object
- NaturalSort::Key
- Includes:
- Comparable
- Defined in:
- lib/natural_sort/key.rb
Overview
A precomputed, comparable sort key. Wrap a value with NaturalSort.key (or the NaturalSort() helper) and use it as a sort_by key:
array.sort_by { |string| NaturalSort.key(string) }
The string is split once, on construction: digit runs with no leading zero become Integers (compared by value); everything else — text, and digit runs with a leading zero — stays a String (compared by byte value). Whitespace is skipped. This reproduces Martin Pool’s strnatcmp ordering.
Splitting runs over the raw bytes, so any input sorts by byte value rather than raising — including malformed encodings (e.g. Latin-1 bytes mislabeled UTF-8) and ASCII-incompatible ones (UTF-16/UTF-32). For valid UTF-8, byte order and codepoint order agree, so this changes ordering for no one.
Instance Method Summary collapse
-
#<=>(other) ⇒ Integer?
Three-way comparison.
-
#eql?(other) ⇒ Boolean
Equal keys (same token list) hash alike and collapse in a Hash, Set, or #uniq — consistent with #== / #<=>, since segments are equal exactly when the comparison is 0.
- #hash ⇒ Integer
-
#initialize(input) ⇒ Key
constructor
A new instance of Key.
- #to_s ⇒ Object
Constructor Details
#initialize(input) ⇒ Key
Returns a new instance of Key.
30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/natural_sort/key.rb', line 30 def initialize(input) @input = input.to_s.dup.freeze @segments = @input.b.scan(TOKENIZER).filter_map do |token| if token.match?(WHITESPACE) nil elsif NUMERIC.match?(token) Integer(token) else token end end.freeze freeze end |
Instance Method Details
#<=>(other) ⇒ Integer?
Three-way comparison. Numeric segments (Integers) compare by value when paired with another numeric segment; in every other pairing both sides compare by byte value. A non-zero-leading integer’s #to_s is its original digits, so the cross-type byte comparison stays exact.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/natural_sort/key.rb', line 54 def <=>(other) return nil unless other.is_a?(Key) mine = segments theirs = other.segments index = 0 while index < mine.length right = theirs[index] return 1 if right.nil? left = mine[index] result = if left.is_a?(Integer) right.is_a?(Integer) ? left <=> right : left.to_s <=> right else right.is_a?(Integer) ? left <=> right.to_s : left <=> right end return result unless result.zero? index += 1 end theirs.length > mine.length ? -1 : 0 end |
#eql?(other) ⇒ Boolean
Equal keys (same token list) hash alike and collapse in a Hash, Set, or #uniq — consistent with #== / #<=>, since segments are equal exactly when the comparison is 0.
85 86 87 |
# File 'lib/natural_sort/key.rb', line 85 def eql?(other) other.is_a?(Key) && segments == other.segments end |
#hash ⇒ Integer
90 91 92 |
# File 'lib/natural_sort/key.rb', line 90 def hash segments.hash end |
#to_s ⇒ Object
44 45 46 |
# File 'lib/natural_sort/key.rb', line 44 def to_s @input end |