The ruby sample below provides a simple client library to consume the daylife APIs. This code was graciously contributed to daylife by the enthusiastic ruby developer - Conor Hunt
This code demonstrates integration with a single API call - search_getRelatedArticles.
The code below provides hooks to receive xml encoded response objects from the daylife API.
Update: Also attached below is a Ruby Client contributed by Aditya Sarawgi. It has fixes to work with Ruby 1.9.2
#sample api call using the ruby client library classes below
require 'daylife'
a = Daylife::API.new('your api key','sharedsecret')
r = a.execute('search','getRelatedArticles', :query => 'sam adams', :limit => 5)
if(r.success?)
r.articles.each {|a| puts a.headline }
puts r.articles[1].source.daylife_url
else
# output the error message
puts "Error: #{r.code}: #{r.message}"
end
##
# Ruby classes to help consume the daylife API
#
# Author: Conor Hunt - conor.hunt AT gmail DOT com - 5/29/2007
#
# To get an API key and to learn more about the daylife API go to http://developer.daylife.com
#
# Example Usage:
#
# require 'daylife'
# a = Daylife::API.new('your api key','sharedsecret')
# r = a.execute('search','getRelatedArticles', :query => 'sam adams', :limit => 5)
# r.articles.each {|a| puts a.headline }
# puts r.articles[1].source.daylife_url
#
require 'rexml/document'
require 'net/http'
require 'md5'
require 'cgi'
module Daylife
class API
DEFAULT_PROTOCOL = 'xmlrest'
DEFAULT_VERSION = '4.8'
DEFAULT_SERVER = 'freeapi.daylife.com'
CORE_IDENTIFIER_MAP = {'search' => :query, 'topic' => :name, 'article' => :article_id, 'quote' => :quote_id, 'image' => :image_id}
def initialize(access_key, shared_secret, options = {})
@protocol = options[:protocol] || DEFAULT_PROTOCOL
@version = options[:version] || DEFAULT_VERSION
@server = options[:server] || DEFAULT_SERVER
@access_key = access_key
@shared_secret = shared_secret
end
def execute(service_name, method_name, parameters = {})
# Create the signature
core_identifier = parameters[:core_identfier] || parameters[CORE_IDENTIFIER_MAP[service_name]]
parameters[:signature] = Digest::MD5.hexdigest(@access_key + @shared_secret + core_identifier) unless parameters[:signature]
# Convert Time objects to strings with correct format
parameters[:start_time] = parameters[:start_time].strftime("%Y-%m-%d %H:%M:%S") if(parameters[:start_time] and parameters[:start_time].kind_of? Time)
parameters[:end_time] = parameters[:end_time].strftime("%Y-%m-%d %H:%M:%S") if(parameters[:end_time] and parameters[:end_time].kind_of? Time)
# Build the URL
parameters[:accesskey] = @access_key
url = "http://#{@server}/#{@protocol}/publicapi/#{@version}/#{service_name}_#{method_name}"
param_string = parameters.collect {|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join("&")
url += "?" + param_string if parameters.length > 0
http_response = Net::HTTP.get_response(URI.parse(url))
# TODO: Check for 404 etc.
Daylife::Response.new(http_response.body)
end
end
class Response
attr_accessor :document
attr_accessor :root
def initialize(response)
@document = REXML::Document.new(response)
@nodes = Daylife::Node.new(@document.elements['response/payload'])
end
def code
@document.elements["response/code"].text.to_i
end
def message
@document.elements["response/message"].text
end
def success?
self.code == 2001
end
# Pass through missing methods to the daylife node for easy access to the api responses
def method_missing(name, *args)
@nodes.send(name, args)
end
end
# This class represents a level in the Daylife response XML, used for easy access to the API results
class Node
include Enumerable
def initialize(node)
@document = node
end
def each
@document.each {|e| yield Daylife::Node.new(e) }
end
def [](index)
return Daylife::Node.new(@document[index])
end
def size
return @document.size
end
def method_missing(name, *args)
return nil if @document.kind_of? Array
name = name.to_s
if name.reverse[0..0] == 's'
# If there is an 's' then assume this is an array of elements we are trying to access
elem = Array.new
@document.elements.each("#{name[0..name.length-2]}") {|e| elem << e}
return Daylife::Node.new(elem)
else
elem = @document.elements[name]
if(elem.size > 1)
# If the element has > 1 child elements then we assume it has no content
return Daylife::Node.new(elem)
else
value = elem.text
value = value.to_i if(type = elem.attributes["type"] and (type == 'int4' or type == 'int8'))
value = Time.parse(value) if(name == 'timestamp')
return value
end
end
end
end
end