Ruby switches

Let's say I have something like this

case
when "".empty? then puts "Empty"
when "".nil? then puts "Nil"
when "".include?("a") then puts "Includes 'a'"
end

Is there a way to do something like this instead? (This does not work
since the methods in the switches are acting on Object instead of "".)

case ""
when empty? then puts "Empty"
when nil? then puts "Nil"
when include?("a") then puts "Includes 'a'"
end

···

--
Posted via http://www.ruby-forum.com/.

Kenneth wrote:

Let's say I have something like this

case
when "".empty? then puts "Empty"
when "".nil? then puts "Nil"
when "".include?("a") then puts "Includes 'a'"
end

Is there a way to do something like this instead? (This does not work
since the methods in the switches are acting on Object instead of "".)

case ""
when empty? then puts "Empty"
when nil? then puts "Nil"
when include?("a") then puts "Includes 'a'"
end

case str
when "": puts "Empty"
when nil: puts "Nil"
when /a/: puts "Includes 'a'"
end

The case statement actually expands to the === operator, so this is
equivalent to

if "" === str
  puts "Empty"
elsif nil === str
  puts "Nil"
elsif /a/ === str
  puts "Includes 'a'"
end

The === operator does the "right thing" in each of these cases.

···

--
Posted via http://www.ruby-forum.com/\.

Hi, the point I was trying to make was sending a boolean method to the
case.

Let's say I have a User object and it has instance methods banned? and
activated? They are either true or false.

Instead of doing
case
when user.banned? then ...
when user.activated? then ...
end

I was hoping there would be something like
case user
when banned? then ...
when activated? then ...
end

I would like to see something like this but it seems hard to implement.

···

--
Posted via http://www.ruby-forum.com/.

I guess you can define a new method inside the class like this when
possible, as long as your then statements are nice.

class User
  def status
    case
    when banned? then ...
    when activated? then ...
    end
  end
end

···

--
Posted via http://www.ruby-forum.com/.

Kenneth wrote:

Hi, the point I was trying to make was sending a boolean method to the
case.

Then no, there is not a variant of the case statement which does this.

I was hoping there would be something like
case user
when banned? then ...
when activated? then ...
end

If you want to invoke method 'banned?' on a particular object, then you
have to send it to that object. A bare called to 'banned?' is invoked on
the current object (self).

But here are a couple of alternatives to consider:

user = Object.new
def user.banned?; false; end
def user.activated?; true; end

# Example 1

user.instance_eval {
  case
  when banned?; puts "Banned!"
  when activated?; puts "Activated!"
  end
}

# Example 2

[
  [:banned?, lambda { puts "Banned!" }],
  [:activated?, lambda { puts "Activated!" }],
].each do |method, action|
  user.send(method) && (action; break)
end

However if it's only a handful of conditions I'd be inclined to write

when user.banned?
when user.activated?

···

--
Posted via http://www.ruby-forum.com/\.

class User
  attr_accessor :banned

  def banned?
    banned
  end

  def active?
    not banned
  end
end

class Symbol
  def ===(other)
    other.send(self)
  end
end

a = User.new
a.banned = true

case a
when :banned? ; puts "banned!"
when :active? ; puts "active!"
end

a.banned = false

case a
when :banned? ; puts "banned!"
when :active? ; puts "active!"
end

martin

···

On Wed, Jul 7, 2010 at 6:23 PM, Kenneth <ken70r@gmail.com> wrote:

I was hoping there would be something like
case user
when banned? then ...
when activated? then ...
end

I would like to see something like this but it seems hard to implement.

Ah, and if you would absolutely respect the same syntax, it is
possible without changing self (but certainly not a good practice)

def method_missing(meth, *a, &b)
  lambda { |obj| obj.send(meth, *a, &b) }
end

case user
when banned?
  puts "Banned !"
when activated?
  puts "This is insane but you're fine!"
end

···

On 7 July 2010 15:53, Kenneth <ken70r@gmail.com> wrote:

Hi, the point I was trying to make was sending a boolean method to the
case.

Let's say I have a User object and it has instance methods banned? and
activated? They are either true or false.

Instead of doing
case
when user.banned? then ...
when user.activated? then ...
end

I was hoping there would be something like
case user
when banned? then ...
when activated? then ...
end

I would like to see something like this but it seems hard to implement.

I see. Thanks!

···

--
Posted via http://www.ruby-forum.com/.

user = Object.new
def user.banned?; false; end
def user.activated?; true; end

# Example 3

class Pred
  def initialize(sym)
    @sym = sym
  end
  def ===(other)
    other.send(@sym)
  end
end
def is(sym); Pred.new(sym); end
Banned = is(:banned?)
Activated = is(:activated?)

case user
when Banned; puts "Banned!"
when Activated; puts "Activated!"
end

···

--
Posted via http://www.ruby-forum.com/.

Quite cool the Symbol#===,
it made me think to Proc#===

Sadly, Proc need always a method to be created (so &:sym can not be
used directly)
But I found a (convoluted) example to use Proc#===

#encoding: utf-8
alias :λ :lambda

def check(user)
  case user
  when λ(&:banned?)
    puts "Banned !"
  when λ(&:active?)
    puts "This is over-convoluted, but you're fine!"
  end
end

user = User.new
user.banned = true
check user
user.banned = false
check user

···

On 7 July 2010 17:18, Martin DeMello <martindemello@gmail.com> wrote:

class User
attr_accessor :banned

def banned?
banned
end

def active?
not banned
end
end

class Symbol
def ===(other)
other.send(self)
end
end

a = User.new
a.banned = true

case a
when :banned? ; puts "banned!"
when :active? ; puts "active!"
end

a.banned = false

case a
when :banned? ; puts "banned!"
when :active? ; puts "active!"
end

martin

Thanks! The Symbol#=== way looks very cool!

···

--
Posted via http://www.ruby-forum.com/.