/usr/lib/ruby/vendor_ruby/fakeredis/sort_method.rb is in ruby-fakeredis 0.5.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | # Codes are mostly referenced from MockRedis' implementation.
module FakeRedis
module SortMethod
def sort(key, *redis_options_array)
return [] unless key
unless %w(list set zset).include? type(key)
warn "Operation against a key holding the wrong kind of value: Expected list, set or zset at #{key}."
raise Redis::CommandError.new("WRONGTYPE Operation against a key holding the wrong kind of value")
end
# redis_options is an array of format [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
# Lets nibble it back into a hash
options = extract_options_from(redis_options_array)
# And now to actually do the work of this method
projected = project(data[key], options[:by], options[:get])
sorted = sort_by(projected, options[:order])
sliced = slice(sorted, options[:limit])
# We have to flatten it down as redis-rb adds back the array to the return value
result = sliced.flatten(1)
options[:store] ? rpush(options[:store], sliced) : sliced.flatten(1)
end
private
ASCENDING_SORT = Proc.new { |a, b| a.first <=> b.first }
DESCENDING_SORT = Proc.new { |a, b| b.first <=> a.first }
def extract_options_from(options_array)
# Defaults
options = {
:limit => [],
:order => "ASC",
:get => []
}
if options_array.first == "BY"
options_array.shift
options[:by] = options_array.shift
end
if options_array.first == "LIMIT"
options_array.shift
options[:limit] = [options_array.shift, options_array.shift]
end
while options_array.first == "GET"
options_array.shift
options[:get] << options_array.shift
end
if %w(ASC DESC ALPHA).include?(options_array.first)
options[:order] = options_array.shift
options[:order] = "ASC" if options[:order] == "ALPHA"
end
if options_array.first == "STORE"
options_array.shift
options[:store] = options_array.shift
end
options
end
def project(enumerable, by, get_patterns)
enumerable.map do |*elements|
element = elements.flatten.first
weight = by ? lookup_from_pattern(by, element) : element
value = element
if get_patterns.length > 0
value = get_patterns.map do |pattern|
pattern == "#" ? element : lookup_from_pattern(pattern, element)
end
value = value.first if value.length == 1
end
[weight, value]
end
end
def sort_by(projected, direction)
sorter =
case direction.upcase
when "DESC"
DESCENDING_SORT
when "ASC", "ALPHA"
ASCENDING_SORT
else
raise "Invalid direction '#{direction}'"
end
projected.sort(&sorter).map(&:last)
end
def slice(sorted, limit)
skip = limit.first || 0
take = limit.last || sorted.length
sorted[skip...(skip + take)] || sorted
end
def lookup_from_pattern(pattern, element)
key = pattern.sub('*', element)
if (hash_parts = key.split('->')).length > 1
hget hash_parts.first, hash_parts.last
else
get key
end
end
end
end
|