Search code examples
rubycamping

Parent class definition with arguments


I was browsing the camping documentation, and I ran into this example for defining a controller:

class Digits < R '/nuts/(\d+)'
  def get(number)
    "You got here by: /nuts/#{number}"
  end
end

It looks like what this class definition is doing is that it's passing a string argument to the R superclass. However, I looked through the camping codebase and I didn't see R defined as a class anymore. It was defined as a method like this:

def R(c,*g)
  p,h=/\(.+?\)/,g.grep(Hash)
  g-=h
  raise "bad route" if !u = c.urls.find{|x|
    break x if x.scan(p).size == g.size && 
      /^#{x}\/?$/ =~ (x=g.inject(x){|x,a|
        x.sub p,U.escape((a.to_param rescue a))}.gsub(/\\(.)/){$1})
  }
  h.any?? u+"?"+U.build_query(h[0]) : u
end

and the method to actually handle the route:

def /(p); p[0] == ?/ ? @root + p : p end

I don't understand exactly how this works, because when I tried to make a class and define a method as a superclass, like this:

def doSomething(boo)
    puts boo
end

class Someclass < doSomething 'boo'
end

I get this error:

(eval):60: (eval):60: superclass must be a Class (NilClass given) (TypeError)

Can someone point me to where in the ruby documentation this feature (using a method as a superclass) is covered? I don't know what to call this feature, so my googling efforts couldn't really find me anything.


Solution

  • You'll have to return a class from your method:

    def doSomething(boo)
      Class.new { define_method(:boo) { boo } }
    end
    
    class SomeClass < doSomething 'boo'
    end
    
    SomeClass.new.boo # => 'boo'
    

    You're also looking at the wrong method. Camping has a class method on Controllers called R (that's the one used when defining controllers) and an instance method on Base called R (for generating routes). This is the actual definition: https://github.com/camping/camping/blob/ae5a9fabfbd02ba2361ad8831c15d723d3740b7e/lib/camping-unabridged.rb#L551