Last active
December 24, 2015 13:09
-
-
Save bhb/6802338 to your computer and use it in GitHub Desktop.
A toy example of defining filter and sorting operations in one place (on a class) while still keeping collections generic.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# An idea on how to sort and filter Ruby collections in a functional | |
# style | |
# Just using Struct for convenience, this could be a normal class. | |
User = Struct.new(:first_name, :last_name, :admin) do | |
def self.sort_by_name | |
# Define a new sort | |
lambda do |x,y| | |
# last name, first name DESC | |
(y.last_name + " " + y.first_name) <=> (x.last_name + " " + x.first_name) | |
end | |
end | |
def self.default_sort | |
sort_by_name | |
end | |
def self.not_admin | |
lambda { |x| !x.admin } | |
end | |
end | |
joe = User.new("Joe", "Smith", false) | |
bob = User.new("Bob", "Jones", true) | |
alice = User.new("Alice", "Fields", false) | |
arr = [joe, bob, alice] | |
# The logic for selection is within class | |
puts arr.select(&User.not_admin).inspect | |
# The logic for sorting is also in one place in the class | |
puts arr.sort(&User.sort_by_name).inspect | |
puts arr.sort(&User.default_sort).inspect |
Yeah, my initial thought was that you'd have to pass in the specific sort in the controller every time (but the definition of how to sort
would be kept on the class so it's defined once), but certainly you could even have the collection defer to the first element.
# haven't actually run this ...
class AwesomeArray < Array
alias_method :old_sort, :sort
def sort(&block)
if block
old_sort(&block)
else
sort(&first.class.default_sort)
end
end
end
AwesomeArray.new([joe, bob, alice]).sort
or pass in a set of defaults
# haven't actually run this ...
class AwesomeArray < Array
def with_defaults=(d)
@defaults = d
self
end
alias_method :old_sort, :sort
def sort(&block)
if block
old_sort(&block)
elsif @defaults
old_sort(&@defaults.default_sort)
end
end
end
AwesomeArray.new([joe, bob, alice]).with_defaults(User).sort
Yes, maybe you need to make a new collection type that supports this, but the point is that you can use the same collection type for Books or Users or Cars or anything else.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
interesting so basically in some controller you would have your collection and still call .sort, but you could pass in some shared module with predefined sorts on it. Default sort could even inspect arr[0] and select an appropriate default sort or something