Class: IHelp::IHelpIndex

Inherits:
Object show all
Defined in:
lib/ihelp.rb

Overview

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.

Constant Summary collapse

GLOBAL_INDEX_PATH =

Default place to save and load the index from.

File.join(File.dirname(__FILE__), "ihelp.index")
LOCAL_INDEX_PATH =
File.join(ENV["HOME"], ".ihelp.index")
DEFAULT_LOG_LEVEL =
2

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(use_global_index = (ENV["USER"] == "root")) ⇒ IHelpIndex

Returns a new instance of IHelpIndex.



601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
# File 'lib/ihelp.rb', line 601

def initialize(use_global_index = (ENV["USER"] == "root"))
  @log_level = DEFAULT_LOG_LEVEL
  if use_global_index
    @index_path = GLOBAL_INDEX_PATH
  else
    @index_path = LOCAL_INDEX_PATH
    if not File.exist?(@index_path) and File.exist?(GLOBAL_INDEX_PATH)
      FileUtils.cp_r(GLOBAL_INDEX_PATH, @index_path) rescue nil
    elsif not File.exist?(@index_path)
      self.class.reindex_when_needed = true
    end
  end
  analyzer = IHelpAnalyzer.new
  have_index = File.exist? @index_path
  if have_index
    log "Loading existing index from #{@index_path}", 1
    @index = Ferret::I.new(
      :key => :full_name,
      :path => @index_path,
      :analyzer => analyzer
    )
  else
    log "Creating new index in #{@index_path}", 2
    field_infos = Ferret::Index::FieldInfos.new(:term_vector => :no)
    field_infos.add_field(:name,
                      :store => :yes,
                      :index => :yes,
                      :boost => 10.0)
    field_infos.add_field(:full_name,
                      :store => :yes,
                      :index => :untokenized,
                      :boost => 0.0)
    field_infos.add_field(:content,
                      :boost => 1.0,
                      :store => :yes,
                      :index => :yes,
                      :term_vector => :with_positions_offsets)
    @index = Ferret::I.new(
      :key => :full_name,
      :field_infos => field_infos,
      :analyzer => analyzer
    )
  end
  if self.class.reindex_when_needed and need_reindexing?
    reindex!
  end
  unless have_index
    @index.persist(@index_path)
    log "\nSaved index.", 2
  end
end

Class Attribute Details

.reindex_when_neededObject

Returns the value of attribute reindex_when_needed.



588
589
590
# File 'lib/ihelp.rb', line 588

def reindex_when_needed
  @reindex_when_needed
end

Instance Attribute Details

#indexObject

The search index, is a Ferret::Index::Index



592
593
594
# File 'lib/ihelp.rb', line 592

def index
  @index
end

#log_levelObject

Returns the value of attribute log_level.



594
595
596
# File 'lib/ihelp.rb', line 594

def log_level
  @log_level
end

Instance Method Details

#all_namesObject



684
685
686
# File 'lib/ihelp.rb', line 684

def all_names
  IHelp.ri_driver.ri_reader.all_names.uniq
end

#already_indexed?(full_name) ⇒ Boolean

Returns true if there already is an object named full_name

Returns:

  • (Boolean)


670
671
672
# File 'lib/ihelp.rb', line 670

def already_indexed? full_name
  @index[full_name]
end

#displayObject



742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
# File 'lib/ihelp.rb', line 742

def display
  return @display if @display
  @display = IHelp.ri_driver.display
  if ENV["PAGER"].to_s.size > 0
    unless ENV["PAGER"] =~ /(^|\/)less\b.* -[a-zA-Z]*[rR]/
      IHelp.no_colors = true
    end
  else
    ENV["PAGER"] = "less -R"
  end
  class << @display
    public :page
    attr_accessor :formatter
  end
  @display
end

#format_time(t) ⇒ Object



674
675
676
677
678
679
680
681
682
# File 'lib/ihelp.rb', line 674

def format_time(t)
  sec = t % 60
  min = (t / 60) % 60
  hour = (t / 3600)
  str = sec.to_i.to_s.rjust(2,'0')
  str = min.to_i.to_s.rjust(2,'0') + ":" + str
  str = hour.to_i.to_s.rjust(2,'0') + ":" + str if hour >= 1
  str
end

#init_displayObject



776
777
778
# File 'lib/ihelp.rb', line 776

def init_display
  display
