Invalid function in ruby

前端 未结 3 363
眼角桃花
眼角桃花 2020-12-02 01:12

Why is this function invalid?

def request(method=\'get\',resource, meta={}, strip=true)

end

unexcpected \')\' expecting keyword_end

<
相关标签:
3条回答
  • 2020-12-02 01:29

    Try reordering your parameters:

    def Request(resource,strip=true,method='get',meta={})
    end
    
    0 讨论(0)
  • 2020-12-02 01:35

    You can only have one group of optional parameters in a parameter list.

    A pseudo-regex for parameter lists in Ruby is something like this:

    mand* opt* splat? mand* (mand_kw | opt_kw)* kwsplat? block?
    

    Here's an example:

    def foo(m1, m2, o1=:o1, o2=:o2, *splat, m3, m4, 
              ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk)
      Hash[local_variables.map {|var| [var, eval(var.to_s)] }]
    end
    
    method(:foo).arity
    # => -5
    
    method(:foo).parameters
    # => [[:req, :m1], [:req, :m2], [:opt, :o1], [:opt, :o2], [:rest, :splat], 
    #     [:req, :m3], [:req, :m4], [:keyreq, :mk1], [:keyreq, :mk2], 
    #     [:key, :ok1], [:key, :ok2], [:keyrest, :ksplat], [:block, :blk]]
    
    foo(1, 2, 3, 4)
    # ArgumentError: missing keywords: mk1, mk2
    
    foo(1, 2, 3, mk1: 4, mk2: 5)
    # ArgumentError: wrong number of arguments (3 for 4+)
    
    foo(1, 2, 3, 4, mk1: 5, mk2: 6)
    # => { m1: 1, m2: 2, o1: :o1, o2: :o2, splat: [], m3: 3, m4: 4, 
    #      ok1: :ok1, mk1: 5, mk2: 6, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, mk1: 6, mk2: 7)
    # => { m1: 1, m2: 2, o1: 3, o2: :o2, splat: [], m3: 4, m4: 5, 
    #      ok1: :ok1, mk1: 6, mk2: 7, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, mk1: 7, mk2: 8)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [], m3: 5, m4: 6, 
    #      ok1: :ok1, mk1: 7, mk2: 8, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, mk1: 8, mk2: 9)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5], m3: 6, m4: 7, 
    #      ok1: :ok1, mk1: 8, mk2: 9, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, mk1: 9, mk2: 10)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: :ok1, mk1: 9, mk2: 10, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13, k4: 14)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, 
          ok1: 9, ok2: 10, mk1: 11, mk2: 12, k3: 13, k4: 14) do 15 end
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
    #      blk: #<Proc:0xdeadbeefc00l42@(irb):15> }
    

    [Note: mandatory keyword arguments will be introduced in Ruby 2.1, all the rest already works.]

    0 讨论(0)
  • 2020-12-02 01:41

    In Ruby, you can't surround a required parameter with optional parameters. Using

    def request(resource, method='get', strip=true, meta={})
    end
    

    will solve the issue.

    As a thought experiment, consider the original function

    def request(method='get',resource, meta={}, strip=true)
    end
    

    If I call that method as request(object), the desired behavior is fairly obvious -- call the method with object as the resource parameter. But what if I call it as request('post', object)? Ruby would need to understand the semantics of method to decide whether 'post' is the method or the resource, and whether object is the resource or the meta. This is beyond the scope of Ruby's parser, so it simply throws an invalid function error.

    A couple additional tips:

    I would also put the meta argument last, which allows you to pass the hash options in without curly braces, such as:

    request(object, 'get', true, foo: 'bar', bing: 'bang')
    

    As Andy Hayden pointed out in the comments, the following function works:

    def f(aa, a='get', b, c); end
    

    It's generally good practice to place all your optional parameters at the end of the function to avoid the mental gymnastics required to follow calls to a function like this.

    0 讨论(0)
提交回复
热议问题