comparison operations in case statements

Discussion in 'Ruby' started by Joel VanderWerf, Jan 14, 2006.

  1. This looks kind of cute, as a way to mix class-matching tests with
    comparison operator tests in case statements. Too bad it's not really
    practical (the commented out caching may help a bit, but may also use
    too much memory):

    class Comparator < Proc
    def ===(val)
    call val
    end

    def &(other)
    compare do |val|
    self[val] and other[val]
    end
    end
    end

    def compare
    Comparator.new
    end

    class Numeric
    #@comparator_lt = {}
    def self.<(x)
    #@comparator_lt[x] ||=
    compare do |val|
    self === val and val < x
    end
    end

    #@comparator_gt = {}
    def self.>(x)
    #@comparator_gt[x] ||=
    compare do |val|
    self === val and val > x
    end
    end
    end


    raise unless (Numeric < 6) === 3
    raise if (Integer < 6) === 2.3
    raise if (Integer < 6) === "foo"

    case 3
    when (Numeric < 6) & (Numeric > 5); raise
    when (Numeric < 0) & (Numeric > -10); raise
    when (Numeric < 6) & (Numeric > 2)
    else raise
    end
     
    Joel VanderWerf, Jan 14, 2006
    #1
    1. Advertisements

  2. Neat. Seems a little redundant though

    raise unless Numeric === 3
    case
    when 3 < 6 and 3 > 5; raise
    when 3 < 0 and 3 > -10; raise
    when 3 < 6 and 3 > 2
    else raise
    end

    I'm presuming nine times out of ten the variable you'll run these
    tests on will have less characters than Numeric for instance.

    eg:
    x = 3
    raise unless Numeric === x
    case
    when x > 2; ...
    end
     
    Logan Capaldo, Jan 14, 2006
    #2
    1. Advertisements

  3. This doesn't allow for arbitrary chaining. You would rather have to return
    something that overloads & as well. But that will be difficult in the light
    of the last value returned (you don't know that it's the last value in the
    method).
    I'd prefer the more general approach as I suggested a while back already:

    module Kernel
    private
    condition(&cond)
    class<<cond
    alias :=== :call
    end
    cond
    end
    end

    Then you can do

    case 3
    when condition {|x| x<6 && x>5}; ...

    end

    or

    LESS_THAN_6_AND_GREATER_THAN_5 = condition {|x| x<6 && x>5}

    case 3
    when LESS_THAN_6_AND_GREATER_THAN_5; ...
    ....

    or better

    ILLEGAL = condition {|x| x<6 && x>5 or ...}

    case x
    when ILLEGAL; raise ...
    ....

    Of course this looks silly in this case, but in more reasonable cases it
    doesn't. For example

    NEGATIVE = condition {|x|x<0}
    EVEN = condition {|x| x%2==0}

    case x
    when NEGATIVE; raise "error!"
    when EVEN; puts "found an even number"
    end

    which reads nicely.

    Kind regards

    robert
     
    Robert Klemme, Jan 14, 2006
    #3
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.