sortsmith 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Extensions to Ruby's built-in Enumerable module.
5
+ #
6
+ # Sortsmith extends {Enumerable} to provide enhanced sorting capabilities
7
+ # while preserving the original behavior when used with blocks.
8
+ #
9
+ # The key enhancement is allowing `sort_by` to be called without a block,
10
+ # which returns a {Sortsmith::Sorter} instance for method chaining.
11
+ #
12
+ # @example Original behavior (unchanged)
13
+ # [1, 2, 3].sort_by { |n| -n }
14
+ # # => [3, 2, 1]
15
+ #
16
+ # @example New chainable behavior
17
+ # users.sort_by.dig(:name).downcase.sort
18
+ # # => Returns Sorter instance for chaining
19
+ #
20
+ # @see Sortsmith::Sorter The chainable sorting interface
21
+ #
22
+ module Enumerable
23
+ ##
24
+ # Stores the original sort_by method before extension.
25
+ #
26
+ # This alias preserves Ruby's original `sort_by` behavior, allowing
27
+ # Sortsmith to enhance the method while maintaining full backward
28
+ # compatibility when blocks are provided.
29
+ #
30
+ # @see #sort_by The enhanced version
31
+ # @api private
32
+ #
33
+ alias_method :og_sort_by, :sort_by
34
+
35
+ ##
36
+ # Enhanced sort_by that supports both traditional block usage and direct field extraction.
37
+ #
38
+ # This method extends Ruby's built-in `sort_by` to provide a fluent, chainable API
39
+ # for sorting operations. When called with a block, it behaves exactly like the
40
+ # original `sort_by`. When called without a block, it returns a {Sortsmith::Sorter}
41
+ # instance for method chaining.
42
+ #
43
+ # The direct syntax (`sort_by(field)`) provides a concise way to sort by a specific
44
+ # field or method without verbose chaining, making simple sorting operations more
45
+ # readable and intuitive.
46
+ #
47
+ # @param field [Symbol, String, nil] Optional field name for direct extraction
48
+ # @param positional [Array] Additional positional arguments for extraction
49
+ # @param keyword [Hash] Additional keyword arguments for extraction
50
+ # @param block [Proc, nil] Optional block for traditional sort_by behavior
51
+ #
52
+ # @return [Array, Sortsmith::Sorter] Array when block given, Sorter instance otherwise
53
+ #
54
+ # @example Traditional block usage (unchanged)
55
+ # users.sort_by { |user| user.name.downcase }
56
+ # # => sorted array
57
+ #
58
+ # @example Direct field syntax (new)
59
+ # users.sort_by(:name).insensitive.sort
60
+ # # => sorted array via method chaining
61
+ #
62
+ # @example Direct syntax with immediate result
63
+ # users.sort_by(:score).desc.first(3)
64
+ # # => top 3 users by score
65
+ #
66
+ # @example Chainable interface without field
67
+ # users.sort_by.dig(:profile, :email).sort
68
+ # # => sorted by nested email field
69
+ #
70
+ # @example Mixed key types
71
+ # mixed_data = [
72
+ # { name: "Bob" }, # symbol key
73
+ # { "name" => "Alice" } # string key
74
+ # ]
75
+ # mixed_data.sort_by(:name, indifferent: true).sort
76
+ # # => handles both key types gracefully
77
+ #
78
+ # @example Object method sorting
79
+ # products.sort_by(:calculate_price).desc.sort
80
+ # # => sorted by calculated price method
81
+ #
82
+ # @example Dynamic field selection
83
+ # sort_field = params[:sort_by] # might be nil
84
+ # users.sort_by(sort_field).sort
85
+ # # => gracefully handles nil field
86
+ #
87
+ # @example Integration with enumerable methods
88
+ # users.sort_by(:created_at).desc.take(10)
89
+ # # => newest 10 users without breaking the chain
90
+ #
91
+ # @raise [ArgumentError] When extraction results in incomparable types
92
+ #
93
+ # @note This method maintains full backward compatibility with Ruby's original sort_by
94
+ # @note When field is nil, returns a plain Sorter instance for manual chaining
95
+ #
96
+ # @see Sortsmith::Sorter The chainable sorting interface
97
+ # @see #extract Universal extraction method
98
+ # @see Enumerable#sort_by Original Ruby method (aliased as og_sort_by)
99
+ # @since 1.0.0
100
+ #
101
+ def sort_by(field = nil, *positional, **keyword, &block)
102
+ return og_sort_by(&block) if block
103
+
104
+ sorter = Sortsmith::Sorter.new(self)
105
+ return sorter if field.nil?
106
+
107
+ sorter.extract(field, *positional, **keyword)
108
+ end
109
+ end