Skip to content

Commit bac7221

Browse files
committed
first commit
0 parents  commit bac7221

13 files changed

+945
-0
lines changed

README

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
= Digg
2+
3+
Description goes here

Rakefile

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# I think this is the one that should be moved to the extension Rakefile template
2+
3+
# In rails 1.2, plugins aren't available in the path until they're loaded.
4+
# Check to see if the rspec plugin is installed first and require
5+
# it if it is. If not, use the gem version.
6+
7+
# Determine where the RSpec plugin is by loading the boot
8+
unless defined? RADIANT_ROOT
9+
ENV["RAILS_ENV"] = "test"
10+
case
11+
when ENV["RADIANT_ENV_FILE"]
12+
require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
13+
when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
14+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
15+
else
16+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
17+
end
18+
end
19+
20+
require 'rake'
21+
require 'rake/rdoctask'
22+
require 'rake/testtask'
23+
24+
rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
25+
$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
26+
require 'spec/rake/spectask'
27+
# require 'spec/translator'
28+
29+
# Cleanup the RADIANT_ROOT constant so specs will load the environment
30+
Object.send(:remove_const, :RADIANT_ROOT)
31+
32+
extension_root = File.expand_path(File.dirname(__FILE__))
33+
34+
task :default => :spec
35+
task :stats => "spec:statsetup"
36+
37+
desc "Run all specs in spec directory"
38+
Spec::Rake::SpecTask.new(:spec) do |t|
39+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
40+
t.spec_files = FileList['spec/**/*_spec.rb']
41+
end
42+
43+
namespace :spec do
44+
desc "Run all specs in spec directory with RCov"
45+
Spec::Rake::SpecTask.new(:rcov) do |t|
46+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
47+
t.spec_files = FileList['spec/**/*_spec.rb']
48+
t.rcov = true
49+
t.rcov_opts = ['--exclude', 'spec', '--rails']
50+
end
51+
52+
desc "Print Specdoc for all specs"
53+
Spec::Rake::SpecTask.new(:doc) do |t|
54+
t.spec_opts = ["--format", "specdoc", "--dry-run"]
55+
t.spec_files = FileList['spec/**/*_spec.rb']
56+
end
57+
58+
[:models, :controllers, :views, :helpers].each do |sub|
59+
desc "Run the specs under spec/#{sub}"
60+
Spec::Rake::SpecTask.new(sub) do |t|
61+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
62+
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
63+
end
64+
end
65+
66+
# Hopefully no one has written their extensions in pre-0.9 style
67+
# desc "Translate specs from pre-0.9 to 0.9 style"
68+
# task :translate do
69+
# translator = ::Spec::Translator.new
70+
# dir = RAILS_ROOT + '/spec'
71+
# translator.translate(dir, dir)
72+
# end
73+
74+
# Setup specs for stats
75+
task :statsetup do
76+
require 'code_statistics'
77+
::STATS_DIRECTORIES << %w(Model\ specs spec/models)
78+
::STATS_DIRECTORIES << %w(View\ specs spec/views)
79+
::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
80+
::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
81+
::CodeStatistics::TEST_TYPES << "Model specs"
82+
::CodeStatistics::TEST_TYPES << "View specs"
83+
::CodeStatistics::TEST_TYPES << "Controller specs"
84+
::CodeStatistics::TEST_TYPES << "Helper specs"
85+
::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
86+
end
87+
88+
namespace :db do
89+
namespace :fixtures do
90+
desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
91+
task :load => :environment do
92+
require 'active_record/fixtures'
93+
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
94+
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
95+
Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
96+
end
97+
end
98+
end
99+
end
100+
end
101+
102+
desc 'Generate documentation for the digg extension.'
103+
Rake::RDocTask.new(:rdoc) do |rdoc|
104+
rdoc.rdoc_dir = 'rdoc'
105+
rdoc.title = 'DiggExtension'
106+
rdoc.options << '--line-numbers' << '--inline-source'
107+
rdoc.rdoc_files.include('README')
108+
rdoc.rdoc_files.include('lib/**/*.rb')
109+
end
110+
111+
# For extensions that are in transition
112+
desc 'Test the digg extension.'
113+
Rake::TestTask.new(:test) do |t|
114+
t.libs << 'lib'
115+
t.pattern = 'test/**/*_test.rb'
116+
t.verbose = true
117+
end
118+
119+
# Load any custom rakefiles for extension
120+
Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }

