From: Robert Feldt Date: 2001-02-26T22:28:34+09:00 Subject: [ruby-talk:11587] ri patch for the lazy - prefix matching Dear Dave, Thanks a lot for 'ri'; its *very* useful. I patched my ri script so that it can handle prefix matches. You'll find the patch below in case someone else finds it useful. With this patch you can do ri Ar same as ri Array ri Ar#collect same as ri Array#collect ri Di#chd same as ri Dir#chdir etc. and also $ ri Bi Multiple classes have same prefix as `Bi': Bignum, Binding $ ri ea No method named `ea' but several methods have same prefix: each_object, each_key, each, each_pair, each_line, each_index, each_with_index, each_byte, each_value $ ri Ar#co Multiple methods have same prefix as `co': collect, collect!, compact, compact!, concat $ ./ri ear No method named `ear' but several methods have same prefix: each_object, each_key, each, each_pair, each_line, each_index, each_with_index, each_byte, each_value No doubt, the patch can be refactored and made more "beautiful". Some "bugs" are in there if you specify more than 1 thing to look up at the same time. Probably some other ones too ;-)... Regards, Robert --- ri.old Mon Feb 26 13:38:36 2001 +++ ri Mon Feb 26 14:05:38 2001 @@ -50,18 +50,68 @@ end ## +# Filter out strings in array with given prefix. If none match and +# recurseWhileShrinking then drop char's at the end of prefix and try again. +# +def filter_strings_with_prefix(anArrayOfStrings, prefix, + recurseWhileShrinking = true) + return [] unless prefix.length > 0 + res = anArrayOfStrings.collect {|s| ((s =~ prefix) == 0) ? s : nil}.compact + return res if res.length > 0 + if recurseWhileShrinking + filter_strings_with_prefix(anArrayOfStrings, prefix[0...-1], true) + else + [] + end +end + +def classes + classes = nil + Dir.open($datadir) {|dir| classes = dir.grep(/^[A-Z]/)} + classes +end + +## # Read in a serialized class description # def findClass(name) fname = name.tr(':', '_') begin File.open(File.join($datadir, fname)) do |f| - return Marshal.load(f) + cl = Marshal.load(f) + def cl.findMethod(meth, classMethod) + @methods.each do |m| + if m.name == meth + return m if classMethod and m.type == "class" + return m if !classMethod and m.type != "class" + end + end + methods = + filter_strings_with_prefix(@methods.collect{|m| m.name}, meth) + if methods.length > 1 + $stderr.puts "Multiple methods have same prefix as `#{meth}':\n" + $stderr.puts Text::wrap(" ", methods.join(", ")) + exit(1) + else + @methods.detect{|m| m.name == methods[0]} + end + end + return cl end rescue - $stderr.puts "Couldn't find class/module `#{name}'.\n" + + classes_with_prefix = filter_strings_with_prefix(classes, name) + if classes_with_prefix.length == 1 + fname = classes_with_prefix.first + retry + elsif classes_with_prefix.length > 1 + $stderr.puts "Multiple classes have same prefix as `#{name}':\n" + $stderr.puts Text::wrap(" ", classes_with_prefix.join(", ")) + exit(1) + else + $stderr.puts "Couldn't find class/module `#{name}'.\n" + "Use #$0 with no parameter for a list" - exit(1) + exit(1) + end end end @@ -83,7 +133,6 @@ end end - ## # Print a simple list of classes and exit def usage @@ -92,14 +141,12 @@ $stderr.puts "\nDisplays documentation for the names classes or methods\n\n" $stderr.puts "I have documentation for the classes and modules:\n\n" - Dir.open($datadir) do |dir| - names = dir.grep(/^[A-Z]/) + names = classes - if names.size.zero? - $stderr.puts "Configuration error: could not find class list" - else - puts Text::wrap(" ", names.sort.join(", ")) - end + if names.size.zero? + $stderr.puts "Configuration error: could not find class list" + else + puts Text::wrap(" ", names.sort.join(", ")) end end @@ -170,8 +217,20 @@ options = index[name] if !options - $stderr.puts "Don't know anything about a method called `#{name}'." - exit(1) + def index.method_with_prefix(name) + filter_strings_with_prefix(@index.keys, name, true) + end + methods = index.method_with_prefix(name) + if methods.length == 0 + $stderr.puts "Don't know anything about a method called `#{name}'." + exit(1) + elsif methods.length > 1 + puts "No method named `#{name}' but several methods have same prefix:" + puts Text::wrap(" ", methods.join(", ")) + exit(0) + else + options = index[methods[0]] + end end if options.size == 1