Get Parameter names from methods

S

Sam Smoot

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.
 
S

Sam Smoot

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...
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top