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.



598
599
600
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
# File 'lib/ihelp.rb', line 598

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.



585
586
587
# File 'lib/ihelp.rb', line 585

def reindex_when_needed
  @reindex_when_needed
end

Instance Attribute Details

#indexObject

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



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

def index
  @index
end

#log_levelObject

Returns the value of attribute log_level.



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

def log_level
  @log_level
end

Instance Method Details

#all_namesObject



681
682
683
# File 'lib/ihelp.rb', line 681

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)


667
668
669
# File 'lib/ihelp.rb', line 667

def already_indexed? full_name
  @index[full_name]
end

#displayObject



739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
# File 'lib/ihelp.rb', line 739

def display
  return @display if @display
  @display = RI::Options.instance.displayer.clone
  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



671
672
673
674
675
676
677
678
679
# File 'lib/ihelp.rb', line 671

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



773
774
775
# File 'lib/ihelp.rb', line 773

def init_display
  display
end

#log(str, level = 1) ⇒ Object



650
651
652
# File 'lib/ihelp.rb', line 650

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

#need_reindexing?Boolean

Returns:

  • (Boolean)


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

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

#page(*a, &b) ⇒ Object



756
757
758
# File 'lib/ihelp.rb', line 756

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

#pathObject



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

def path
  @index_path
end

#reindex!Object

Reindexes any non-indexed help documents.



691
692
693
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
# File 'lib/ihelp.rb', line 691

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, *a) ⇒ Object

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

See Ferret::QueryParser for query string format.



781
782
783
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
# File 'lib/ihelp.rb', line 781

def search(query, *a)
  result = @index.search(query, *a)
  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 10" if result.total_hits > 10} ".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



658
659
660
661
662
663
# File 'lib/ihelp.rb', line 658

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

#wrap(str) ⇒ Object



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

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

#wrap_str(str) ⇒ Object



764
765
766
767
768
769
770
771
# File 'lib/ihelp.rb', line 764

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