Skip to content

Instantly share code, notes, and snippets.

@steveklabnik
Created March 24, 2012 20:27
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save steveklabnik/2187514 to your computer and use it in GitHub Desktop.
Save steveklabnik/2187514 to your computer and use it in GitHub Desktop.
A Shoes hypermedia client for ALPS microblogging
require 'net/http'
require 'open-uri'
require 'hpricot'
# A simple get request should not require this much boilerplate.
def fetch_data(uri)
uri = URI(uri)
req = Net::HTTP::Get.new(uri.request_uri)
req['Accept'] = "application/xhtml+xml"
res = Net::HTTP.start(uri.host, uri.port) {|http|
http.request(req)
}
Hpricot(res.body)
end
# I also like to wrap post requests, too. This is basically taken straight
# from the Net::HTTP docs: http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTP.html
def post_data_with_auth(uri, username, password, data)
uri = URI(uri)
req = Net::HTTP::Post.new(uri.path)
req.basic_auth username, password
req.set_form_data(data)
res = Net::HTTP.start(uri.host, uri.port) do |http|
http.request(req)
end
case res
when Net::HTTPSuccess then
res
when Net::HTTPRedirection then
# We expect a redirect most of the time, and we'll want to
# follow the redirect.
res['location']
else
res.value
end
end
# An ALPS microblogging client.
#
# http://amundsen.com/hypermedia/profiles/
require 'ostruct'
require './http'
# We're going to want to save some configuration options
Config = OpenStruct.new
# The only URI we hard-code. Bonus points for making this configuration, too.
Config.root_uri = "http://alps-microblog.herokuapp.com/"
Config.current_uri = Config.root_uri
class MicroblogClient < Shoes
# We have two basic screens: the preferences setup screen, and our index,
# where all the action happens
url '/', :index
url '/preferences', :preferences
def index
current_data = fetch_data(Config.current_uri)
# We want to make sure that this gets set. We can't post stuff without it!
unless Config.username and Config.password
visit "/preferences"
end
if form = current_data.search("//form[@class='message-post']")
para "What's happening?", :size => "large"
flow do
message_text = edit_line
button "Post" do
uri = form.first['action']
Config.current_uri = post_data_with_auth(uri, Config.username, Config.password, :message => message_text.text)
visit "/"
end
end
end
if messages = current_data.search("//div[@id='messages']/ul[@class='all']")
stack do
para "All messages", :size => "large"
messages.search("li").each do |message|
text = message.search("//span[@class='message-text']").inner_html.strip
user = message.search("//span[@class='user-text']").inner_html
para "'#{text}' - @#{user}"
end
end
end
button "refresh", :right => 10, :top => 5, :align => "right" do
visit "/"
end
end
# This preferences screen will allow us to set our username and password
# so that we don't have to re-authenticate per request
def preferences
para "Account Information", :size => "large"
stack do
user_edit = nil
pass_edit = nil
root_edit = nil
flow do
para "Username:"
user_edit = edit_line
end
flow do
para "Password:"
pass_edit = edit_line :secret => true
end
flow do
para "Root URI:"
root_edit = edit_line :width => 300
root_edit.text = Config.root_uri
end
button "Save" do
Config.username = user_edit.text
Config.password = pass_edit.text
Config.root_uri = root_edit.text
visit "/"
end
end
end
end
Shoes.app :title => "ALPS Microblogging Client"
@steveklabnik
Copy link
Author

No need to be sorry!

@mamund
Copy link

mamund commented Apr 28, 2012

The rel attribute should also be treated the same way; it could contain multiple white-space separated values.

@carols10cents
Copy link

I decided to make a repo so I can describe the changes I'm making: https://github.com/clnclarinet/shoes-alps-client

@mamund
Copy link

mamund commented May 9, 2012 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment