One day I read a story called the Legend of the Ferret. It seems, at first, like a mighty sad tale but the ferrets have gotten to be experts at scurrying through Mouse Holes looking for things. In fact, I keep a pet ferret myself, just for this finding ability. His name is Herbert and he searches my web history.
Would you like your own pet ferret? I'm sure you would, they're very handy. Start by grabbing a ferret gem:
gem install ferret -y
Before your new friend can move, you'll need a place for your it to store its pages. Here you can borrow my spare den for the time being, until you build your own personalised one. Just save this code into ~/.mouseHole/petferretden.rb:
# petferretden.rb - web history indexer for MouseHole 2
#
# Your pet ferret collects web pages in its den and makes them searchable!
# You'll also need the ferret itself, petferret.rb.
#
require 'ferret'
class PetFerretDen < MouseHole::App
title "Pet Ferret Den"
namespace "alex@mugofgrog.com"
description ("Your pet ferret collects pages from your web browsing and stores them in its den. " +
"Golly, it's a mess!")
version "0.1"
+ url("*")
def untangle(s)
s = s.gsub(/<(script|style).*?<\/[^>]*>/m, '')
s.gsub!(/<[^>]*>/m, ' ')
s.gsub!(/&[^ ;]*;/m, ' ')
s.gsub!(/\s+/, ' ')
s
end
def rewrite(page)
Ferret::Index::Index.new :path => '+pet_ferret_index' do |index|
title = untangle $1 if page.body =~ /<title[^>]*>([^<]*)<\//m
title ||= page.location
index << { :id => page.location,
:title => title,
:content => untangle(page.body) }
end
end
end
Next you'll need the pet ferret itself, save this code in ~/.mouseHole/petferret.rb:
# petferret.rb - web history search frontend for MouseHole 2
#
# What do you get when you put a ferret in a mouse hole? Why a personal search
# engine of course!
#
# You'll also need the indexer part, petferretden.rb.
#
require 'camping'
require 'ferret'
Camping.goes :PetFerret
PageSize = 10
module PetFerret::Controllers
class Index < R '/'
def get
if @input[:q]
@ferret = Ferret::Index::Index.new :path => "+pet_ferret_index"
parser = Ferret::QueryParser.new(:or_default => false,
:fields => ['title', 'content', 'id'])
query = parser.parse(@input[:q])
@start = 0
@start = @input[:start].to_i if @input[:start]
@topdocs = @ferret.search query, :offset => @start, :limit => PageSize
@total = @topdocs.total_hits
@end = [@start + PageSize, @total].min
@start = 0 if @start + 1 > @end
@results = @topdocs.hits
render :results
else
render :index
end
end
end
end
module PetFerret::Views
def layout
html do
head do
style do
self << '.result a { display: block; }'
self << '.result span { color: #55f; display: block; }'
end
end
body do
h1 "Pet Ferret"
self << search_box
self << yield
end
end
end
def search_box
form :action => R(Index) do
input :name => :q, :value => @input[:q]
input :type => :submit, :value => "Go ferret!"
end
end
def index
p { em "Your ferret idly chews on an ethernet cable while awaiting your command." }
end
def results
p do
strong "Whoosh! "
em "Your ferret swiftly returns, eagerly dragging some slightly-chewed pages."
end
p "Results #{@start+1} to #{@end} out of #{@topdocs.total_hits} for \"#{@input[:q]}\""
for hit in @results
doc = @ferret[hit.doc]
p :class => :result do
a doc[:title], :href => doc[:id]
self << @ferret.highlight(@input[:q], hit.doc, :field => :content)
span "#{doc[:id]}"
end
end
if @end < @total
a "Gimme more...", :href => "?q=#{CGI.escape @input[:q]}&start=#{@end}"
else
p "No more results. :-("
end
end
end
Startup your Mouse Hole and visit a few pages. If your ferret has settled in happily you should be able visit him at http://mh/petferret/ and he'll be able to find all your pages again.