end

#log(str, level = 1) ⇒ Object



653
654
655
# File 'lib/ihelp.rb', line 653

def log str, level = 1
  STDERR.puts str if level >= @log_level
end

#need_reindexing?Boolean

Returns:

  • (Boolean)


688
689
690
# File 'lib/ihelp.rb', line 688

def need_reindexing?
  all_names.size > @index.size
end

#page(*a, &b) ⇒ Object



759
760
761
# File 'lib/ihelp.rb', line 759

def page(*a,&b)
  display.page(*a,&b)
end

#pathObject



657
658
659
# File 'lib/ihelp.rb', line 657

def path
  @index_path
end

#reindex!Object

Reindexes any non-indexed help documents.



694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
# File 'lib/ihelp.rb', line 694

def reindex!
  start_size = @index.size
  names = all_names
  log "Indexing...", 2
  nsz = names.size.to_s
  i = 0
  names.each{|n|
    i += 1
    next if (start_size > 0) and (already_indexed?(n))
    if @log_level == DEFAULT_LOG_LEVEL
      amt_done = (i.to_f / names.size)
      pct = ("%.1f" % [100*amt_done]).rjust(5)
      STDERR.write "\r #{pct}% (#{i.to_s.rjust(nsz.size)}/#{nsz}) #{n}".ljust(80)[0,80]
      STDERR.flush
    end
    hd = if n.include? "#"
      IHelp.ri_driver.get_info_str(*(n.split("#") + [true]))
    elsif n.include? "::"
      IHelp.ri_driver.get_info_str(n) or
      IHelp.ri_driver.get_info_str(*n.reverse.split("::",2).reverse.map{|r| r.reverse })
    else
      IHelp.ri_driver.get_info_str n
    end
    if hd.nil?
      log "skipping #{n} (not found)"
      next
    else
      log "indexing #{n}"
    end
    @index << {
      :name => hd.full_name,
      :full_name => n,
      :content => wrap_str(hd.to_text)
    }
  }
  if @log_level == DEFAULT_LOG_LEVEL
    amt_done = (i.to_f / names.size)
    pct = ("%.1f" % [100*amt_done]).rjust(5)
    STDERR.write "\r #{pct}% (#{i.to_s.rjust(nsz.size)}/#{nsz}) #{names.last}".ljust(80)[0,80]
    STDERR.flush
    STDERR.puts
  end
  if start_size != @index.size
    log "Optimizing index... (old size #{start_size}, current size #{@index.size})"
    @index.optimize
  end
end

#search(query) ⇒ Object

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

See Ferret::QueryParser for query string format.



784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
# File 'lib/ihelp.rb', line 784

def search(query)
  result = @index.search(query, :limit => 1000)
  init_display
  if IHelp.no_colors or `which less`.strip.empty?
    pre_tag = "<<"
     = ">>"
  else
    name_start = "\033[32m"
    name_end = "\033[0m"
    pre_tag = "\033[36m"
     = "\033[0m"
  end
  page do
    puts
    puts "=== #{result.total_hits} hits#{", showing first 1000" if result.total_hits > 1000} ".ljust(72,"=")
    puts
    result.hits.each_with_index do |hit, i|
      id, score = hit.doc, hit.score
      #puts hit.score
      puts "#{name_start}#{@index[id][:full_name]}#{name_end}"
      puts
      puts @index.highlight(query, id, :field => :content,
                            :pre_tag => pre_tag,
                            :post_tag => ,
                            :ellipsis => "...\n").to_s
      puts
      display.formatter.draw_line
      puts
    end
    puts "#{result.total_hits} hits"
  end
  p result.hits.map{|hit| @index[hit.doc][:full_name] }
  result
end

#timeObject



661
662
663
664
665
666
# File 'lib/ihelp.rb', line 661

def time
  t = Time.now
  rv = yield
  log "Took #{Time.now - t}"
  rv
end

#wrap(str) ⇒ Object



763
764
765
# File 'lib/ihelp.rb', line 763

def wrap(str)
  display.formatter.wrap(str)
end

#wrap_str(str) ⇒ Object



767
768
769
770
771
772
773
774
# File 'lib/ihelp.rb', line 767

def wrap_str(str)
  $stdout = StringIO.new
  wrap(str)
  $stdout.rewind
  s = $stdout.read
  $stdout = STDOUT
  s
end