Class IHelp::IHelpIndex
In: lib/ihelp.rb
Parent: Object
Ferret::Analysis::StandardAnalyzer IHelpAnalyzer RiDriver IHelpDriver IHelpIndex Renderer lib/ihelp.rb IHelp dot/m_0_1.png

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.

Methods

Constants

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

Attributes

index  [RW]  The search index, is a Ferret::Index::Index
log_level  [RW] 
reindex_when_needed  [RW] 

Public Class methods

[Source]

     # File lib/ihelp.rb, line 601
601:     def initialize(use_global_index = (ENV["USER"] == "root"))
602:       @log_level = DEFAULT_LOG_LEVEL
603:       if use_global_index
604:         @index_path = GLOBAL_INDEX_PATH
605:       else
606:         @index_path = LOCAL_INDEX_PATH
607:         if not File.exist?(@index_path) and File.exist?(GLOBAL_INDEX_PATH)
608:           FileUtils.cp_r(GLOBAL_INDEX_PATH, @index_path) rescue nil
609:         elsif not File.exist?(@index_path)
610:           self.class.reindex_when_needed = true
611:         end
612:       end
613:       analyzer = IHelpAnalyzer.new
614:       have_index = File.exist? @index_path
615:       if have_index
616:         log "Loading existing index from #{@index_path}", 1
617:         @index = Ferret::I.new(
618:           :key => :full_name,
619:           :path => @index_path,
620:           :analyzer => analyzer
621:         )
622:       else
623:         log "Creating new index in #{@index_path}", 2
624:         field_infos = Ferret::Index::FieldInfos.new(:term_vector => :no)
625:         field_infos.add_field(:name,
626:                           :store => :yes,
627:                           :index => :yes,
628:                           :boost => 10.0)
629:         field_infos.add_field(:full_name,
630:                           :store => :yes,
631:                           :index => :untokenized,
632:                           :boost => 0.0)
633:         field_infos.add_field(:content,
634:                           :boost => 1.0,
635:                           :store => :yes,
636:                           :index => :yes,
637:                           :term_vector => :with_positions_offsets)
638:         @index = Ferret::I.new(
639:           :key => :full_name,
640:           :field_infos => field_infos,
641:           :analyzer => analyzer
642:         )
643:       end
644:       if self.class.reindex_when_needed and need_reindexing?
645:         reindex!
646:       end
647:       unless have_index
648:         @index.persist(@index_path)
649:         log "\nSaved index.", 2
650:       end
651:     end

Public Instance methods

[Source]

     # File lib/ihelp.rb, line 684
684:     def all_names
685:       IHelp.ri_driver.ri_reader.all_names.uniq
686:     end

Returns true if there already is an object named full_name

[Source]

     # File lib/ihelp.rb, line 670
670:     def already_indexed? full_name
671:       @index[full_name]
672:     end

[Source]

     # File lib/ihelp.rb, line 742
742:     def display
743:       return @display if @display
744:       @display = IHelp.ri_driver.display
745:       if ENV["PAGER"].to_s.size > 0
746:         unless ENV["PAGER"] =~ /(^|\/)less\b.* -[a-zA-Z]*[rR]/
747:           IHelp.no_colors = true
748:         end
749:       else
750:         ENV["PAGER"] = "less -R"
751:       end
752:       class << @display
753:         public :page
754:         attr_accessor :formatter
755:       end
756:       @display
757:     end

[Source]

     # File lib/ihelp.rb, line 674
674:     def format_time(t)
675:       sec = t % 60
676:       min = (t / 60) % 60
677:       hour = (t / 3600)
678:       str = sec.to_i.to_s.rjust(2,'0')
679:       str = min.to_i.to_s.rjust(2,'0') + ":" + str
680:       str = hour.to_i.to_s.rjust(2,'0') + ":" + str if hour >= 1
681:       str
682:     end

[Source]

     # File lib/ihelp.rb, line 776
776:     def init_display
777:       display
778:     end

[Source]

     # File lib/ihelp.rb, line 653
653:     def log str, level = 1
654:       STDERR.puts str if level >= @log_level
655:     end

[Source]

     # File lib/ihelp.rb, line 688
688:     def need_reindexing?
689:       all_names.size > @index.size
690:     end

[Source]

     # File lib/ihelp.rb, line 759
