Dave Thomas wrote: > > On Nov 10, 2008, at 8:50 AM, Austin Ziegler wrote: > >> That feels a little better from my ability to understand it, but then >> programs which want to do metaprogramming have to do a lot of extra work >> (split on /=/; know that "*" means greedy, etc.). I was sort of thinking >> an array of Hashes, but that's not necessarily any lighter weight than a >> Struct or a dedicated class. > > Actually, I'm not convinced there's any extra work compared to handling > a structured type coming back. I tried a few use cases, and it seems > that the conditional logic I'd need is the same in all cases, and the > string representation has simplicity on its side. It's actually an array of arrays with a set structure; I tend to like the array since it's a trivial bit of structured data and doesn't bloat up the global namespace with yet another class with only a single purpose. Since the reuse case for a MethodArg type would be extremely limited, I vote for arrays. Whatever it ends up as, we'll provide support in JRuby for both 1.8 and 1.9 modes. For anyone interested, the code (all ruby) to add this feature in JRuby is below. - Charlie require 'java' require 'jruby' module GetArgs Methods = org.jruby.internal.runtime.methods def get_args real_method = JRuby.reference(self) # hack to expose a protected field; could be improved in 1.1.5 method_field = org.jruby.RubyMethod.java_class.declared_field(:method) method_field.accessible = true dyn_method = method_field.value(real_method) case dyn_method when Methods.MethodArgs return build_args(dyn_method.args_node) else raise "Can't get args from method: #{self}" end end def build_args(args_node) args = [] required = [] optional = [] # required args if (args_node.args && args_node.args.size > 0) required << args_node.args.child_nodes.map { |arg| [arg.name.to_s.intern] } end # optional args if (args_node.opt_args && args_node.opt_args.size > 0) optional << args_node.opt_args.child_nodes.map do |arg| name = arg.name.to_s.intern value_node = arg.value_node case value_node when org.jruby.ast::FixnumNode value = value_node.value when org.jruby.ast::SymbolNode value = value_node.get_symbol(JRuby.runtime) when org.jruby.ast::StrNode value = value_node.value else value = nil end [name, value] end end first_args = required.first optional.first.each {|arg| first_args << arg} if optional.first args = [first_args] rest = args_node.rest_arg_node args << (rest ? rest.name.to_s.intern : nil) block = args_node.block_arg_node args << (block ? block.name.to_s.intern : nil) args end end