#! /usr/local/bin/ruby -KsW0 # # name: kre # # description: # コマンドラインから吉里吉里のリファレンスを引くためのスクリプト。 # # example: # % kre System getTickCount => System.getTickCount # % kre sys gettick => System.getTickCount 省略可能 # % kre gettick => System.getTickCount メソッド名が一意ならば、それでも引ける。 # % kre sys => System クラス名にマッチするときは、クラスの説明文になる。 # % kre sys gTC => System.getTickCount 大文字による省略 # # requirement: w3m # # notice: # * 吉里吉里のリファレンスが f_*_*.html のファイル名であることに依存している。 # * メソッド名が英字のみからなっていることに依存している。(数字はダメ) # # # license: # このスクリプトは、パブリックドメイン扱いとします。 # # author: Kouhei Yanagita # # # ↓要変更 KIRIKIRI_DOCS_DIR = '/h/home/doc/kr2doc/contents' module KRE Version = "kre version 0.1.1" class LookupError < StandardError; end module ReferenceDisplayer def get_description_from_file(file) `w3m -dump -T text/html #{file}` end def print_description puts get_description_from_file(get_description_filename()) end end class KirikiriMethod attr_reader :name, :klass def initialize(name, c, root_dir = '') @name = name @klass = c @root_dir = root_dir end def full_name "#{@klass.name}.#{name}" end include ReferenceDisplayer private def get_description_filename "#{@root_dir}/f_#{@klass.name}_#{@name}.html" end end class KirikiriClass attr_reader :name def initialize(name, root_dir = '') @name = name @methods = [] @root_dir = root_dir end def add_method(m) @methods << KirikiriMethod.new(m, self, @root_dir) if not @methods.find{|me| me.name == m} end def find_method(m, opt) Matcher.new(@methods).get(m, opt){|item| item.name} end def each_methods @methods.each do |m| yield m end end include ReferenceDisplayer private def get_description_filename "#{@root_dir}/f_#{@name}.html" end end class Database def initialize(root_dir) @root_dir = root_dir make_table end private def make_table @classes = [] files = Dir.glob("#{@root_dir}/f_*.html") files.each do |file| case file when /f_([^_]*)_([^_]*)\.html/ class_name, method_name = $1, $2 c = @classes.find{|c| c.name == class_name} if not c c = KirikiriClass.new(class_name, @root_dir) @classes << c end c.add_method(method_name) when /f_([^_]*)\.html/ class_name = $1 else end end end def search_class_name(class_name, opt) Matcher.new(@classes).get(class_name, opt){|item| item.name} end public def find(class_name, method_name, opt) if class_name.nil? # print all classes @classes.each{|c| puts "#{c.name}"} elsif method_name.nil? # method found_classes = search_class_name(class_name, opt) # クラス名でぴったり一致 if found_classes.size == 1 and found_classes[0].name == class_name found_classes[0].print_description return end method_name = class_name found_methods = search_method_name(@classes, method_name, opt) case found_classes.size + found_methods.size when 0 raise LookupError, "not match: #{class_name}" when 1 (found_classes + found_methods).each{|e| e.print_description} else found_classes.each{|c| puts c.name} found_methods.each{|m| puts m.full_name} end else # class + method found_methods = search_method_name(search_class_name(class_name, opt), method_name, opt) case found_methods.size when 0 raise LookupError, "not match: #{class_name} #{method_name}" when 1 found_methods[0].print_description else found_methods.each{|m| puts m.full_name} end end end private def search_method_name(classes, method_name, opt) result = [] classes.each do |c| result += c.find_method(method_name, opt) end result end end class Matcher IGNORE_CASE = 1 CAPITAL_ABBREVIATION = 2 MIDDLE_MATCH = 4 CAPITAL_MATCHES_ONLY_CAPITAL = 8 def initialize(items) @items = items end def get(pattern, opt) result = @items.find{|e| (block_given? ? yield(e) : e) == pattern} return [result] if not result.nil? # ぴったり一致するときはそれを採用 re = make_regexp_from_pattern(pattern, opt) puts "pattern=#{pattern}, opt=#{opt}, re=#{re.inspect}" if $OPT_DEBUG result = [] @items.each do |e| result << e if (block_given? ? yield(e) : e) =~ re end result end private def make_regexp_from_pattern(pattern, opt) if not (opt & MIDDLE_MATCH) != 0 pattern = '^' + pattern end ignore_case = ((opt & IGNORE_CASE) != 0) if ignore_case pattern = pattern.gsub(/([a-zA-Z])/){ match = $1 if (opt & CAPITAL_ABBREVIATION) != 0 case match when /[A-Z]/ "[a-zA-Z]*#{match}" when /[a-z]/ "[#{match}#{match.upcase}]" else match end else case match when /[A-Z]/ "[#{match}#{match.downcase}]" when /[a-z]/ "[#{match}#{match.upcase}]" else match end end } Regexp.new(pattern) else if (opt & CAPITAL_ABBREVIATION) != 0 pattern = pattern.gsub(/([A-Z])/){ "[a-zA-Z]*#{$1}" } end Regexp.new(pattern) end end end end def parse_options require 'getoptlong' parser = GetoptLong.new parser.set_options(['--consider-case', '-c', GetoptLong::NO_ARGUMENT], ['--ignore-case', '-i', GetoptLong::NO_ARGUMENT], ['--no-capital-abbreviation', '-A', GetoptLong::NO_ARGUMENT], ['--middle-match', '-m', GetoptLong::NO_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--version', '-v', GetoptLong::NO_ARGUMENT], ['--debug', '-d', GetoptLong::NO_ARGUMENT] ) begin parser.each_option do |name, arg| eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_').upcase} = '#{arg}'" end rescue exit(1) end end def print_help puts < err $stderr.puts err.message exit 1 end end main