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"
@carols10cents
Copy link

zomg 80 chars!!!11!!1!11 ❤️

@steveklabnik
Copy link
Author

inorite

@mamund
Copy link

mamund commented Apr 27, 2012

Good to see this here!

Just a note. The ALPS spec doesn't mean that only certain class names will appear on an element (link, form, etc.). You proly need to use contains() in your XPath queries when checking for a class name on a div, span, form, etc..

@steveklabnik
Copy link
Author

I'm guessing you got @clnclarinet's emails, then. :) I will have to update my code.

@mamund
Copy link

mamund commented Apr 27, 2012 via email

@carols10cents
Copy link

sorry about that, @steveklabnik ;)

@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