Ruby中的filter联盟

我设计了一个NumberSet类,它包含一个数组,我必须在其上实现某些filter,我将其设计为类。 代码是:

class NumberSet include Enumerable def initialize @arr=[] end def each (&block) @arr.each do |member| block.call (member) end end def << number @arr<<number unless @arr.include?(number) end def [] (sito) @arr.select{|number| sito.filter(number)} end end class Filter attr_reader :filter def initialize &block @filter = block end def filter number @filter.call(number) end end class SignFilter def initialize(sign) @sign = sign end def filter number return true if(@sign==:negative && number0) return true if(@sign==:nonnegative && number >= 0) return true if(@sign==:nonpositive && number <= 0) end end class TypeFilter def initialize(sign) @sign = sign end def filter number return true if (@sign==:complex && number.is_a?(Complex) == true) return true if (@sign==:integer && number.is_a?(Integer) == true) return true if (@sign==:real && (number.is_a?(Rational) == true || number.is_a?Float) == true)) end end 

一切运作良好,但我还要定义&| 运算符使它们像交集和并集一样工作,这意味着&应该只获得满足所有filter和| 满足至少一个filter的数字。

另外,语法

 numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }] 

必须有效。

如何定义它们以使它们正常工作?


为了回答一些评论,我正在寻找一种方法来制作运营商&| 以我想要的方式工作。 问题不在于如何编写语法,而是defend之间的代码应该是什么。

您可以像任何其他方法一样定义它们。 我只是试着这个例子:

 class Adder def &(number_to_add) number_to_add + 20 end end a = Adder.new a & 20 #=> 40 

就像一张纸条,因为这看起来像是气味:

 def filter number return true if(@sign==:negative && number<0) return true if(@sign==:positive && number>0) return true if(@sign==:nonnegative && number >= 0) return true if(@sign==:nonpositive && number <= 0) end 

为什么试试这个:

 class SignFilter @@signs = {negative: "<", positive: ">", nonnegative: ">=", nonpositive: "<="} @@signs.each do |meth,sign| define_method meth do |number| number.send(sign,0) end end def initialize(sign) @sign = sign end def filter(number) self.public_send(@sign,number) end end 

您可以使用TypeFilter执行相同操作(作为提示Numeric具有#real?方法)或单独定义方法。 我知道这不是你的实际问题的答案,我只是喜欢干净的代码。 🙂

这是冥想的东西……

 def filter number return true if(@sign==:negative && number<0) return true if(@sign==:positive && number>0) return true if(@sign==:nonnegative && number >= 0) return true if(@sign==:nonpositive && number <= 0) end 

可以写成:

 def filter number ( @sign == :negative && number < 0 ) || ( @sign == :positive && number > 0 ) || ( @sign == :nonnegative && number >= 0 ) || ( @sign == :nonpositive && number <= 0 ) end 

为什么? 因为每个测试都返回true或false。 如果一个返回true,则没有其他人通过||加入 将进行测试,因为|| 短路,Ruby看到的最终值将是真的,将返回。 如果第一个失败, || 将告诉Ruby检查下一个,并在链上。

这模仿了原始代码的行为,但两者都存在问题。 在成功的结果中,返回true。 失败将是零。 这是你想要的,还是你想要返回false使方法只返回true / false? 在Ruby中,nil是一个“假”值,因此它的工作方式相同,但为了保持一致性,您可能只想返回true / false。

此外,作为编码式推荐,请在运算符之间使用空格。

 @sign==:negative && number<0 

不像是那样可读

 @sign == :negative && number < 0 

在调试时或将代码传递给其他人进行维护之后,可读性非常重要。 人们喜欢说他们以后会修复它,但后来,代码保持不变并被投入生产,等待在凌晨3点激怒一些可怜的灵魂。

这样的事怎么样?

 class Filter def initialize(&filter_block) @filter_block = filter_block end def filter(number) @filter_block.call(number) end def &(other) CompositeFilterAND.new(self, other) end def |(other) CompositeFilterOR.new(self, other) end end class CompositeFilterAND attr_accessor :left, :right def initialize(left, right) @left, @right = left, right end def filter(number) @left.filter(number) && @right.filter(number) # This is the magic. end end class CompositeFilterOR attr_accessor :left, :right def initialize(left, right) @left, @right = left, right end def filter(number) @left.filter(number) || @right.filter(number) # And this. end end