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.



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

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
    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
  reindex! if self.class.reindex_when_needed and need_reindexing?
  unless have_index
    @index.persist(@index_path)
    log "Saved index.", 2
  end
end

Class Attribute Details

.reindex_when_neededObject

Returns the value of attribute reindex_when_needed.



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

def reindex_when_needed
  @reindex_when_needed
end

Instance Attribute Details

#indexObject

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



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

def index
  @index
end

#log_levelObject

Returns the value of attribute log_level.



596
597
598
# File 'lib/ihelp.rb', line 596

def log_level
  @log_level
end

Instance Method Details

#all_namesObject



678
679
680
# File 'lib/ihelp.rb', line 678

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)


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

def already_indexed? full_name
  @index[full_name]
end

#displayObject



735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
# File 'lib/ihelp.rb', line 735

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



668
669
670
671
672
673
674
675
676
# File 'lib/ihelp.rb', line 668

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



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

def init_display
  display
end

#log(str, level = 1) ⇒ Object



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

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

#need_reindexing?Boolean

Returns:

  • (Boolean)


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

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

#page(*a, &b) ⇒ Object



752
753
754
# File 'lib/ihelp.rb', line 752

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

#reindex!Object

Reindexes any non-indexed help documents.



688
689
690
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
# File 'lib/ihelp.rb', line 688

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 => 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
  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.



768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'lib/ihelp.rb', line 768

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
      wrap @index.highlight(query, id, :field => :content,
                            :pre_tag => pre_tag,
                            :post_tag => ).to_s
      puts
      display.formatter.draw_line
      puts
    end
    puts
  end
  p result.hits.map{|hit| @index[hit.doc][:full_name] }
  result
end

#timeObject



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

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

#wrap(str) ⇒ Object



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

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