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.
@@ -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