2014-10-22 4 views
0

Я разработал класс NumberSet, который содержит массив, на котором я должен реализовать определенные фильтры, которые я разработал как классы. Код:Объединение фильтров в Ruby

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 && number<0) 
    return true if(@sign==:positive && number>0) 
    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 

Все работает хорошо, но я должен также определить & и | операторов, чтобы они работают как пересечения и объединения, что означает, что & должны получить только числа, которые удовлетворяют все фильтры и | числа, которые удовлетворяют по крайней мере, один из фильтров.

Кроме того, синтаксис

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

должен быть действительным.

Как определить их, чтобы они работали правильно?


Чтобы ответить на некоторые замечания, я ищу способ, чтобы операторы &, | работу так, как я хочу их. Проблема заключается не в том, как написать синтаксис, а в том, что должен делать код между def и end be.

+0

Почему у вас возникли проблемы с определением этих методов? – Brennan

+0

@Brennan Потому что я не могу понять логически, как это сделать. – user103220

+0

Вы можете определить их как любой другой метод: 'def &(arg); arg + 10; end', но вы должны называть их, используя send: 'self.send (« & », 10)' – Brennan

ответ

0

Вы можете определить их так же, как и любой другой метод. Я просто попытался это как пример:

class Adder 
    def &(number_to_add) 
     number_to_add + 20 
    end 
end 

a = Adder.new 
a & 20 
#=> 40 
+0

Я знаю, как их определить. Я не знаю, как они должны действовать между 'def' и' end'. Чтобы было лучше, что должен сделать метод '&', чтобы я мог объединить эффект двух фильтров? – user103220

0

Так же, как примечание, потому что это выглядит как запах:

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?) или определить методы индивидуально. Я знаю, что это не ответ на ваш реальный вопрос. Мне просто нравится чистый код. :)

+0

Почему '@@ знаки' вместо' SIGNS', или даже лучше, опускать это полностью и просто перебирать хеш напрямую? – tadman

0

Вот что-то медитировать на ...

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 видит true, которое будет возвращено. Если первый сбой, || скажет Ruby, чтобы проверить следующее, и вниз по цепочке.

Это подражает поведению исходного кода, но есть и проблема. В успешном результате возвращается true. Неудача будет нулевой. Это то, что вы хотите, или вы хотите, чтобы false возвращался, чтобы заставить метод возвращать true/false? В Ruby nil это значение «false», поэтому оно будет работать одинаково, но для согласованности вы можете вернуть true/false.

Кроме того, в качестве рекомендации в стиле кодирования используйте пробелы между операторами.

@sign==:negative && number<0 

не читаемые, как

@sign == :negative && number < 0 

читаемость очень важна при отладке, или после прохождения коды на кого-то другое для обслуживания. Людям нравится говорить, что они исправит это позже, но позже придет, код остается тем же самым и попадает в производство, где он ждет, чтобы раздражать бедную душу в 3 утра.

0

Как насчет этого?

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 
Смежные вопросы