app/models/digg.rb

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# = Digg-Ruby v0.1
2+
# Ruby wrapper for the Digg.com API
3+
# http://code.google.com/p/digg-ruby
4+
#
5+
# Author:: John Wulff <[email protected]>
6+
# Copyright:: Copyright (c) 2007 John Wulff <[email protected]>
7+
# License:: MIT <http://www.opensource.org/licenses/mit-license.php>
8+
#
9+
# USAGE:
10+
# require 'digg'
11+
# digg = Digg.new # create a digg client
12+
# digg.stories.each do |story| # fetch and print titles of stories
13+
# puts story.title
14+
# end
15+
# digg.stories('stories/topic/apple', :count => 5) # fetch 5 stories with topic `Apple`
16+
#
17+
# Use the same style for users, events, topics, and errors
18+
#
19+
# See http://apidoc.digg.com for a full listing of possible calls.
20+
21+
# TODO:
22+
# - convert attributes like { :topic => 'apple' } to Digg style endpoint
23+
# - also return comment events, currently only returns diggs
24+
# - check calls againts list of valid endpoints and arguments
25+
# - load relational elements as proper objects
26+
# - refactor to not use class_eval
27+
28+
require 'net/http'
29+
require 'rexml/document'
30+
require 'rexml/xpath'
31+
require 'cgi'
32+
33+
34+
DIGG_API_URL = 'http://services.digg.com'
35+
USER_AGENT = 'http://code.google.com/p/digg-ruby'
36+
DEFAULT_API_KEY = 'http://code.google.com/p/digg-ruby'
37+
38+
#CONTENT_CLASSES = :user, :story, :digg, :comment, :topic, :error, :container
39+
40+
#CONTAINER_CONTENTS_MAP = { :users => :user,
41+
# :stories => :story,
42+
# :events => :digg,
43+
# :topics => :topic,
44+
# :errors => :error }
45+
46+
#overwriting the original defined variables
47+
CONTENT_CLASSES = :user, :story, :digg, :comment, :topic, :error, :container, :galleryphoto
48+
49+
CONTAINER_CONTENTS_MAP = { :users => :user,
50+
:stories => :story,
51+
:events => :digg,
52+
:topics => :topic,
53+
:errors => :error,
54+
:galleries => :galleryphoto}
55+
56+
57+
58+
CONTAINER_ATTRIBUTES = :name, :short_name
59+
CONTAINER_ELEMENTS = []
60+
CONTAINER_ELEMENTS_AS_OBJECTS = []
61+
62+
COMMENT_ATTRIBUTES = []
63+
COMMENT_ELEMENTS = []
64+
COMMENT_ELEMENTS_AS_OBJECTS = []
65+
66+
STORIES_ATTRIBUTES = :timestamp, :min_date, :total, :offset, :count
67+
STORY_ATTRIBUTES = :id, :link, :submit_date, :diggs, :comments, :href, :status
68+
STORY_ELEMENTS = :title, :description
69+
STORY_ELEMENTS_AS_OBJECTS = :user , :topic, :container
70+
VALID_STORY_ENDPOINT_ARGUMENTS = :min_submit_date, :max_submit_date,
71+
:min_promote_date, :max_promote_date,
72+
:sort, :count, :offset, :domain, :link
73+
74+
USERS_ATTRIBUTES = :timestamp, :total, :offset, :count
75+
USER_ATTRIBUTES = :name, :icon, :registered, :profileviews
76+
USER_ELEMENTS = []
77+
USER_ELEMENTS_AS_OBJECTS = []
78+
VALID_USER_ENDPOINT_ARGUMENTS = :sort, :count, :offset
79+
80+
EVENTS_ATTRIBUTES = :timestamp, :min_date, :total, :offset, :count
81+
DIGG_ATTRIBUTES = :date, :story, :id, :user, :status
82+
DIGG_ELEMENTS = []
83+
DIGG_ELEMENTS_AS_OBJECTS = []
84+
VALID_EVENT_ENDPOINT_ARGUMENTS = :min_date, :max_date, :sort, :count, :offset
85+
86+
TOPICS_ATTRIBUTES = [ :timestamp ]
87+
TOPIC_ATTRIBUTES = :name, :short_name
88+
TOPIC_ELEMENTS = []
89+
TOPIC_ELEMENTS_AS_OBJECTS = [ :container ]
90+
VALID_TOPIC_ENDPOINT_ARGUMENTS = []
91+
92+
ERRORS_ATTRIBUTES = [ :timestamp ]
93+
ERROR_ATTRIBUTES = :code, :message
94+
ERROR_ELEMENTS = []
95+
ERROR_ELEMENTS_AS_OBJECTS = []
96+
VALID_ERROR_ENDPOINT_ARGUMENTS = []
97+
98+
99+
100+
101+
#Added variables:
102+
#VALID_DIGG_ENDPOINT_ARGUMENTS
103+
104+
#The following are added to fetch the images from the gallery
105+
#GALLERIES_ATTRIBUTES
106+
#GALLERYPHOTO_ATTRIBUTES
107+
#GALLERYPHOTO_ELEMENTS
108+
#GALLERYPHOTO_ELEMENTS_AS_OBJECTS
109+
#VALID_GALLERYPHOTO_ENDPOINT_ARGUMENTS
110+
111+
112+
VALID_DIGG_ENDPOINT_ARGUMENTS = :min_date, :max_date, :sort, :count, :offset
113+
114+
#Adding Gallery item
115+
GALLERIES_ATTRIBUTES = [ :timestamp, :min_date, :total, :offset, :count ]
116+
GALLERYPHOTO_ATTRIBUTES = [ :id, :submit_name, :href, :src ]
117+
GALLERYPHOTO_ELEMENTS = [ :title ]
118+
GALLERYPHOTO_ELEMENTS_AS_OBJECTS = []
119+
VALID_GALLERYPHOTO_ENDPOINT_ARGUMENTS = [ :count ]
120+
121+
122+
123+
124+
125+
126+
127+
128+
class Digg
129+
def initialize(api_key = DEFAULT_API_KEY)
130+
@api_key = api_key
131+
end
132+
133+
def fetch(path, arguments = {})
134+
host, port, path = assemble_url(path, arguments)
135+
response = Net::HTTP.start(host, port) do |http|
136+
http.get path,
137+
'User-Agent' => USER_AGENT,
138+
'Accept' => 'application/xml'
139+
end
140+
xml = REXML::Document.new response.body
141+
return xml
142+
end
143+
144+
def assemble_url(path, arguments = {})
145+
uri = URI.parse(DIGG_API_URL + '/' + path)
146+
path = uri.path + assemble_arguments(arguments)
147+
return uri.host, uri.port, path
148+
end
149+
150+
def assemble_arguments(arguments = {})
151+
args = "?appkey=#{CGI::escape @api_key}"
152+
arguments.each_pair do |field, value|
153+
args += "&#{field}=#{CGI::escape value.to_s}"
154+
end
155+
return args
156+
end
157+
158+
CONTENT_CLASSES.each do |content_class|
159+
content_class = content_class.to_s.capitalize
160+
# Define the content class.
161+
class_eval <<-EOV
162+
class #{content_class}
163+
(#{content_class.upcase}_ATTRIBUTES +
164+
#{content_class.upcase}_ELEMENTS +
165+
#{content_class.upcase}_ELEMENTS_AS_OBJECTS).each { |x| attr_accessor x }
166+
167+
def self.populate_from_xml(xml)
168+
content = #{content_class}.new
169+
for attribute in #{content_class.upcase}_ATTRIBUTES
170+
if xml
171+
content.send attribute.to_s + '=', xml.attributes[attribute.to_s]
172+
end
173+
end
174+
for element in #{content_class.upcase}_ELEMENTS
175+
content.send element.to_s + '=', xml.elements[element.to_s].text
176+
end
177+
for type in #{content_class.upcase}_ELEMENTS_AS_OBJECTS
178+
klass = eval type.to_s.capitalize
179+
content.send(type.to_s + '=', klass.populate_from_xml(REXML::XPath.first(xml, type.to_s)))
180+
end
181+
return content
182+
end
183+
end
184+
EOV
185+
end
186+
187+
CONTAINER_CONTENTS_MAP.each_pair do |container_type, contents_type|
188+
container_class = container_type.to_s.capitalize
189+
content_class = contents_type.to_s.capitalize
190+
191+
# Define the container specific fetcher.
192+
class_eval <<-EOV
193+
def #{container_type}(path = '#{container_type}', arguments = {})
194+
arguments.each_pair do |field, value|
195+
unless VALID_#{content_class.upcase}_ENDPOINT_ARGUMENTS.include?(field.to_sym)
196+
raise field.to_s + ' is not a valid argument for the #{container_class} endpoint'
197+
end
198+
end
199+
#{container_class}.populate_from_xml(fetch(path, arguments))
200+
end
201+
EOV
202+
203+
# Define the xml to container/contents processor for this container.
204+
class_eval <<-EOV
205+
class #{container_class} < Array
206+
#{container_class.upcase}_ATTRIBUTES.each { |x| attr_accessor x }
207+
208+
def self.populate_from_xml(xml)
209+
container = #{container_class}.new
210+
for attribute in #{container_class.upcase}_ATTRIBUTES
211+
x = REXML::XPath.first xml, '//#{container_type}'
212+
if x
213+
container.send attribute.to_s + '=', x.attributes[attribute.to_s]
214+
end
215+
end
216+
217+
REXML::XPath.each(xml, '//#{contents_type}') do |x|
218+
container << #{content_class}.populate_from_xml(x)
219+
end
220+
221+
return container
222+
end
223+
end
224+
EOV
225+
end
226+
end
227+

0 commit comments

Comments
 (0)