Get Parameter names from methods

Discussion in 'Ruby' started by Sam Smoot, Jun 15, 2007.

  1. Sam Smoot

    Sam Smoot Guest

    Oft asked for, here you go:

    > module Kernel
    >
    > PARAMETERIZED_CLASSES = {}
    >
    > def parameterized_require(libpath)
    > libpath = libpath + '.rb' unless libpath =~ /\.rb$/
    >
    > load_path = $LOAD_PATH.find do |search_path|
    > File.exists?(File.join(search_path, libpath))
    > end
    >
    > if load_path.nil? && !File.exists?(libpath)
    > raise LoadError.new("Could not find library path: #{libpath}")
    > end
    >
    > file_path = (load_path.nil? ? libpath : File.join(load_path, libpath))
    > contents = File.read(file_path)
    >
    > contents.scan(/^\s*class\s(\w+)/) do |class_name|
    > PARAMETERIZED_CLASSES[class_name.first.freeze] = file_path
    > end
    >
    > require(libpath)
    >
    > rescue => e
    > raise LoadError.new(e)
    > end
    >
    > end
    >
    > class UnboundMethod
    >
    > def binding_class
    > @class_name || @class_name = begin
    > to_s =~ /\#\<UnboundMethod\:\s(\w+)/
    > Object.const_get($1)
    > end
    > end
    >
    > def name
    > @name || @name = begin
    > to_s =~ /\#\<UnboundMethod\:\s\w+\#(\w+)/
    > $1.freeze
    > end
    > end
    >
    > def parameters
    > @parameters || @parameters = begin
    > parameter_names = []
    >
    > if file_path = PARAMETERIZED_CLASSES[binding_class.name]
    > if match = /def\s+#{name}\!?(\s+(.+)|\((.+)\))(\;|$)/.match(File.read(file_path))
    > parameters_capture = match.captures[1] || match.captures[2]
    > parameter_names = parameters_capture.split(/\,\s*/).reject do |parameter_name|
    > parameter_name.empty? || parameter_name == 'nil'
    > end.map { |s| s.freeze }
    > end
    > end
    >
    > parameter_names
    > end
    > end
    >
    > end


    There's holes in this. It's not a full Ruby parser. But it should work
    for 99% of your files.

    The idea is to extend web MVC frameworks like Merb to allow actions
    like the following:

    > class Post
    > def show(id)
    > @post = Post.find(id)
    > end
    > end


    I got the idea from a .NET project based _loosely_ on Rails:
    http://castleproject.org/monorail/index.html

    The problem is Ruby doesn't provide reflection similar to c#'s
    ParameterInfo object to make this easy. So here we are. I hope someone
    else finds this useful.
     
    Sam Smoot, Jun 15, 2007
    #1
    1. Advertising

  2. Sam Smoot

    Sam Smoot Guest

    Uhmm, yeah. Nevermind that version. Perfection!:

    > require 'parse_tree'
    >
    > class UnboundMethod
    >
    > def binding_class
    > @class_name || @class_name = begin
    > to_s =~ /\#\<UnboundMethod\:\s(\w+)/
    > Object.const_get($1)
    > end
    > end
    >
    > def name
    > @name || @name = begin
    > to_s =~ /\#\<UnboundMethod\:\s\w+\#(\w+)/
    > $1.freeze
    > end
    > end
    >
    > def parameters
    > @parameters || @parameters = begin
    > ParseTree.new.parse_tree_for_method(binding_class, name)[2][1][1][1..-1]
    > end
    > end
    >
    > end


    Now any UnboundMethod (written in Ruby) can be inspected for it's
    parameters, without any fancy require hacks...
     
    Sam Smoot, Jun 16, 2007
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paddy McCarthy
    Replies:
    3
    Views:
    719
    Anthony J Bybell
    Sep 24, 2004
  2. Stephen Kellett
    Replies:
    2
    Views:
    192
    Stephen Kellett
    Dec 12, 2004
  3. Jeff Cohen
    Replies:
    6
    Views:
    140
  4. Kenneth McDonald
    Replies:
    5
    Views:
    325
    Kenneth McDonald
    Sep 26, 2008
  5. Abdul Mohsin
    Replies:
    1
    Views:
    267
Loading...

Share This Page