|
|
|
|Home|Why Use?|Demos|About
|Contact|Mail List
|Group
|Hpricot By Mr _Why
|FAQ|Workbench|Workbench-RO|
Disclaimer!
Welcome to http://hpricot.com.
I wrote this site to teach you Hpricot, Ruby, and some Rails.
The code you see here is unsuitable for any other purpose.
The code here is released under the same terms and conditions as Ruby.
Dan Bikle
bikle@bikle.com
Source Code Which Serves This Page:
/views/layouts/application.rhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<%= render(:partial => "layouts/head") %>
<body>
<table id="t2" width="98%" border="0">
<tr id="t2r2">
<td id="t2r2c2" valign="top">
<%= render(:partial => "layouts/t2r2c2") %>
</td> <!-- t2r2c2 end -->
<td id="t2r2c4" valign="top">
<%= render(:partial => "layouts/bcrmbs") %>
<%= yield %>
<hr />
<h3> Source Code Which Serves This Page: </h3>
<%= render(:partial => "layouts/show_source") %>
<hr />
<%= render(:partial => "layouts/bcrmbs") %>
<hr />
</td> <!-- t2r2c4 end -->
<td id="t2r2c6" class="hpricot-color" valign="top">
<%= render(:partial => "layouts/t2r2c6") %>
</td> <!-- t2r2c6 end -->
</tr> <!-- t2r2 end -->
</table> <!-- t2 end -->
</body>
</html>
/views/layouts/_head.haml
%head
%meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
%title hpricot.com
%link{:rel => "shortcut icon", :href => "/favicon.ico"}
= javascript_include_tag("prototype")
= javascript_include_tag("effects")
= javascript_include_tag("dragdrop")
= javascript_include_tag("controls")
= javascript_include_tag("application")
= active_scaffold_includes
= stylesheet_link_tag("application")
/views/layouts/_t2r2c2.haml
/ _t2r2c2.haml
%td#t2r2c2.hpricot-color{:valign => "top"}
%div.white-color
%hr
%a{:href => "/"}
%img{:src => "/images/hpricot-small.png", :alt => "http://hpricot.com"}
%hr
%h2
= bcrmb('<a href="/">http://hpricot.com</a>')
%hr
%p
%b
= bcrmb('<a href="/sttc/why_hpricot"> Why Learn/Use Hpricot?</a>')
%p
%b
= bcrmb('<a href="/demos"> Hpricot Demonstrations</a>')
%p
%b
= bcrmb('<a href="/demos/about"> About</a>')
%p
%b
= bcrmb('<a href="/sttc/contact"> Contact</a>')
%p
%b
= bcrmb('<a href="/sttc/maillist"> Mail List</a>')
%p
%b
%a{:href => "http://groups.google.com/group/hpricot", :target => "hp"} http://groups.google.com/group/hpricot
%p
%b
%a{:href => "http://code.whytheluckystiff.net/hpricot", :target => "hp"} http://code.whytheluckystiff.net/hpricot
%hr
%p= render(:partial => "layouts/login_status")
%hr
%p
%b
= bcrmb('<a href="/sttc/workbench_faq"> FAQ for Hpricot Workbench</a>')
%p
%b
= bcrmb('<a href="/frgmnts"> An Hpricot Workbench</a>')
%p
%b
= bcrmb('<a href="/asls/frgmnts"> Hpricot Workbench Public (Read-Only)</a>')
%p
%b
%a{:href => "http://chrispederick.com/work/web-developer", :target => "wd"}
Hpricot Development Aid:
%br http://chrispederick.com/work/web-developer
%p
%b
%a{:href => "http://www.getfirebug.com", :target => "wd"}
Hpricot Development Aid:
%br http://www.getfirebug.com
%p
%b
%a{:href => "/hpricot_rdoc154/index.html", :target => "hp"} RDoc of Hpricot 0.6
%p
%b
%a{:href => "/app/index.html", :target => "hp"} RDoc of hpricot.com
%p
%b
= bcrmb('<a href="/sttc/disclaimer"> Disclaimer!</a>')
%hr
= render(:partial => "/layouts/built_with")
%hr
/views/layouts/_show_source.rhtml
<%= show_code("views/layouts", "application.rhtml") -%>
<%= show_code("views/layouts", "_head.haml") -%>
<%= show_code("views/layouts", "_t2r2c2.haml") -%>
<%= show_code("views/layouts", "_show_source.rhtml") -%>
<%= show_code("../public/stylesheets/sass", "application.sass") -%>
<%= show_code("../config", "routes.rb") -%>
<%= show_code("controllers", "application.rb") -%>
<%= show_code("controllers", "#{params[:controller]}_controller.rb") -%>
<%= show_code("helpers", "application_helper.rb") -%>
<%= show_code("helpers", "#{params[:controller]}_helper.rb") -%>
<p />
The Hpricot Workbench makes use of these models:
<p />
<%= show_code("models", "exprtype.rb") -%>
<%= show_code("models", "stck.rb") -%>
<%= show_code("models", "frgmnt.rb") -%>
<%= show_code("models", "usr.rb") -%>
/../public/stylesheets/sass/application.sass
td
:border-style solid
:border-width 1px
:border-color black
body
:background-color white
:width 98%
.hpricot-color
:background-color #FF7700
.white-color
:background-color white
a
:text-decoration underline
:color #335500
:font-weight bold
a:hover
:text-decoration underline
:color #FF7700
:background-color #FFFFFF
a:visited
.redstack
:background-color red
.greenstack
:background-color green
.bluestack
:background-color blue
.yellowstack
:background-color yellow
.orangestack
:background-color orange
.whitestack
:background-color white
.blackstack
:background-color black
// frgmnt-frgtxt is out of control. I constrain it with scroll bars.
div.frgmnt-frgtxt
:overflow scroll
:height 200px
:width 200px
// Make text message at end of frgtxt more noticeable
span.snipmsg
:color #1F7F00
:font-weight bold
// Code
code
:font-size 120%
:line-height 140%
:background-color #ddd
pre
:background #333
:color #fffed8
:border 1px inset #aaa
:overflow auto
:padding 3px 5px
:margin 5px 0
pre code
:background-color transparent
// Code End
/../config/routes.rb
ActionController::Routing::Routes.draw do |map|
# The priority is based upon order of creation: first created -> highest priority.
# Sample of regular route:
# map.connect 'products/:id', :controller => 'catalog', :action => 'view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
# This route can be invoked with purchase_url(:id => product.id)
# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
map.connect '', :controller => "demos", :action => "about"
# Allow downloading Web Service WSDL as a file with an extension
# instead of a file named 'wsdl'
map.connect ':controller/service.wsdl', :action => 'wsdl'
# Install the default route as the lowest priority.
map.connect ':controller/:action/:id.:format'
map.connect ':controller/:action/:id'
end
/controllers/application.rb
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
require 'usr_system'
require 'rubygems'
require 'hpricot'
require 'open-uri'
class ApplicationController < ActionController::Base
# Pick a unique cookie name to distinguish our session data from others'
session :session_key => '_hp12_session_id'
include ERB::Util
include UsrSystem
helper :usr
before_filter :authenticate_usr
# I help Hpricot
Hpricot.buffer_size = 262144
# Null out the parse() method of WebAgent::CookieManager so it cannot save cookies
module Tst
class WebAgent::CookieManager
# Empty parse method which nulls out the effect of the real parse()
def parse x, y
@index = "nada"
end # parse
end # class
end # module
# Method for rendering the HTML in a Fragment
def rndr_frgmnt
@somehtml = Frgmnt.find(params[:id]).frgtxt
render(:layout => "layouts/layout4rndr")
end # rndr_frgmnt
protected
# Returns raw HTML. Usually it gets passed to get_my_hp_elem()
def get_my_html_from_open_uri(u)
hdrs = {"User-Agent"=>"Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1", "Accept-Charset"=>"utf-8", "Connection"=>"Keep-Alive", "Accept"=>"text/html"}
my_html = ""
begin
open(u, hdrs).each {|s| my_html << s}
rescue
my_html = "<html><body><p /><b>hello world</b></body></html>"
end
return my_html
end # get_my_html_from_open_uri()
# Returns an Hpricot object from HTML obtained by get_my_html_from_open_uri()
def get_my_hp_elem(u)
h0 = Hpricot(get_my_html_from_open_uri(u))
# remove crap
# (h0/"script").remove
return h0
end # get_my_hp_elem()
# Repel users who manually tinker with id in the request URL
def repel_them
# I dont need to repel_them if id is nil
return if (params[:id] == nil)
# Get the model class loaded into an object which can also be a class
myklass = self.active_scaffold_config.model
# Use the object-class-beastie to run .find() against the id in the request URL
the_obj = myklass.find(params[:id])
# Find out who owns the_obj
the_usr_id = the_obj.send(:usr_id)
# Repel them if they dont own the object pointed to by the id in the request URL
redirect_to("/") unless the_usr_id == session[:usr_id]
end
end # class
/controllers/sttc_controller.rb
# Serves up mostly static content.
class SttcController < ApplicationController
# Open this controller to the world
skip_before_filter :authenticate_usr
end # class
/helpers/application_helper.rb
# Methods in this helper are available to all templates in the application.
module ApplicationHelper
# An Hpricot based breadcrumb helper.
# Usage:
# bcrmb("<a href='/x/y'>About</a> | <a href='/z'>Contact</a>")
# Loads html into an hpricot and then swaps out any a-tag with a span-tag
# if the a-tag-href matches the request.path
def bcrmb(h)
# get an hpricot from the input-html
hp = Hpricot(h)
# Inside the hpricot, look for an a-tag containing the request.path
hps = hp.search("a[@href=#{request.path}]")
if (matched_a_tag = hps.first)
# I hooked one, get it's text node
txtnode = matched_a_tag.inner_text
# Inside the hpricot, swap the a-tag with a span-tag
matched_a_tag.swap("<span class='bcrmb'>#{txtnode}</span>")
end
# Pull html out of the hpricot.
return hp.to_html
end # bcrmb
# Builds a simple a-element from URL
def inputurl_column(record)
"<a target='inputurl' href='#{record.inputurl}'>#{record.inputurl}</a>"
end # inputurl_column
# Override the stck column so I can add color to it via CSS
def stck_column(record)
"<span class='#{record.stck.name}'>#{record.stck.name}</span>"
end
# Override the frgtxt column so I can add links to it and maybe show a subset of the data in it.
def frgtxt_column(record)
link_to_rndr = link_to("Render The HTML Below:", {:id => record, :action => "rndr_frgmnt", :controller => "frgmnts"}, {:target => "l"})
# Use the ERB::Util.h() method below to make sure the HTML is displayed rather than rendered.
# If they want to render, they can click the link.
# Notice that I use .slice() to limit the amount of text sent back to the browser.
# If they want to see all of the text they can .rndr_frgmnt() and use browser-view-source.
myfrgtxt = (record.frgtxt || "nil")
if (h(myfrgtxt).length > 1024)
snipmsg = "<span class='snipmsg'>SNIPPED at character number 1024. Use render and then browser-view-source to see all of it.</span>"
else
snipmsg = ""
end # if
return("<div class='frgmnt-frgtxt'> <hr />#{link_to_rndr}<hr />#{h(myfrgtxt.slice(0,1024))} <hr /> #{snipmsg} <hr /></div>")
end # frgtxt_column()
# I found this in the AS demo. They use it to show ruby code which corresponds to scaffold views.
# This helper is called in a partial here: app/views/layouts/_show_source.rhtml
# Here is a sample line from app/views/layouts/_show_source.rhtml:
# <%= show_code("controllers", "#{params[:controller]}_controller.rb") -%>
def show_code(path, filename, comment = "")
begin
file = File.open("#{File.dirname __FILE__}/../../app/#{path}/#{filename}")
<<PRE_BLOCK
<h4>/#{path}/#{filename} #{comment}</h4>
<pre><code class=\"ruby\">#{file.read.gsub("<", "<").gsub(">", ">").strip}</code></pre>
PRE_BLOCK
rescue
"#{filename} is missing"
end # begin, rescue
end # show_code
end
/helpers/sttc_helper.rb
module SttcHelper
end
The Hpricot Workbench makes use of these models:
/models/exprtype.rb
class Exprtype < ActiveRecord::Base
# Associations should come after callbacks
has_many :frgmnts
# Validations come after associations
validates_presence_of :name
validates_uniqueness_of :name, :message => " is already being used. Pick a different name."
end
/models/stck.rb
class Stck < ActiveRecord::Base
# Associations should come after callbacks
has_many :frgmnts
# Validations come after associations
validates_presence_of :name
validates_uniqueness_of :name, :message => " is already being used. Pick a different name."
end
/models/frgmnt.rb
class Frgmnt < ActiveRecord::Base
acts_as_tree :order => "name"
# Associations should come after callbacks
belongs_to :usr
belongs_to :exprtype
belongs_to :stck
# Validations come after associations
validates_presence_of :name
validates_uniqueness_of :name, :message => " is already being used. Pick a different name."
protected
def validate
case
# Ensure we have some input
when (parent == nil and inputurl == nil)
errors.add(:parent, ", and Input URL are all nil. You need one.")
# We only want 1 input
when (parent != nil and inputurl != nil)
errors.add(:parent, "and Input URL are both not nil. A fragment needs 1 (and only 1!)")
# We should not scrape ourself
when (parent == self)
errors.add(:parent, " == self. Pick a different parent.")
# The controller will set name = "record_usr_id_ne_session_usr_id" if
# I try to update a record I do not own.
when name == "record_usr_id_ne_session_usr_id"
errors.add_to_base "You can only update your records, not other's records."
# display-enumerable needs format like this: table.some-class,[1,5]
when (exprtype.name == 'display-enumerable()' and ((arg1 =~ /(.*)?(\,)(\[)(\d+)(,)(\d+)(\])$/) != 0))
errors.add(:arg1, ' Problem. display-enumerable() needs format like this: table.some-class,[1,5]')
end # case
end # validate
end
/models/usr.rb
require 'digest/sha1'
# this model expects a certain database layout and its based on the name/login pattern.
class Usr < ActiveRecord::Base
CHANGEABLE_FIELDS = ['first_name', 'last_name', 'email']
attr_accessor :password_needs_confirmation
after_save '@password_needs_confirmation = false'
after_validation :crypt_password
validates_presence_of :login, :on => :create
validates_length_of :login, :within => 3..40, :on => :create
validates_uniqueness_of :login, :on => :create
validates_uniqueness_of :email, :on => :create
validates_presence_of :password, :if => :validate_password?
validates_confirmation_of :password, :if => :validate_password?
validates_length_of :password, { :minimum => 5, :if => :validate_password? }
validates_length_of :password, { :maximum => 40, :if => :validate_password? }
# Associations should come after callbacks
has_many :frgmnts
def initialize(attributes = nil)
super
@password_needs_confirmation = false
end
def self.authenticate(login, pass)
u = find( :first, :conditions => ["login = ? AND verified = TRUE AND deleted = FALSE", login])
return nil if u.nil?
find( :first, :conditions => ["login = ? AND salted_password = ? AND verified = TRUE", login, salted_password(u.salt, hashed(pass))])
end
def self.authenticate_by_token(id, token)
# Allow logins for deleted accounts, but only via this method (and
# not the regular authenticate call)
logger.info "Attempting authorization of #{id} with #{token}"
u = find( :first, :conditions => ["id = ? AND security_token = ?", id, token])
if u
logger.info "Authenticated by token: #{u.inspect}"
else
logger.info "Not authenticated" if u.nil?
end
return nil if (u.nil? or u.token_expired?)
u.update_attributes :verified => true, :token_expiry => Clock.now
return u
end
def token_expired?
self.security_token and self.token_expiry and (Clock.now >= self.token_expiry)
end
def generate_security_token
if self.security_token.nil? or self.token_expiry.nil? or (Clock.now.to_i + token_lifetime / 2) >= self.token_expiry.to_i
token = new_security_token
return token
else
return self.security_token
end
end
def change_password(pass, confirm = nil)
self.password = pass
self.password_confirmation = confirm.nil? ? pass : confirm
@password_needs_confirmation = true
end
def token_lifetime
UsrSystem::CONFIG[:security_token_life_hours] * 60 * 60
end
# Help Active Scaffold display Usr objects.
# ref: http://activescaffold.com/tutorials/to_label
def to_label
login
end
protected
attr_accessor :password, :password_confirmation
def validate_password?
@password_needs_confirmation
end
def self.hashed(str)
return Digest::SHA1.hexdigest("change-me--#{str}--")[0..39]
end
def crypt_password
if @password_needs_confirmation
write_attribute("salt", self.class.hashed("salt-#{Clock.now}"))
write_attribute("salted_password", self.class.salted_password(salt, self.class.hashed(@password)))
end
end
def new_security_token
expiry = Time.at(Clock.now.to_i + token_lifetime)
write_attribute('security_token', self.class.hashed(self.salted_password + Clock.now.to_i.to_s + rand.to_s))
write_attribute('token_expiry', expiry)
update_without_callbacks
return self.security_token
end
def self.salted_password(salt, hashed_password)
hashed(salt + hashed_password)
end
end
|Home|Why Use?|Demos|About
|Contact|Mail List
|Group
|Hpricot By Mr _Why
|FAQ|Workbench|Workbench-RO|
|
|