问题描述
|
RailsWizard是一种生成Rails模板的工具,它可以通过指定要在给定配方之前(
run_before
选项)和之后(ѭ1which)运行哪些配方来设置配方顺序,如https://github.com/intridea/rails_wizard/wiki/中所述配方配置
这是在“ 2”类中实现的:
module RailsWizard
class Recipe
extend Comparable
def self.<=>(another)
return -1 if another.run_after.include?(self.key) || self.run_before.include?(another.key)
return 1 if another.run_before.include?(self.key) || self.run_after.include?(another.key)
self.key <=> another.key # simple sort by name
end
end
end
但是,此算法通常会提供错误的顺序,请参见相应的问题以及此问题的演示脚本:https://gist.github.com/987025
您将如何解决此算法?
解决方法
该算法的问题在于比较运算符未定义严格弱排序。
具体来说,它缺乏传递性(如果x
before?比较运算符的代码。
require \'yaml\'
hash = YAML.load \'
a:
after:
before:
l:
after:
before:
n:
after:
before: l
b:
after:
before:
m:
after:
before:
c:
after:
before:
z:
after:
before:
\'
hash.each do |k,v|
v.each do |vk,vv|
v[vk] = (vv||\'\').split
end
end
class Hash
def without *ks
delete_if { |k,v| ks.include? k }
end
def delete! *ks
#print \"\\n\\nwithout: #{ks.join(\',\')}\"
replace without *ks
end
end
def print_keys hash
puts hash.map(&:first).join(\' \')
end
def sort hash
array = hash.to_a
selection_sort array
print_keys array
Hash[array]
end
def selection_sort array
(0...array.length).each do |i|
min = i
((i+1)...array.length).each do |j|
min = j if before?(array[j],array[min])
end
temp = array[min]
array[min] = array[i]
array[i] = temp
end
end
def before? a,b
b.last[\'after\'].include?(a.first) || a.last[\'before\'].include?(b.first)
end
def test hash
puts nil,nil
print_keys hash
puts \'-\'*hash.count*3
hash.count.times { hash = sort hash }
end
test hash
这给出了:
$ ruby sort_test.rb
a l n b m c z
---------------------
a n l b m c z
a n l b m c z
a n l b m c z
a n l b m c z
a n l b m c z
a n l b m c z
a n l b m c z