daylife 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ == 0.1.0 2007-12-04
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -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.
@@ -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
@@ -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'
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -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'
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/daylife")
2
+
3
+ require 'base'
4
+ require 'article'
5
+ require 'quote'
6
+ require 'search'
7
+ require 'topic'
8
+ require 'image'
9
+ require 'source'
@@ -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
@@ -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