759:     def page(*a,&b)
760:       display.page(*a,&b)
761:     end

[Source]

     # File lib/ihelp.rb, line 657
657:     def path
658:       @index_path
659:     end

Reindexes any non-indexed help documents.

[Source]

     # File lib/ihelp.rb, line 694
694:     def reindex!
695:       start_size = @index.size
696:       names = all_names
697:       log "Indexing...", 2
698:       nsz = names.size.to_s
699:       i = 0
700:       names.each{|n|
701:         i += 1
702:         next if (start_size > 0) and (already_indexed?(n))
703:         if @log_level == DEFAULT_LOG_LEVEL
704:           amt_done = (i.to_f / names.size)
705:           pct = ("%.1f" % [100*amt_done]).rjust(5)
706:           STDERR.write "\r #{pct}% (#{i.to_s.rjust(nsz.size)}/#{nsz}) #{n}".ljust(80)[0,80]
707:           STDERR.flush
708:         end
709:         hd = if n.include? "#"
710:           IHelp.ri_driver.get_info_str(*(n.split("#") + [true]))
711:         elsif n.include? "::"
712:           IHelp.ri_driver.get_info_str(n) or
713:           IHelp.ri_driver.get_info_str(*n.reverse.split("::",2).reverse.map{|r| r.reverse })
714:         else
715:           IHelp.ri_driver.get_info_str n
716:         end
717:         if hd.nil?
718:           log "skipping #{n} (not found)"
719:           next
720:         else
721:           log "indexing #{n}"
722:         end
723:         @index << {
724:           :name => hd.full_name,
725:           :full_name => n,
726:           :content => wrap_str(hd.to_text)
727:         }
728:       }
729:       if @log_level == DEFAULT_LOG_LEVEL
730:         amt_done = (i.to_f / names.size)
731:         pct = ("%.1f" % [100*amt_done]).rjust(5)
732:         STDERR.write "\r #{pct}% (#{i.to_s.rjust(nsz.size)}/#{nsz}) #{names.last}".ljust(80)[0,80]
733:         STDERR.flush
734:         STDERR.puts
735:       end
736:       if start_size != @index.size
737:         log "Optimizing index... (old size #{start_size}, current size #{@index.size})"
738:         @index.optimize
739:       end
740:     end

Searches for the terms in query and prints out first ten hits

See Ferret::QueryParser for query string format.

[Source]

     # File lib/ihelp.rb, line 784
784:     def search(query)
785:       result = @index.search(query, :limit => 1000)
786:       init_display
787:       if IHelp.no_colors or `which less`.strip.empty?
788:         pre_tag = "<<"
789:         post_tag = ">>"
790:       else
791:         name_start = "\033[32m"
792:         name_end = "\033[0m"
793:         pre_tag = "\033[36m"
794:         post_tag = "\033[0m"
795:       end
796:       page do
797:         puts
798:         puts "=== #{result.total_hits} hits#{", showing first 1000" if result.total_hits > 1000} ".ljust(72,"=")
799:         puts
800:         result.hits.each_with_index do |hit, i|
801:           id, score = hit.doc, hit.score
802:           #puts hit.score
803:           puts "#{name_start}#{@index[id][:full_name]}#{name_end}"
804:           puts
805:           puts @index.highlight(query, id, :field => :content,
806:                                 :pre_tag => pre_tag,
807:                                 :post_tag => post_tag,
808:                                 :ellipsis => "...\n").to_s
809:           puts
810:           display.formatter.draw_line
811:           puts
812:         end
813:         puts "#{result.total_hits} hits"
814:       end
815:       p result.hits.map{|hit| @index[hit.doc][:full_name] }
816:       result
817:     end

[Source]

     # File lib/ihelp.rb, line 661
661:     def time
662:       t = Time.now
663:       rv = yield
664:       log "Took #{Time.now - t}"
665:       rv
666:     end

[Source]

     # File lib/ihelp.rb, line 763
763:     def wrap(str)
764:       display.formatter.wrap(str)
765:     end

[Source]

     # File lib/ihelp.rb, line 767
767:     def wrap_str(str)
768:       $stdout = StringIO.new
769:       wrap(str)
770:       $stdout.rewind
771:       s = $stdout.read
772:       $stdout = STDOUT
773:       s
774:     end

[Validate]