How to determine if optional arguments are passed in Ruby

送分小仙女□ 提交于 2019-12-10 13:56:22

问题


If I have the following method in Ruby:

def foo(arg1, arg2 = "bar")
  puts arg1
  puts arg2
end

Is there a way of determining if a user passed a value in for arg2 within the method? Obviously I could just add if arg2 == "bar" to the method, but this doesn't catch the case where the user manually passed in "bar" herself. Of course, I could set the default to be something that no user would ever pass in, but then that gets pretty ugly pretty quickly.

Is there anything elegant out there?


回答1:


I am not sure this is possible. Consider the following:

class Test
  def method(a,b=1)
    local_variables.each do |var|
          puts "Setting #{var} to #{eval var.to_s}"
    end
  end
end

And then try to call method on an instance of Test:

?> t.method(1)
Setting a to 1
Setting b to 1
=> [:a, :b]

?> t.method(1,2)
Setting a to 1
Setting b to 2
=> [:a, :b]

?> t.method(1,1)
Setting a to 1
Setting b to 1
=> [:a, :b]

Those do not distinguish how the method was called.

So I would suggest @sawa's approach mixed with the following:

raise ArgumentError, "Too many arguments" if args.length > 2

since you seem to want to limit the parameters to 2 and @sawa's approach allows for an undefined number.

This is an unorthodox approach to an unorthodox requirement, so just make sure the clients of your method are aware of how the API works.




回答2:


def foo(arg1, arg2 = (arg2_not_passed = true; "bar"))
  puts arg1
  puts arg2
  puts 'arg2 was passed' unless arg2_not_passed
end



回答3:


def foo(*args)
  case args.length
  when 1
    # arg2 was not given
    arg1, arg2 = args.first, "bar"
    ...
  when 2
    # arg2 was given
    arg1, arg2 = args
    ...
  else
    raise ArgumentError
  end
end



回答4:


One way (not elegant but fun) is to make the default value such that it has a unique object_id. It wil not work if default value is an immutable object like integer.

def c
  @c ||= "bar"
end

def fun(a,b = c)   
     puts  b.object_id == c.object_id ? "default" : "user" 
end

fun "foo"
#=> "default"

fun "foo", "bar"
#=> "user"



回答5:


I have a solution! Suppose we want:

def foo(arg1, arg2 = 42)

Then we would instead write:

def foo(arg1, arg2 = [42,KEY])

If agr2 == [42,KEY], we conclude that the calling method did not pass a second argument, in which case the default of 42 applies. If arg2 is anything else, arg2 was passed. Simple!

I know what you're thinking: what if the calling program were to actually pass [42,KEY]? I have that figured out too: KEY = rand(100000000000000).

I would like to add one more thing. I am in principal opposed to doing so, but I know if I don't I will receive so many downvotes that my reputation will go negative. So here it is: :-)



来源:https://stackoverflow.com/questions/19472413/how-to-determine-if-optional-arguments-are-passed-in-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!