Skip to content

Instantly share code, notes, and snippets.

@wjlroe
Created April 25, 2018 16:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wjlroe/87cf44cbcf3101fc09315411c81037c9 to your computer and use it in GitHub Desktop.
Save wjlroe/87cf44cbcf3101fc09315411c81037c9 to your computer and use it in GitHub Desktop.
Riddle me this: How can you compose sort_by in Ruby?
require 'minitest/autorun'
class ComposableSort
def initialize(stuff)
@stuff = stuff
end
def sorted
@stuff.sort_by { |item|
criteria.flat_map { |criterium| criterium.call(item) }
}
end
end
class SortByName < ComposableSort
def criteria
[->(item) { [item.name] }]
end
end
class SortByNameThenScore < SortByName
def criteria
super + [->(item) { [-(item.score || -1)] }]
end
end
StuffThing = Struct.new(:name, :score)
describe SortByNameThenScore do
it 'sorts first by name' do
a_name = StuffThing.new('AA', 43)
b_name = StuffThing.new('BB', 43)
stuff = [b_name, a_name]
sorter = SortByNameThenScore.new(stuff)
sorter.sorted.must_equal([a_name, b_name])
end
it 'sorts secondarily by score' do
a_score = StuffThing.new('AA', 45)
b_score = StuffThing.new('AA', 20)
stuff = [b_score, a_score]
sorter = SortByNameThenScore.new(stuff)
sorter.sorted.must_equal([a_score, b_score])
end
it 'sorts also with structs' do
high_score = StuffThing.new('AA', 50)
no_score = StuffThing.new('AA', nil)
stuff = [no_score, high_score]
sorter = SortByNameThenScore.new(stuff)
sorter.sorted.must_equal([high_score, no_score])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment