daylife 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +25 -0
- data/README.txt +27 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +71 -0
- data/config/requirements.rb +17 -0
- data/lib/daylife.rb +9 -0
- data/lib/daylife/article.rb +44 -0
- data/lib/daylife/base.rb +167 -0
- data/lib/daylife/image.rb +19 -0
- data/lib/daylife/quote.rb +29 -0
- data/lib/daylife/search.rb +43 -0
- data/lib/daylife/source.rb +5 -0
- data/lib/daylife/topic.rb +35 -0
- data/lib/daylife/version.rb +9 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/test/test_daylife.rb +11 -0
- data/test/test_helper.rb +2 -0
- metadata +82 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Bobby Uhlenbrock
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/daylife.rb
|
9
|
+
lib/daylife/version.rb
|
10
|
+
lib/daylife/base.rb
|
11
|
+
lib/daylife/article.rb
|
12
|
+
lib/daylife/quote.rb
|
13
|
+
lib/daylife/search.rb
|
14
|
+
lib/daylife/topic.rb
|
15
|
+
lib/daylife/image.rb
|
16
|
+
lib/daylife/source.rb
|
17
|
+
log/debug.log
|
18
|
+
script/destroy
|
19
|
+
script/generate
|
20
|
+
script/txt2html
|
21
|
+
setup.rb
|
22
|
+
tasks/deployment.rake
|
23
|
+
tasks/environment.rake
|
24
|
+
test/test_daylife.rb
|
25
|
+
test/test_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
== Daylife API Library for Ruby
|
2
|
+
|
3
|
+
Copyright Bobby Uhlenbrock (buhlenbrock@thinkbarefoot.com) 2007
|
4
|
+
|
5
|
+
A fully featured Ruby library for accessing the Daylife DayPI
|
6
|
+
|
7
|
+
Daylife.authenticate('8befa1cf0a7c0291613242235638a662', '2e548ef751397c653752057adcff0c9f')
|
8
|
+
articles = Daylife::Article.get_related_articles('03cV5zI2fk03s')
|
9
|
+
|
10
|
+
When in doubt check the Daylife DayPI documentation:
|
11
|
+
|
12
|
+
http://developer.daylife.com/docs/DayPI101
|
13
|
+
|
14
|
+
=== Installation and Usage
|
15
|
+
|
16
|
+
To get an accesskey:
|
17
|
+
|
18
|
+
http://developer.daylife.com/member/register
|
19
|
+
|
20
|
+
To install:
|
21
|
+
|
22
|
+
sudo gem install path/to/daylife-xxx.gem
|
23
|
+
|
24
|
+
To use:
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'daylife'
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'daylife/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Bobby Uhlenbrock' # can also be an array of Authors
|
4
|
+
EMAIL = "buhlenbrock@thinkbarefoot.com"
|
5
|
+
DESCRIPTION = "A fully featured Ruby library for accessing the Daylife DayPI"
|
6
|
+
GEM_NAME = 'daylife' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'daylife' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "unknown"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = Daylife::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
RDOC_OPTS = ['--quiet', '--title', 'daylife documentation',
|
36
|
+
"--opname", "index.html",
|
37
|
+
"--line-numbers",
|
38
|
+
"--main", "README",
|
39
|
+
"--inline-source"]
|
40
|
+
|
41
|
+
class Hoe
|
42
|
+
def extra_deps
|
43
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
44
|
+
@extra_deps
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate all the Rake tasks
|
49
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
50
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
51
|
+
p.author = AUTHOR
|
52
|
+
p.description = DESCRIPTION
|
53
|
+
p.email = EMAIL
|
54
|
+
p.summary = DESCRIPTION
|
55
|
+
p.url = HOMEPATH
|
56
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
57
|
+
p.test_globs = ["test/**/test_*.rb"]
|
58
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
59
|
+
|
60
|
+
# == Optional
|
61
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
62
|
+
#p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
63
|
+
|
64
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
69
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
70
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
71
|
+
hoe.rsync_args = '-av --delete --ignore-errors'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'daylife'
|
data/lib/daylife.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class Daylife::Article < Daylife::API
|
2
|
+
|
3
|
+
attr_accessor :article_id, :daylife_url, :excerpt, :headline, :image, :quote_story_relevance, :source, :timestamp, :url
|
4
|
+
|
5
|
+
def self.core_identifier
|
6
|
+
return :article_id
|
7
|
+
end
|
8
|
+
|
9
|
+
# This function returns basic information about a given article.
|
10
|
+
def self.get_info(article_id, parameters={})
|
11
|
+
get :get_info, parameters.merge(:article_id => article_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
# This method is used to retrieve articles that are related to the given article.
|
15
|
+
def self.get_related_articles(article_id, parameters={})
|
16
|
+
get :get_related_articles, parameters.merge(:article_id => article_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
# This method is used to retrieve images from articles related to the given article.
|
20
|
+
def self.get_related_images(article_id, parameters={})
|
21
|
+
get :get_related_images, parameters.merge(:article_id => article_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
# This method is used to retrieve quotes from articles related to the given article.
|
25
|
+
def self.get_related_quotes(article_id, parameters={})
|
26
|
+
get :get_related_quotes, parameters.merge(:article_id => article_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
# This method is used to retrieve topics from articles related to the given article.
|
30
|
+
def self.get_related_topics(article_id, parameters={})
|
31
|
+
get :get_related_topics, parameters.merge(:article_id => article_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
# This method is used to retrieve quotes from within the given article.
|
35
|
+
def self.get_quotes(article_id, parameters={})
|
36
|
+
get :get_quotes, parameters.merge(:article_id => article_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
# This method is used to retrieve topics from within the given article.
|
40
|
+
def self.get_topics(article_id, parameters={})
|
41
|
+
get :get_topics, parameters.merge(:article_id => article_id)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/daylife/base.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'net/http'
|
3
|
+
require 'md5'
|
4
|
+
require 'cgi'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
module Daylife
|
8
|
+
|
9
|
+
class DaylifeError < StandardError; end
|
10
|
+
class BadResponse < DaylifeError; end
|
11
|
+
class BadRequest < DaylifeError; end
|
12
|
+
class ObjectNotSupported < DaylifeError; end
|
13
|
+
|
14
|
+
# The accesskey and shared_secret are stored within the Daylife::API class
|
15
|
+
# where they are used to create the unique signature for each call.
|
16
|
+
def self.authenticate(accesskey, shared_secret)
|
17
|
+
API.auth[:accesskey] = accesskey
|
18
|
+
API.auth[:shared_secret] = shared_secret
|
19
|
+
end
|
20
|
+
|
21
|
+
# DayPI 101: http://developer.daylife.com/docs/DayPI101
|
22
|
+
#
|
23
|
+
# The DayPI call responses include codes indicating success or failure as well as a message
|
24
|
+
# with some explanation or helpful tip in cases of failure. For acurrent list of response/error
|
25
|
+
# codes and messages, see http://developer.daylife.com/docs/Response_Error_Codes
|
26
|
+
#
|
27
|
+
# Sample Usage
|
28
|
+
#
|
29
|
+
# Daylife.authenticate('8befa1cf0a7c0291613242235638a662', '2e548ef751397c653752057adcff0c9f')
|
30
|
+
# articles = Daylife::Article.get_related_articles('03cV5zI2fk03s')
|
31
|
+
class API
|
32
|
+
|
33
|
+
@@auth = { :accesskey => '', :shared_secret => '' }
|
34
|
+
|
35
|
+
def initialize(props={})
|
36
|
+
props.each do |key, val|
|
37
|
+
setter = "#{key}=".intern
|
38
|
+
self.send setter, val if respond_to? setter
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.auth
|
43
|
+
@@auth
|
44
|
+
end
|
45
|
+
|
46
|
+
# Make a get request to the input method with a parameters hash.
|
47
|
+
# Returbs an instanceor list of instances of API objects.
|
48
|
+
#
|
49
|
+
# Article.get :get_topics, :article_id => 03cV5zI2fk03s
|
50
|
+
#
|
51
|
+
# Generates the request:
|
52
|
+
#
|
53
|
+
# article_getTopics?accesskey=<accesskey>&signature=<signature>&article_id=03cV5zI2fk03s
|
54
|
+
def self.get(method, parameters={})
|
55
|
+
parameters = @@auth.merge(parameters)
|
56
|
+
resp = Request.new(methodize(method)).get(parameters)
|
57
|
+
resp.parse
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates a Daylife style method name from a symbol.
|
61
|
+
# Article.methodize :get_topics #=> "article_getTopics"
|
62
|
+
def self.methodize(method)
|
63
|
+
"#{name.split('::').last.downcase}_#{method.to_s.gsub(/_([a-z])/) { $1.upcase }}"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class Request
|
69
|
+
|
70
|
+
BASE_URL = 'http://freeapi.daylife.com/xmlrest/publicapi/4.3/'
|
71
|
+
|
72
|
+
def initialize(method)
|
73
|
+
@method = method
|
74
|
+
end
|
75
|
+
|
76
|
+
def get(parameters)
|
77
|
+
# Create the signature
|
78
|
+
parameters[:signature] = create_signature(@method.split("_").first, parameters) unless parameters[:signature]
|
79
|
+
parameters.delete_if { |key, value| key == :shared_secret }
|
80
|
+
# Convert Time objects to strings with correct format
|
81
|
+
parameters[:start_time] = parameters[:start_time].strftime("%Y-%m-%d %H:%M:%S") if (parameters[:start_time] && parameters[:start_time].kind_of?(Time))
|
82
|
+
parameters[:end_time] = parameters[:end_time].strftime("%Y-%m-%d %H:%M:%S") if (parameters[:end_time] && parameters[:end_time].kind_of?(Time))
|
83
|
+
# Build the URL
|
84
|
+
query_string = "#{@method}?" << build_params(parameters)
|
85
|
+
url = URI.parse(BASE_URL + query_string)
|
86
|
+
puts url
|
87
|
+
response = Net::HTTP.get_response(url)
|
88
|
+
if response.kind_of?(Net::HTTPSuccess)
|
89
|
+
return Response.new(response.body)
|
90
|
+
else
|
91
|
+
raise Daylife::BadRequest, "Failed with message: #{response.code}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
def build_params(parameters)
|
98
|
+
parameters.collect { |key, value|
|
99
|
+
"#{key.to_s}=#{CGI::escape(value.to_s)}" if value
|
100
|
+
}.compact.join "&"
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_signature(news_object, parameters)
|
104
|
+
core_identifier = Module.const_get("Daylife").const_get(news_object.capitalize).core_identifier.to_sym
|
105
|
+
Digest::MD5.hexdigest(parameters[:accesskey] + parameters[:shared_secret] + parameters[core_identifier])
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
class Response
|
111
|
+
|
112
|
+
def initialize(response)
|
113
|
+
@document = REXML::Document.new(response)
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse
|
117
|
+
if self.success?
|
118
|
+
objects = @document.elements['/response/payload']
|
119
|
+
# Prevent empty requests from showing up in the array.
|
120
|
+
unless objects.size == 1 && objects[0].children.size == 0
|
121
|
+
objects.collect { |o| get_object(o) }
|
122
|
+
else
|
123
|
+
return []
|
124
|
+
end
|
125
|
+
else
|
126
|
+
raise Daylife::BadResponse, "Failed with message: #{self.message} (#{self.code})"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def code
|
131
|
+
@document.elements['/response/code'].text.to_i
|
132
|
+
end
|
133
|
+
|
134
|
+
def message
|
135
|
+
@document.elements['/response/message/'].text
|
136
|
+
end
|
137
|
+
|
138
|
+
def success?
|
139
|
+
self.code == 2001 || self.code == 2002
|
140
|
+
end
|
141
|
+
|
142
|
+
protected
|
143
|
+
|
144
|
+
def get_object(element)
|
145
|
+
begin
|
146
|
+
klass = Module.const_get("Daylife").const_get(element.name.capitalize)
|
147
|
+
rescue
|
148
|
+
raise ObjectNotSupported, "Daylife::#{element.name.capitalize}"
|
149
|
+
end
|
150
|
+
children = Hash.new
|
151
|
+
# Iterate through the nodes recursively.
|
152
|
+
element.children.each do |child|
|
153
|
+
if child.children.size > 1
|
154
|
+
children[child.name] = get_object(child)
|
155
|
+
else
|
156
|
+
value = child.text
|
157
|
+
value = child.to_i if (type = child.attributes["type"] && (type == 'int4' || type == 'int8'))
|
158
|
+
value = Time.parse(value) if (child.name == 'timestamp')
|
159
|
+
children[child.name] = value
|
160
|
+
end
|
161
|
+
end
|
162
|
+
klass.new children
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Daylife::Image < Daylife::API
|
2
|
+
|
3
|
+
attr_accessor :caption, :credit, :daylife_url, :height, :image_id, :source, :timestamp, :thumb_url, :url, :width
|
4
|
+
|
5
|
+
def self.core_identifier
|
6
|
+
return :image_id
|
7
|
+
end
|
8
|
+
|
9
|
+
# This function returns basic information about a given image.
|
10
|
+
def self.get_info(image_id, parameters={})
|
11
|
+
get :get_info, parameters.merge(:image_id => image_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
# This method is used to retrieve topics that are related to the given image.
|
15
|
+
def self.get_related_topics(image_id, parameters={})
|
16
|
+
get :get_related_topics, parameters.merge(:image_id => image_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Daylife::Quote < Daylife::API
|
2
|
+
|
3
|
+
attr_accessor :article, :name, :quote_id, :quote_text, :source, :timestamp
|
4
|
+
|
5
|
+
def self.core_identifier
|
6
|
+
return :quote_id
|
7
|
+
end
|
8
|
+
|
9
|
+
# This method returns basic information for a quote.
|
10
|
+
def self.get_info(quote_id, parameters={})
|
11
|
+
get :get_info, parameters.merge(:quote_id => quote_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
# This method is used to retrieve articles that are related to the article that contains the given quote.
|
15
|
+
def self.get_related_articles(quote_id, parameters={})
|
16
|
+
get :get_related_articles, parameters.merge(:quote_id => quote_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
# This method is used to retrieve quotes from articles that are related to the article containing the given quote.
|
20
|
+
def self.get_related_quotes(quote_id, parameters={})
|
21
|
+
get :get_related_quotes, parameters.merge(:quote_id => quote_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
# This method is used to retrieve topics from articles that are related to the article containing the given quote.
|
25
|
+
def self.get_related_topics(quote_id, parameters={})
|
26
|
+
get :get_related_topics, parameters.merge(:quote_id => quote_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|