| Class | IHelp::IHelpIndex |
| In: |
lib/ihelp.rb
|
| Parent: | Object |
IHelpIndex uses Ferret to index all available RI documentation and lets you do full text searches over the index.
E.g. IHelpIndex.new.search("domain name lookup")
See Ferret::QueryParser for query string format.
| GLOBAL_INDEX_PATH | = | File.join(File.dirname(__FILE__), "ihelp.index") | Default place to save and load the index from. | |
| LOCAL_INDEX_PATH | = | File.join(ENV["HOME"], ".ihelp.index") | ||
| DEFAULT_LOG_LEVEL | = | 2 |
| index | [RW] | The search index, is a Ferret::Index::Index |
| log_level | [RW] | |
| reindex_when_needed | [RW] |
# File lib/ihelp.rb, line 600
600: def initialize(use_global_index = (ENV["USER"] == "root"))
601: @log_level = DEFAULT_LOG_LEVEL
602: if use_global_index
603: @index_path = GLOBAL_INDEX_PATH
604: else
605: @index_path = LOCAL_INDEX_PATH
606: if not File.exist?(@index_path) and File.exist?(GLOBAL_INDEX_PATH)
607: FileUtils.cp_r(GLOBAL_INDEX_PATH, @index_path) rescue nil
608: elsif not File.exist?(@index_path)
609: self.class.reindex_when_needed = true
610: end
611: end
612: analyzer = IHelpAnalyzer.new
613: have_index = File.exist? @index_path
614: if have_index
615: log "Loading existing index from #{@index_path}", 1
616: @index = Ferret::I.new(
617: :key => :full_name,
618: :path => @index_path,
619: :analyzer => analyzer
620: )
621: else
622: log "Creating new index in #{@index_path}", 2
623: field_infos = Ferret::Index::FieldInfos.new(:term_vector => :no)
624: field_infos.add_field(:name,
625: :store => :yes,
626: :index => :yes,
627: :boost => 10.0)
628: field_infos.add_field(:full_name,
629: :store => :yes,
630: :index => :untokenized,
631: :boost => 0.0)
632: field_infos.add_field(:content,
633: :boost => 1.0,
634: :store => :yes,
635: :index => :yes,
636: :term_vector => :with_positions_offsets)
637: @index = Ferret::I.new(
638: :key => :full_name,
639: :field_infos => field_infos,
640: :analyzer => analyzer
641: )
642: end
643: if self.class.reindex_when_needed and need_reindexing?
644: reindex!
645: end
646: unless have_index
647: @index.persist(@index_path)
648: log "\nSaved index.", 2
649: end
650: end
# File lib/ihelp.rb, line 683
683: def all_names
684: IHelp.ri_driver.ri_reader.all_names.uniq
685: end
Returns true if there already is an object named full_name
# File lib/ihelp.rb, line 669
669: def already_indexed? full_name
670: @index[full_name]
671: end
# File lib/ihelp.rb, line 741
741: def display
742: return @display if @display
743: @display = IHelp.ri_driver.display
744: if ENV["PAGER"].to_s.size > 0
745: unless ENV["PAGER"] =~ /(^|\/)less\b.* -[a-zA-Z]*[rR]/
746: IHelp.no_colors = true
747: end
748: else
749: ENV["PAGER"] = "less -R"
750: end
751: class << @display
752: public :page
753: attr_accessor :formatter
754: end
755: @display
756: end
# File lib/ihelp.rb, line 673
673: def format_time(t)
674: sec = t % 60
675: min = (t / 60) % 60
676: hour = (t / 3600)
677: str = sec.to_i.to_s.rjust(2,'0')
678: str = min.to_i.to_s.rjust(2,'0') + ":" + str
679: str = hour.to_i.to_s.rjust(2,'0') + ":" + str if hour >= 1
680: str
681: end
# File lib/ihelp.rb, line 652
652: def log str, level = 1
653: STDERR.puts str if level >= @log_level
654: end
Reindexes any non-indexed help documents.
# File lib/ihelp.rb, line 693
693: def reindex!
694: start_size = @index.size
695: names = all_names
696: log "Indexing...", 2
697: nsz = names.size.to_s
698: i = 0
699: names.each{|n|
700: i += 1
701: next if (start_size > 0) and (already_indexed?(n))
702: if @log_level == DEFAULT_LOG_LEVEL
703: amt_done = (i.to_f / names.size)
704: pct = ("%.1f" % [100*amt_done]).rjust(5)
705: STDERR.write "\r #{pct}% (#{i.to_s.rjust(nsz.size)}/#{nsz}) #{n}".ljust(80)[0,80]
706: STDERR.flush
707: end
708: hd = if n.include? "#"
709: IHelp.ri_driver.get_info_str(*(n.split("#") + [true]))
710: elsif n.include? "::"
711: IHelp.ri_driver.get_info_str(n) or
712: IHelp.ri_driver.get_info_str(*n.reverse.split("::",2).reverse.map{|r| r.reverse })
713: else
714: IHelp.ri_driver.get_info_str n
715: end
716: if hd.nil?
717: log "skipping #{n} (not found)"
718: next
719: else
720: log "indexing #{n}"
721: end
722: @index << {
723: :name => hd.full_name,
724: :full_name => n,
725: :content => wrap_str(hd.to_text)
726: }
727: }
728: if @log_level == DEFAULT_LOG_LEVEL
729: amt_done = (i.to_f / names.size)
730: pct = ("%.1f" % [100*amt_done]).rjust(5)
731: STDERR.write "\r #{pct}% (#{i.to_s.rjust(nsz.size)}/#{nsz}) #{names.last}".ljust(80)[0,80]
732: STDERR.flush
733: STDERR.puts
734: end
735: if start_size != @index.size
736: log "Optimizing index... (old size #{start_size}, current size #{@index.size})"
737: @index.optimize
738: end
739: end
Searches for the terms in query and prints out first ten hits
See Ferret::QueryParser for query string format.
# File lib/ihelp.rb, line 783
783: def search(query)
784: result = @index.search(query, :limit => 1000)
785: init_display
786: if IHelp.no_colors or `which less`.strip.empty?
787: pre_tag = "<<"
788: post_tag = ">>"
789: else
790: name_start = "\033[32m"
791: name_end = "\033[0m"
792: pre_tag = "\033[36m"
793: post_tag = "\033[0m"
794: end
795: page do
796: puts
797: puts "=== #{result.total_hits} hits#{", showing first 1000" if result.total_hits > 1000} ".ljust(72,"=")
798: puts
799: result.hits.each_with_index do |hit, i|
800: id, score = hit.doc, hit.score
801: #puts hit.score
802: puts "#{name_start}#{@index[id][:full_name]}#{name_end}"
803: puts
804: puts @index.highlight(query, id, :field => :content,
805: :pre_tag => pre_tag,
806: :post_tag => post_tag,
807: :ellipsis => "...\n").to_s
808: puts
809: display.formatter.draw_line
810: puts
811: end
812: puts "#{result.total_hits} hits"
813: end
814: p result.hits.map{|hit| @index[hit.doc][:full_name] }
815: result
816: end
# File lib/ihelp.rb, line 660
660: def time
661: t = Time.now
662: rv = yield
663: log "Took #{Time.now - t}"
664: rv
665: end