csexton-twitter_archive 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-12-28
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009 Christopher Sexton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,29 @@
1
+ bin/twitter_archive
2
+ CHANGELOG
3
+ config/test.yml
4
+ lib/twitter_archive/backends/blogger/base.rb
5
+ lib/twitter_archive/backends/blogger/blogger.rb
6
+ lib/twitter_archive/backends/blogger/post_body.html.erb
7
+ lib/twitter_archive/backends/blogger/README
8
+ lib/twitter_archive/backends/blogger_archive.rb
9
+ lib/twitter_archive/backends/yaml_archive.rb
10
+ lib/twitter_archive/base.rb
11
+ lib/twitter_archive/runner.rb
12
+ lib/twitter_archive/version.rb
13
+ lib/twitter_archive.rb
14
+ LICENSE
15
+ Manifest
16
+ Rakefile
17
+ README.rdoc
18
+ script/console
19
+ script/destroy
20
+ script/generate
21
+ spec/backends/blogger_archive_spec.rb
22
+ spec/backends/yaml_archive_spec.rb
23
+ spec/fixtures/blogger_authenticate_response.yml
24
+ spec/fixtures/twitter_response.yml
25
+ spec/spec.opts
26
+ spec/spec_helper.rb
27
+ spec/twitter_archive_spec.rb
28
+ tasks/rspec.rake
29
+ twitter_archive.gemspec
data/README.rdoc ADDED
@@ -0,0 +1,91 @@
1
+ = twitter_archive
2
+
3
+ * http://github.com/csexton/twitter_archive
4
+
5
+ == DESCRIPTION:
6
+
7
+ An archiving utility for Twitter.
8
+
9
+ I use my blog as a way to chronicle the things in my life, and I noticed with the introduction of Twitter into my normal routine I found that I was not blogging as much. What I wanted to be able to do is incorporate the twitters into my blog timeline. And while I was able to do some JavaScript trickery to display the twitters on my blog, they were not *in* the blog. Now if I ever want to go back and look up exactly what day my son got his second tooth, I can do so by digging through the blog archives.
10
+
11
+ twitter_archive supports multiple backends. I use Blogger, so I have support for that, as well as a very simple yaml archive backend that was intended for testing, but would provide a pretty good (and easy to parse) plan text backup of Twitter.
12
+
13
+
14
+ == FEATURES/PROBLEMS:
15
+
16
+ Archive your Twitter messages.
17
+
18
+ == SYNOPSIS:
19
+
20
+ === YAML ARCHIVE BACKEND:
21
+
22
+ This requires a config file placed in the user's home directory:
23
+
24
+ Example ~/twitter_archive.yml for use with the yaml archive backend:
25
+
26
+ accounts:
27
+ - name: fuzzymonk
28
+ - name: amperecat
29
+ - name: jnunemaker
30
+ yaml_file: /home/your-user-name/twitter_archive/posts.yml
31
+
32
+ You can enter mutiple twitter accounts, and it will simply interate through them. You should know that twitter_archive will make seperate requests for each account, so unles you have been {IP whitelisted}[http://twitter.com/help/request_whitelisting] by Twitter you can hit their rate limits pretty easily.
33
+
34
+ === BLOGGER ARCHIVE BACKEND:
35
+
36
+ This requires a config file placed in the user's home directory:
37
+
38
+ Example ~/twitter_archive.yml for use with the Blogger archive backend:
39
+
40
+ accounts:
41
+ - name: fuzzymonk
42
+ blogger_user: blogger-user # Normally your gmail address
43
+ blogger_pass: blogger-password
44
+ blogger_title: Twitter # The title you want for you blog post
45
+ blogger_id: 1234567891234567890 #
46
+ backend: blogger
47
+
48
+ To find your Blogger Blog ID refer to the {Blogger Help Center}[http://help.blogger.com/bin/answer.py?hl=en&answer=42191]
49
+
50
+ twitter_archive was intended to be run as a cron job, prolly once a day. It will post in a digest format, collecting all the twitters into one blog post.
51
+
52
+ == INSTALL:
53
+
54
+ Get the gem:
55
+
56
+ sudo gem install twitter_archive
57
+
58
+ Edit crontab to add twitter_archive:
59
+
60
+ $ crontab -e
61
+
62
+ Then Add a line like the following:
63
+
64
+ 0 0 * * * twitter_archive > /home/your-user-name/logs/twitter_archive.log
65
+
66
+ This will run everyday at midnight. You can leave off the "> /home/.../twitter_archive.log" if you don't want to keep logs.
67
+
68
+ == LICENSE:
69
+
70
+ (The MIT License)
71
+
72
+ Copyright (c) 2009 Christopher Sexton
73
+
74
+ Permission is hereby granted, free of charge, to any person obtaining
75
+ a copy of this software and associated documentation files (the
76
+ 'Software'), to deal in the Software without restriction, including
77
+ without limitation the rights to use, copy, modify, merge, publish,
78
+ distribute, sublicense, and/or sell copies of the Software, and to
79
+ permit persons to whom the Software is furnished to do so, subject to
80
+ the following conditions:
81
+
82
+ The above copyright notice and this permission notice shall be
83
+ included in all copies or substantial portions of the Software.
84
+
85
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
89
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
90
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
91
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ ProjectName = 'twitter_archive'
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'echoe'
6
+ require 'spec/rake/spectask'
7
+ require "lib/#{ProjectName}/version"
8
+
9
+ Echoe.new(ProjectName, TwitterArchive::VERSION) do |p|
10
+ p.description = "Twitter archive utility"
11
+ p.url = "http://github.com/csexton/twitter_archive"
12
+ p.author = "Christohper Sexton"
13
+ p.email = "csexton@gmail.com"
14
+ p.extra_deps = [['twitter', '>= 0.4'], ['hpricot', '>= 0.6']]
15
+ p.need_tar_gz = false
16
+ p.docs_host = "http://github.com/csexton/twitter_archive/wikis"
17
+ end
18
+
19
+ desc 'Preps the gem for a new release'
20
+ task :prepare do
21
+ %w[manifest build_gemspec].each do |task|
22
+ Rake::Task[task].invoke
23
+ end
24
+ end
25
+
26
+ Dir['tasks/**/*.rake'].each { |t| load t }
27
+
28
+ Rake::Task[:default].prerequisites.clear
29
+ task :default => :spec
30
+
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require "#{File.dirname(__FILE__)}/../lib/twitter_archive"
3
+
4
+ TwitterArchive::Runner::runner
data/config/test.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ accounts:
3
+ - name: fuzzymonk
4
+ - name: jnunemaker
5
+ backend: yaml
@@ -0,0 +1,31 @@
1
+ This was taken from GDataRuby Gem by Dion Almaer.
2
+
3
+ Mostly because it was not current on rubyforge, and I could get more recent source on github.
4
+
5
+ http://gdata-ruby.rubyforge.net
6
+
7
+ LICENSE
8
+
9
+ (The MIT License)
10
+
11
+ Copyright (c) 2007 FIX
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining
14
+ a copy of this software and associated documentation files (the
15
+ 'Software'), to deal in the Software without restriction, including
16
+ without limitation the rights to use, copy, modify, merge, publish,
17
+ distribute, sublicense, and/or sell copies of the Software, and to
18
+ permit persons to whom the Software is furnished to do so, subject to
19
+ the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be
22
+ included in all copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+
@@ -0,0 +1,76 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'rubygems'
5
+ require 'hpricot'
6
+
7
+ #
8
+ # Make it east to use some of the convenience methods using https
9
+ #
10
+ module Net
11
+ class HTTPS < HTTP
12
+ def initialize(address, port = nil)
13
+ super(address, port)
14
+ self.use_ssl = true
15
+ end
16
+ end
17
+ end
18
+
19
+ module GData
20
+ GOOGLE_LOGIN_URL = URI.parse('https://www.google.com/accounts/ClientLogin')
21
+
22
+ class Base
23
+
24
+ attr_reader :service, :source, :url
25
+
26
+ def initialize(service, source, url)
27
+ @service = service
28
+ @source = source
29
+ @url = url
30
+ end
31
+
32
+ def authenticate(email, password)
33
+ $VERBOSE = nil
34
+ response = Net::HTTPS.post_form(GOOGLE_LOGIN_URL,
35
+ {'Email' => email,
36
+ 'Passwd' => password,
37
+ 'source' => source,
38
+ 'service' => service })
39
+
40
+ response.error! unless response.kind_of? Net::HTTPSuccess
41
+
42
+ @headers = {
43
+ 'Authorization' => "GoogleLogin auth=#{response.body.split(/=/).last}",
44
+ 'GData-Version' => '2',
45
+ 'Content-Type' => 'application/atom+xml'
46
+ }
47
+ end
48
+
49
+ def request(path)
50
+ response, data = get(path)
51
+ data
52
+ end
53
+
54
+ def get(path)
55
+ response, data = http.get(path, @headers)
56
+ end
57
+
58
+ def post(path, entry)
59
+ http.post(path, entry, @headers)
60
+ end
61
+
62
+ def put(path, entry)
63
+ h = @headers
64
+ h['X-HTTP-Method-Override'] = 'PUT' # just to be nice, add the method override
65
+
66
+ http.put(path, entry, h)
67
+ end
68
+
69
+ def http
70
+ conn = Net::HTTP.new(url, 80)
71
+ #conn.set_debug_output $stderr
72
+ conn
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ require 'builder'
3
+
4
+ module GData
5
+
6
+ class Blogger < GData::Base
7
+
8
+ def initialize(blog_id, entry_id=nil)
9
+ @blog_id = blog_id
10
+ @entry_id = entry_id
11
+ super 'blogger', 'gdata-ruby', 'www.blogger.com'
12
+ end
13
+
14
+ def feed
15
+ request "/feeds/#{@blog_id}/posts/default"
16
+ end
17
+
18
+ def list_blogs(profile_id)
19
+ request "/feeds/#{profile_id}/blogs"
20
+ end
21
+
22
+ def entry
23
+ @entry ||= Hpricot(request("/feeds/#{@blog_id}/posts/default/#{@entry_id}"))
24
+ end
25
+
26
+ def enclosure
27
+ entry.search('//link[@rel="enclosure"]')
28
+ end
29
+
30
+ def enclosure?
31
+ enclosure.any?
32
+ end
33
+
34
+ def add_enclosure(enclosure_url, enclosure_length)
35
+ raise "An enclosure has already been added to this entry" if enclosure?
36
+ # todo(stevejenson): replace with builder
37
+ entry.search('//entry').append(%Q{<link rel="enclosure" type="audio/mpeg" title="MP3" href="#{enclosure_url}" length="#{enclosure_length}" />})
38
+ save_entry
39
+ end
40
+
41
+ def remove_enclosure
42
+ if enclosure?
43
+ enclosure.remove
44
+ save_entry
45
+ end
46
+ end
47
+
48
+ def save_entry
49
+ path = "/feeds/#{@blog_id}/posts/default/#{@entry_id}"
50
+
51
+ put(path, entry.to_s)
52
+ end
53
+
54
+ # Creates a new entry with the given title and body
55
+ def entry(title, body)
56
+ x = Builder::XmlMarkup.new :indent => 2
57
+ @entry = x.entry 'xmlns' => 'http://www.w3.org/2005/Atom' do
58
+ x.title title, 'type' => 'text'
59
+ x.content 'type' => 'xhtml' do
60
+ x.div 'xmlns' => 'http://www.w3.org/1999/xhtml' do
61
+ x << body
62
+ end
63
+ end
64
+ end
65
+
66
+ path = "/feeds/#{@blog_id}/posts/default"
67
+ post(path, @entry)
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,32 @@
1
+ <%
2
+ # time format
3
+ %>
4
+ <table class="twitter">
5
+ <tbody class="twitter">
6
+ <% results.each do |result| %>
7
+ <tr class="twitter-status u-<%= result['from_user'] %>">
8
+ <td class="">
9
+ <a href="http://twitter.com/<%= result['from_user'] %>" class="url">
10
+ <img alt="Tom Dougherty" class="twitter-avatar" height="48" src="<%= result['profile_image_url'] %>" width="48" />
11
+ </a>
12
+ </td>
13
+ <td class="twitter-body">
14
+ <div>
15
+ <strong>
16
+ <a href="http://twitter.com/<%= result['from_user'] %>" class="twitter-user" title="<%= result['from_user'] %>">
17
+ <%= result['from_user'] %>
18
+ </a>
19
+ </strong>
20
+ <span class="twitter-text">
21
+ <%= result['text'] %>
22
+ </span>
23
+ <span class="twitter-date" style="font-style: italic; font-size:smaller;">
24
+ <%= format_time(result['created_at']) %>
25
+ </span>
26
+ </div>
27
+ </td>
28
+ </tr>
29
+ <% end %>
30
+ </tbody>
31
+
32
+ </table>
@@ -0,0 +1,31 @@
1
+ require 'erb'
2
+ require File.dirname(__FILE__) + '/blogger/blogger'
3
+
4
+ module TwitterArchive
5
+ module Backends
6
+ class BloggerArchive
7
+ def archive(twitter_results, opts=nil)
8
+ if twitter_results.length > 0
9
+ blogger = GData::Blogger.new(opts['blogger_id'])
10
+ blogger.authenticate(opts['blogger_user'], opts['blogger_pass'])
11
+ blogger.entry(opts['blogger_title'] || 'Twitter', format_post(twitter_results))
12
+ "Posting to blogger id #{opts['blogger_id']}, user #{opts['blogger_user']}"
13
+ else
14
+ "Nothing to post to blogger"
15
+ end
16
+ end
17
+
18
+ def format_post(results)
19
+ results
20
+ template = ERB.new(File.open(File.dirname(__FILE__) + '/blogger/post_body.html.erb') {|f| f.read})
21
+ template.result(binding)
22
+ end
23
+
24
+ def format_time (date_str)
25
+ time = Time.gm(*ParseDate.parsedate(date_str)[0..4])
26
+ time.strftime("%m/%d/%Y at %I:%M%p")
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,9 @@
1
+ module TwitterArchive
2
+ module Backends
3
+ class YamlArchive
4
+ def archive(results, opts=nil)
5
+ results.to_yaml
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ require 'parsedate'
2
+ Dir.glob(File.dirname(__FILE__)+ '/backends/*.rb').each {|f| require f }
3
+
4
+ module TwitterArchive
5
+
6
+ class Base
7
+ attr_accessor :config_file, :config
8
+
9
+ def initialize(config_file = nil)
10
+ @config_file = config_file || ENV['HOME'] + '/.twitter_archive.yml'
11
+ end
12
+
13
+ def get_latest
14
+ all_results = []
15
+ last_max_id = 0
16
+ @config['accounts'].each do |account|
17
+ twitter_response = fetch_from_account(account['name'], config['last_max_id'] || 0)
18
+ config['current_twitter_account'] = account['name']
19
+ puts "Collected #{twitter_response['results'].length} tweets from #{account['name']}"
20
+
21
+ all_results = all_results + twitter_response['results']
22
+ last_max_id = twitter_response['max_id']
23
+ end
24
+
25
+ config['last_max_id'] = last_max_id
26
+
27
+ all_results.sort! {|a, b| b['created_at'] <=> a['created_at'] }
28
+
29
+ backend = load_backend(config['backend'])
30
+
31
+ backend.archive(all_results, config)
32
+ end
33
+
34
+ def fetch_from_account(name, last_max_id=0)
35
+ Twitter::Search.new.from(name).since(last_max_id).fetch
36
+ end
37
+
38
+ def load_config
39
+ @config = YAML::load_file(@config_file)
40
+ end
41
+
42
+ def save_config
43
+ File.open(@config_file, 'w') do |out|
44
+ YAML.dump(config, out)
45
+ end
46
+ end
47
+
48
+ def load_backend(backend_name)
49
+ eval "TwitterArchive::Backends::#{backend_name.capitalize}Archive.new"
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,12 @@
1
+ module TwitterArchive
2
+ class Runner
3
+ def self.runner
4
+ puts "Running Twitter Archiver"
5
+
6
+ ta = TwitterArchive::Base.new
7
+ ta.load_config
8
+ puts ta.get_latest
9
+ ta.save_config
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module TwitterArchive
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,13 @@
1
+ #$:.unshift(File.dirname(__FILE__)) unless
2
+ # $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'yaml'
5
+ require 'rubygems'
6
+ require 'twitter'
7
+
8
+ $:.unshift(File.dirname(__FILE__))
9
+ require 'twitter_archive/base'
10
+ require 'twitter_archive/runner'
11
+ require 'twitter_archive/version'
12
+
13
+ module TwitterArchive; end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/twitter_archive.rb'}"
9
+ puts "Loading twitter_archive gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../../lib/twitter_archive/backends/blogger_archive.rb'
3
+
4
+ describe TwitterArchive::Backends::BloggerArchive do
5
+ before(:all) do
6
+ puts " WARNING Not testing with live blogger, set TEST_BLOGGER to enable" unless ENV['TEST_BLOGGER']
7
+ end
8
+
9
+ before(:each) do
10
+ @ba = TwitterArchive::Backends::BloggerArchive.new
11
+ @config = YAML::load_file(ENV['HOME'] + '/.twitter_archive.yml')
12
+ @twitter_response = YAML::load_file File.dirname(__FILE__) +'/../fixtures/twitter_response.yml'
13
+
14
+ if(ENV['TEST_BLOGGER'])
15
+ Net::HTTPS.stub!(:post_form).and_return(YAML::load_file(
16
+ File.dirname(__FILE__) + '/../../fixtures/blogger_authenticate_response.yml'))
17
+ GData
18
+ end
19
+
20
+ end
21
+
22
+ it "should create an instance" do
23
+ @ba.should be_an_instance_of(TwitterArchive::Backends::BloggerArchive)
24
+ end
25
+
26
+ it "should test post to blogger" do
27
+ @config['blogger_title'] = "Testing twitter_archive"
28
+ @ba.archive(@twitter_response['results'], @config)
29
+ end
30
+
31
+ it "should format html from the tweets" do
32
+ body = @ba.format_post(@twitter_response['results'])
33
+
34
+ body.should_not be_nil
35
+ end
36
+
37
+ it "should format time like google" do
38
+ @ba.format_time("Sun, 28 Dec 2008 23:38:46 +0000").should eql "12/28/2008 at 11:38PM"
39
+ end
40
+
41
+
42
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../../lib/twitter_archive/backends/yaml_archive.rb'
3
+
4
+ describe TwitterArchive::Backends::YamlArchive do
5
+ before(:each) do
6
+ @ya = TwitterArchive::Backends::YamlArchive.new
7
+ end
8
+
9
+ it "should create an instance" do
10
+ @ya.should be_an_instance_of(TwitterArchive::Backends::YamlArchive)
11
+ end
12
+
13
+ end
@@ -0,0 +1,30 @@
1
+ --- !ruby/object:Net::HTTPOK
2
+ body: |
3
+ SID=DQAAAH4AAAAK5SScZgxeJS9BP03rjNP0EeUm0X8jvFKb6vXpRBMG-4aIkON6mbjjlqvpip7vxS8H_9_bNonFN-6PDEw8-xuTtszBogb7qRe4-gzhMc7dDX65VHEw-QmCmyYr5gGvWUP5x_5E0zh-XWef-viVNvbnCx7agwI-CCvBwAzl7fQQVw
4
+ LSID=DQAAAIAAAACZDlUEEuBRdQt9oEgJI2rjL9PJUNLnoDPTQA0duvmtRf3cxhh5DDcPXpfGI6tF-2K7-8ZHubK_4FiShCGhoKTE6d4vzTs0SWz5Itk8MpF_qZoye7AwCb3YVG4tgjALpI0RNl8SEuWTg2Jtiqn2So2mlxzivHeOv8rAE-s01p1qHA
5
+ Auth=DQAAAH8AAACZDlUEEuBRdQt9oEgJI2rjL9PJUNLnoDPTQA0duvmtRf3cxhh5DDcPXpfGI6tF-2J0oYw6koUPpBpn3QOJoJ3ps7lCYCqwPeCc64e265o4UyYgEYFivgbDrI7akWGSkmVvO2hFw6NGxZyGx6-MrKSKFph4MgORs57vPRnrj2UjJw
6
+
7
+ body_exist: true
8
+ code: "200"
9
+ header:
10
+ cache-control:
11
+ - no-cache, no-store
12
+ x-content-type-options:
13
+ - nosniff
14
+ expires:
15
+ - Mon, 01-Jan-1990 00:00:00 GMT
16
+ date:
17
+ - Wed, 31 Dec 2008 20:50:14 GMT
18
+ content-type:
19
+ - text/plain
20
+ server:
21
+ - GFE/1.3
22
+ content-length:
23
+ - "563"
24
+ pragma:
25
+ - no-cache
26
+ http_version: "1.1"
27
+ message: OK
28
+ read: true
29
+ socket:
30
+
@@ -0,0 +1,132 @@
1
+ ---
2
+ max_id: 1083275701
3
+ since_id: 0
4
+ results:
5
+ - text: "@beejpowers glad it was working for you!"
6
+ from_user: fuzzymonk
7
+ to_user: beejpowers
8
+ to_user_id: 2203390
9
+ id: 1083002747
10
+ iso_language_code: en
11
+ from_user_id: 44397
12
+ created_at: Sun, 28 Dec 2008 23:38:46 +0000
13
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
14
+ - text: Testing my twitter app.
15
+ from_user: fuzzymonk
16
+ to_user_id:
17
+ id: 1082726875
18
+ iso_language_code: en
19
+ from_user_id: 44397
20
+ created_at: Sun, 28 Dec 2008 20:14:53 +0000
21
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
22
+ - text: Chicken nugget picnic FTW!
23
+ from_user: fuzzymonk
24
+ to_user_id:
25
+ id: 1082568072
26
+ iso_language_code: de
27
+ from_user_id: 44397
28
+ created_at: Sun, 28 Dec 2008 18:12:25 +0000
29
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
30
+ - text: Riding trikes.
31
+ from_user: fuzzymonk
32
+ to_user_id:
33
+ id: 1082523321
34
+ iso_language_code: nl
35
+ from_user_id: 44397
36
+ created_at: Sun, 28 Dec 2008 17:36:59 +0000
37
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
38
+ - text: Nursery duty. 9:5 helper to toddler ratio. Why did we wake up so early?
39
+ from_user: fuzzymonk
40
+ to_user_id:
41
+ id: 1082306470
42
+ iso_language_code: en
43
+ from_user_id: 44397
44
+ created_at: Sun, 28 Dec 2008 14:24:12 +0000
45
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
46
+ - text: "@beejpowers I need to go back to work to recover from the holiday."
47
+ from_user: fuzzymonk
48
+ to_user: beejpowers
49
+ to_user_id: 2203390
50
+ id: 1081719755
51
+ iso_language_code: en
52
+ from_user_id: 44397
53
+ created_at: Sun, 28 Dec 2008 03:00:30 +0000
54
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
55
+ - text: Where can I get one? http://tinyurl.com/7dxzrv
56
+ from_user: fuzzymonk
57
+ to_user_id:
58
+ id: 1081473926
59
+ iso_language_code: en
60
+ from_user_id: 44397
61
+ created_at: Sat, 27 Dec 2008 23:35:21 +0000
62
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
63
+ - text: Don't like pandemonium. Go away
64
+ from_user: fuzzymonk
65
+ to_user_id:
66
+ id: 1081233677
67
+ iso_language_code: en
68
+ from_user_id: 44397
69
+ created_at: Sat, 27 Dec 2008 20:08:54 +0000
70
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
71
+ - text: "[dotfiles] http://is.gd/dBpg Christopher Sexton - Removing the os specific scripts"
72
+ from_user: fuzzymonk
73
+ to_user_id:
74
+ id: 1079851223
75
+ iso_language_code: en
76
+ from_user_id: 44397
77
+ created_at: Fri, 26 Dec 2008 21:18:11 +0000
78
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
79
+ - text: "[dotfiles] http://is.gd/dBpf Christopher Sexton - Auto linking files in home/"
80
+ from_user: fuzzymonk
81
+ to_user_id:
82
+ id: 1079851212
83
+ iso_language_code: en
84
+ from_user_id: 44397
85
+ created_at: Fri, 26 Dec 2008 21:18:10 +0000
86
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
87
+ - text: "[dotfiles] http://is.gd/dBph Christopher Sexton - Added colors and fixed link if"
88
+ from_user: fuzzymonk
89
+ to_user_id:
90
+ id: 1079851233
91
+ iso_language_code: en
92
+ from_user_id: 44397
93
+ created_at: Fri, 26 Dec 2008 21:18:09 +0000
94
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
95
+ - text: "[dotfiles] http://is.gd/dAcc Christopher Sexton - Added check if the file exists before trying to rename it."
96
+ from_user: fuzzymonk
97
+ to_user_id:
98
+ id: 1079644342
99
+ iso_language_code: en
100
+ from_user_id: 44397
101
+ created_at: Fri, 26 Dec 2008 18:31:37 +0000
102
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
103
+ - text: "'Nene' is a derivative of 'Neal'"
104
+ from_user: fuzzymonk
105
+ to_user_id:
106
+ id: 1079585237
107
+ iso_language_code: it
108
+ from_user_id: 44397
109
+ created_at: Fri, 26 Dec 2008 17:45:34 +0000
110
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
111
+ - text: "[cookbook] http://is.gd/dzKL Christopher Sexton - Fixed link_to in application"
112
+ from_user: fuzzymonk
113
+ to_user_id:
114
+ id: 1079579679
115
+ iso_language_code: en
116
+ from_user_id: 44397
117
+ created_at: Fri, 26 Dec 2008 17:41:05 +0000
118
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
119
+ - text: "[cookbook] http://is.gd/dzKJ Christopher Sexton - Freezing to rails 2.1.1"
120
+ from_user: fuzzymonk
121
+ to_user_id:
122
+ id: 1079579667
123
+ iso_language_code: en
124
+ from_user_id: 44397
125
+ created_at: Fri, 26 Dec 2008 17:41:03 +0000
126
+ profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/30300852/TaylorandMcLauren-jabber_normal.jpg
127
+ results_per_page: 15
128
+ refresh_url: ?since_id=1083275701&q=from%3Afuzzymonk
129
+ next_page: ?page=2&max_id=1083275701&q=from%3Afuzzymonk
130
+ completed_in: 0.01725
131
+ query: from%3Afuzzymonk
132
+ page: 1
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format specdoc
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'twitter_archive'
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe TwitterArchive::Base do
4
+ before(:each) do
5
+ @ta = TwitterArchive::Base.new
6
+ @ta.stub!(:fetch_from_account).and_return(YAML::load_file(
7
+ File.dirname(__FILE__) + '/fixtures/twitter_response.yml'))
8
+ @ta.stub!(:save_config).and_return(true)
9
+ @ta.config_file = File.dirname(__FILE__) + '/../config/test.yml'
10
+ # TODO stubb out backend
11
+ end
12
+
13
+ it "should create an instance" do
14
+ @ta.should be_an_instance_of(TwitterArchive::Base)
15
+ end
16
+
17
+ it "should load the yaml file" do
18
+ @ta.load_config
19
+ @ta.config['backend'].should eql('yaml')
20
+ @ta.config['accounts'][0]['name'].should eql('fuzzymonk')
21
+ end
22
+
23
+ it "should stub the fetch method" do
24
+ @ta.fetch_from_account['max_id'].should eql(1083275701)
25
+ end
26
+
27
+ it "should stub the save_config" do
28
+ @ta.load_config
29
+ @ta.config['joe'] = "test"
30
+ @ta.save_config
31
+
32
+ @ta.load_config
33
+ @ta.config['joe'].should be_nil
34
+ end
35
+
36
+ it "should update the last_max_id in the config file" do
37
+ @ta.load_config
38
+ @ta.get_latest
39
+ @ta.config['last_max_id'].should_not eql(@ta.load_config['last_max_id'])
40
+ end
41
+
42
+ it "should load the yaml backend dynamically" do
43
+ @ta.load_backend('yaml').should be_an_instance_of TwitterArchive::Backends::YamlArchive
44
+ end
45
+
46
+ it "should raise an error when loading an invalid backend" do
47
+ lambda do
48
+ @ta.load_backend('poopie')
49
+ @processor.process(StringIO.new("z"*31))
50
+ end.should raise_error(NameError)
51
+
52
+ end
53
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{twitter_archive}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Christohper Sexton"]
9
+ s.date = %q{2009-01-02}
10
+ s.default_executable = %q{twitter_archive}
11
+ s.description = %q{Twitter archive utility}
12
+ s.email = %q{csexton@gmail.com}
13
+ s.executables = ["twitter_archive"]
14
+ s.extra_rdoc_files = ["bin/twitter_archive", "lib/twitter_archive/backends/blogger/base.rb", "lib/twitter_archive/backends/blogger/blogger.rb", "lib/twitter_archive/backends/blogger/post_body.html.erb", "lib/twitter_archive/backends/blogger/README", "lib/twitter_archive/backends/blogger_archive.rb", "lib/twitter_archive/backends/yaml_archive.rb", "lib/twitter_archive/base.rb", "lib/twitter_archive/runner.rb", "lib/twitter_archive/version.rb", "lib/twitter_archive.rb", "LICENSE", "README.rdoc", "tasks/rspec.rake"]
15
+ s.files = ["bin/twitter_archive", "config/test.yml", "History", "lib/twitter_archive/backends/blogger/base.rb", "lib/twitter_archive/backends/blogger/blogger.rb", "lib/twitter_archive/backends/blogger/post_body.html.erb", "lib/twitter_archive/backends/blogger/README", "lib/twitter_archive/backends/blogger_archive.rb", "lib/twitter_archive/backends/yaml_archive.rb", "lib/twitter_archive/base.rb", "lib/twitter_archive/runner.rb", "lib/twitter_archive/version.rb", "lib/twitter_archive.rb", "LICENSE", "Manifest", "Rakefile", "README.rdoc", "script/console", "script/destroy", "script/generate", "spec/backends/blogger_archive_spec.rb", "spec/backends/yaml_archive_spec.rb", "spec/fixtures/blogger_authenticate_response.yml", "spec/fixtures/twitter_response.yml", "spec/spec.opts", "spec/spec_helper.rb", "spec/twitter_archive_spec.rb", "tasks/rspec.rake", "twitter_archive.gemspec"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://github.com/csexton/twitter_archive}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Twitter_archive", "--main", "README.rdoc"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{twitter_archive}
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{Twitter archive utility}
23
+
24
+ if s.respond_to? :specification_version then
25
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
+ s.specification_version = 2
27
+
28
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
+ s.add_runtime_dependency(%q<twitter>, [">= 0.4"])
30
+ s.add_runtime_dependency(%q<hpricot>, [">= 0.6"])
31
+ s.add_development_dependency(%q<echoe>, [">= 0"])
32
+ else
33
+ s.add_dependency(%q<twitter>, [">= 0.4"])
34
+ s.add_dependency(%q<hpricot>, [">= 0.6"])
35
+ s.add_dependency(%q<echoe>, [">= 0"])
36
+ end
37
+ else
38
+ s.add_dependency(%q<twitter>, [">= 0.4"])
39
+ s.add_dependency(%q<hpricot>, [">= 0.6"])
40
+ s.add_dependency(%q<echoe>, [">= 0"])
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csexton-twitter_archive
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Christohper Sexton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-02 00:00:00 -08:00
13
+ default_executable: twitter_archive
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: twitter
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0.4"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hpricot
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0.6"
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: echoe
35
+ version_requirement:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ description: Twitter archive utility
43
+ email: csexton@gmail.com
44
+ executables:
45
+ - twitter_archive
46
+ extensions: []
47
+
48
+ extra_rdoc_files:
49
+ - bin/twitter_archive
50
+ - lib/twitter_archive/backends/blogger/base.rb
51
+ - lib/twitter_archive/backends/blogger/blogger.rb
52
+ - lib/twitter_archive/backends/blogger/post_body.html.erb
53
+ - lib/twitter_archive/backends/blogger/README
54
+ - lib/twitter_archive/backends/blogger_archive.rb
55
+ - lib/twitter_archive/backends/yaml_archive.rb
56
+ - lib/twitter_archive/base.rb
57
+ - lib/twitter_archive/runner.rb
58
+ - lib/twitter_archive/version.rb
59
+ - lib/twitter_archive.rb
60
+ - LICENSE
61
+ - README.rdoc
62
+ - tasks/rspec.rake
63
+ files:
64
+ - bin/twitter_archive
65
+ - config/test.yml
66
+ - History
67
+ - lib/twitter_archive/backends/blogger/base.rb
68
+ - lib/twitter_archive/backends/blogger/blogger.rb
69
+ - lib/twitter_archive/backends/blogger/post_body.html.erb
70
+ - lib/twitter_archive/backends/blogger/README
71
+ - lib/twitter_archive/backends/blogger_archive.rb
72
+ - lib/twitter_archive/backends/yaml_archive.rb
73
+ - lib/twitter_archive/base.rb
74
+ - lib/twitter_archive/runner.rb
75
+ - lib/twitter_archive/version.rb
76
+ - lib/twitter_archive.rb
77
+ - LICENSE
78
+ - Manifest
79
+ - Rakefile
80
+ - README.rdoc
81
+ - script/console
82
+ - script/destroy
83
+ - script/generate
84
+ - spec/backends/blogger_archive_spec.rb
85
+ - spec/backends/yaml_archive_spec.rb
86
+ - spec/fixtures/blogger_authenticate_response.yml
87
+ - spec/fixtures/twitter_response.yml
88
+ - spec/spec.opts
89
+ - spec/spec_helper.rb
90
+ - spec/twitter_archive_spec.rb
91
+ - tasks/rspec.rake
92
+ - twitter_archive.gemspec
93
+ has_rdoc: true
94
+ homepage: http://github.com/csexton/twitter_archive
95
+ post_install_message:
96
+ rdoc_options:
97
+ - --line-numbers
98
+ - --inline-source
99
+ - --title
100
+ - Twitter_archive
101
+ - --main
102
+ - README.rdoc
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: "0"
110
+ version:
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: "1.2"
116
+ version:
117
+ requirements: []
118
+
119
+ rubyforge_project: twitter_archive
120
+ rubygems_version: 1.2.0
121
+ signing_key:
122
+ specification_version: 2
123
+ summary: Twitter archive utility
124
+ test_files: []
125
+