将if / else转换为case /何时在ruby中

时间:2016-03-21 17:15:51

标签: ruby

我跟随Ryan Bates的RC#386 - 授权。 Ryan的原始代码如下:

module Permissions
  def self.permission_for(user)
    if user.nil?
      GuestPermission.new
    elsif user.is_admin?
      AdminPermission.new(user)
    else
      MemberPermission.new(user)
    end
  end
end

按预期工作。

我需要允许的不仅仅是三种授权方案。我需要添加其他授权角色,例如EditorModeratorSenior Editor等。我正在尝试将其更改为case - 语句。我的代码是:

module Permissions
  def self.permission_for(user)
    case user#.role  #TODO: This will eventually be refactored into a role checker...
    when user.is_admin?
       AdminPermission.new(user)
    when user.current_user
       MemberPermission.new(user)
    else
       GuestPermission.new
    end
  end
end

但是,我在

上遇到NoMethod错误
when user.is_admin?

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

case user
when ->(u) { u.is_admin? } then AdminPermission.new(user)
when ->(u) { u.current_user } then MemberPermission.new(user)
else GuestPermission.new
end

case 
when user.is_admin? then AdminPermission.new(user)
when user.current_user then MemberPermission.new(user)
else GuestPermission.new
end

前者使用Proc#===,后者是一个没有初始条件的完全有效的案例。

答案 1 :(得分:2)

case / when阻止case / case some_relatively_expensive_operation() when :foo # ... when :bar # ... end 阻止的主要优势 - 以及优势 - some_relatively_expensive_operation中的条件将是只运行一次,只运行一次。

所以在这种情况下:

if some_relatively_expensive_operation() == :foo
  # ...
elsif some_relatively_expensive_operation() == :bar
  # ...
end

some_relatively_expensive_operation()只会运行一次,而在这种情况下:

:foo

if将运行一次(如果是elsif)或两次(如果是其他的话)。

这不仅仅关系到性能,它还使得条件以后更容易更改,因为您只需要这样做一次,而不是有多少user / User块。

显然,如果你想测试不同的多个条件,这个结构根本不起作用 - 这是你当前代码正在做的事情。是的,你可以用一个lambda来解决这个问题,这是另一个答案所做的,但这完全忽略了这个结构的意义,就像用锤子钉在钉子上一样。

所以你需要做的是向对象class User # [..] def role if is_admin? :admin else :member end end end 添加一个方法,该方法返回一个带有该角色的值。我对您的case模型没有任何见解,但这很简单:

def self.permission_for(user)
  # No current user - return Guest permissions
  return GuestPermission.new unless user.current_user

  case user.role
    when :admin
      AdminPermission.new(user)
    when :member
      MemberPermission.new(user)
   end
end

我们仍然需要检查特殊访客权限案例,可以在主<{1}}之前完成:

User.role

或者,您可以修改:guest以返回case。无论你喜欢什么。

现在,您会注意到这些线条实际上看起来非常相似。为什么要在这里使用when / user.role块?我们不能只从 # Get instance to the class klass = Object.const_get "#{user.role.to_s.capitalize}Permission" # And create it! klass.new user 构建类名吗?是的,我们可以!

def self.permission_for(user)
  return GuestPermission.new unless user.current_user
  return Object.const_get("#{user.role.to_s.capitalize}Permission").new user
end

我们可以为此制作一个双线方法!

User.role

如果没有当前用户,如果:guest返回proceedure TForm1.Timer1Timer(Sender: TObject);` begin TTask.Run(procedure var i: integer; begin for i:=0 to 50 do begin TThread.Synchronize(TThread.CurrentThread, procedure begin Memo1.Lines.Add(i.ToString); Sleep(500); end); end; end); end; ,即使是一行。

答案 2 :(得分:0)

Case语句检查每个when子句的相等性,例如

case x
   when 1
      puts "Do something when x === 1."
   when "D"
      puts "Do something when x === D."
   else
      puts "Doing nothing"
end

因此,对于您的示例,您希望保留if / then样式语法或执行以下操作:

case user.role
   when :guest
      #something
   when :admin
      #something
   #etc...
end  

http://ruby-doc.org/docs/keywords/1.9/Object.html#method-i-case