wayback 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +10 -0
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +52 -0
- data/LICENSE.md +20 -0
- data/README.md +81 -0
- data/Rakefile +11 -0
- data/lib/wayback.rb +32 -0
- data/lib/wayback/api/archive.rb +42 -0
- data/lib/wayback/api/utils.rb +27 -0
- data/lib/wayback/archive.rb +15 -0
- data/lib/wayback/base.rb +127 -0
- data/lib/wayback/client.rb +62 -0
- data/lib/wayback/configurable.rb +48 -0
- data/lib/wayback/default.rb +68 -0
- data/lib/wayback/error.rb +31 -0
- data/lib/wayback/error/already_favorited.rb +10 -0
- data/lib/wayback/error/already_retweeted.rb +10 -0
- data/lib/wayback/error/bad_gateway.rb +11 -0
- data/lib/wayback/error/bad_request.rb +10 -0
- data/lib/wayback/error/client_error.rb +28 -0
- data/lib/wayback/error/configuration_error.rb +8 -0
- data/lib/wayback/error/decode_error.rb +9 -0
- data/lib/wayback/error/forbidden.rb +10 -0
- data/lib/wayback/error/gateway_timeout.rb +11 -0
- data/lib/wayback/error/identity_map_key_error.rb +9 -0
- data/lib/wayback/error/internal_server_error.rb +11 -0
- data/lib/wayback/error/not_acceptable.rb +10 -0
- data/lib/wayback/error/not_found.rb +10 -0
- data/lib/wayback/error/server_error.rb +28 -0
- data/lib/wayback/error/service_unavailable.rb +11 -0
- data/lib/wayback/error/too_many_requests.rb +12 -0
- data/lib/wayback/error/unauthorized.rb +10 -0
- data/lib/wayback/error/unprocessable_entity.rb +10 -0
- data/lib/wayback/factory.rb +21 -0
- data/lib/wayback/identity.rb +50 -0
- data/lib/wayback/identity_map.rb +22 -0
- data/lib/wayback/page.rb +18 -0
- data/lib/wayback/response/parse_memento.rb +61 -0
- data/lib/wayback/response/parse_memento_page.rb +23 -0
- data/lib/wayback/response/raise_error.rb +31 -0
- data/lib/wayback/version.rb +18 -0
- data/spec/fixtures/list.timemap +9 -0
- data/spec/fixtures/page.html +225 -0
- data/spec/helper.rb +65 -0
- data/spec/wayback/api/archive_spec.rb +73 -0
- data/spec/wayback/archive_spec.rb +23 -0
- data/spec/wayback/base_spec.rb +117 -0
- data/spec/wayback/client_spec.rb +114 -0
- data/spec/wayback/error/client_error_spec.rb +23 -0
- data/spec/wayback/error/server_error_spec.rb +20 -0
- data/spec/wayback/error_spec.rb +20 -0
- data/spec/wayback/identifiable_spec.rb +50 -0
- data/spec/wayback/page_spec.rb +36 -0
- data/spec/wayback_spec.rb +47 -0
- data/wayback.gemspec +26 -0
- metadata +175 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::API::Archive do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@client = Wayback::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# N.B. IN SPEC, NOT USING http:// DUE TO PARSING ISSUE WITH DOUBLE BACKSLASH.
|
10
|
+
|
11
|
+
describe "#list" do
|
12
|
+
before do
|
13
|
+
stub_get("/list/timemap/link/gleu.ch").to_return(:body => fixture("list.timemap"), :headers => {:content_type => "application/link-format"})
|
14
|
+
end
|
15
|
+
it "requests the correct resource" do
|
16
|
+
@client.list('gleu.ch')
|
17
|
+
expect(a_get("/list/timemap/link/gleu.ch")).to have_been_made
|
18
|
+
end
|
19
|
+
it "returns the link data" do
|
20
|
+
timemap = @client.list('gleu.ch')
|
21
|
+
expect(timemap).to be_a Wayback::Archive
|
22
|
+
expect(timemap.id).to eq ('http://gleu.ch')
|
23
|
+
expect(timemap.first_date).to eq (1303064571)
|
24
|
+
expect(timemap.first_date?).to be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#page" do
|
29
|
+
before do
|
30
|
+
stub_get("/memento/20130129170322/gleu.ch").to_return(:body => fixture("page.html"), :headers => {:content_type => "text/html"})
|
31
|
+
end
|
32
|
+
it "requests the correct resource" do
|
33
|
+
@client.page('gleu.ch', 20130129170322)
|
34
|
+
expect(a_get("/memento/20130129170322/gleu.ch")).to have_been_made
|
35
|
+
end
|
36
|
+
it "returns the desired page on date" do
|
37
|
+
page = @client.page('gleu.ch', 20130129170322)
|
38
|
+
expect(page).to be_a Wayback::Page
|
39
|
+
expect(page.html).to match /^\<\!DOCTYPE html\>.*http\:\/\/gleu\.ch.*\<\/html\>/im
|
40
|
+
end
|
41
|
+
it "returns the first desired page" do
|
42
|
+
stub_get("/memento/0/gleu.ch").to_return(:body => fixture("page.html"), :headers => {:content_type => "text/html"})
|
43
|
+
page = @client.page('gleu.ch', :first)
|
44
|
+
expect(page).to be_a Wayback::Page
|
45
|
+
expect(page.html).to match /^\<\!DOCTYPE html\>.*http\:\/\/gleu\.ch.*\<\/html\>/im
|
46
|
+
end
|
47
|
+
it "returns the last desired page" do
|
48
|
+
stub_get("/memento/#{Time.now.to_i}/gleu.ch").to_return(:body => fixture("page.html"), :headers => {:content_type => "text/html"})
|
49
|
+
page = @client.page('gleu.ch', :last)
|
50
|
+
expect(page).to be_a Wayback::Page
|
51
|
+
expect(page.html).to match(/^\<\!DOCTYPE html\>.*http\:\/\/gleu\.ch.*\<\/html\>/im)
|
52
|
+
end
|
53
|
+
it "returns the desired page for Time" do
|
54
|
+
stub_get("/memento/#{Time.now.to_i}/gleu.ch").to_return(:body => fixture("page.html"), :headers => {:content_type => "text/html"})
|
55
|
+
page = @client.page('gleu.ch', Time.now)
|
56
|
+
expect(page).to be_a Wayback::Page
|
57
|
+
expect(page.html).to match(/^\<\!DOCTYPE html\>.*http\:\/\/gleu\.ch.*\<\/html\>/im)
|
58
|
+
end
|
59
|
+
it "returns the desired page for Time string" do
|
60
|
+
stub_get("/memento/#{Time.now.to_i}/gleu.ch").to_return(:body => fixture("page.html"), :headers => {:content_type => "text/html"})
|
61
|
+
page = @client.page('gleu.ch', Time.now.to_s)
|
62
|
+
expect(page).to be_a Wayback::Page
|
63
|
+
expect(page.html).to match(/^\<\!DOCTYPE html\>.*http\:\/\/gleu\.ch.*\<\/html\>/im)
|
64
|
+
end
|
65
|
+
# it "handles when error exists" do
|
66
|
+
# stub_get("/memento/#{Time.now.to_i}/gleu.ch").to_return(:status => 204, :body => '', :headers => {:content_type => "text/xml"})
|
67
|
+
# page = @client.page('gleu.ch', Time.now.to_s)
|
68
|
+
# expect(page).to be_a Wayback::Page
|
69
|
+
# expect(page.html).to match(/^\<\!DOCTYPE html\>.*http\:\/\/gleu\.ch.*\<\/html\>/im)
|
70
|
+
# end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Archive do
|
4
|
+
|
5
|
+
describe "#==" do
|
6
|
+
it "returns true when objects IDs are the same" do
|
7
|
+
saved_search = Wayback::Archive.new(:id => 1, :name => "foo")
|
8
|
+
other = Wayback::Archive.new(:id => 1, :name => "bar")
|
9
|
+
expect(saved_search == other).to be_true
|
10
|
+
end
|
11
|
+
it "returns false when objects IDs are different" do
|
12
|
+
saved_search = Wayback::Archive.new(:id => 1)
|
13
|
+
other = Wayback::Archive.new(:id => 2)
|
14
|
+
expect(saved_search == other).to be_false
|
15
|
+
end
|
16
|
+
it "returns false when classes are different" do
|
17
|
+
saved_search = Wayback::Archive.new(:id => 1)
|
18
|
+
other = Wayback::Identity.new(:id => 1)
|
19
|
+
expect(saved_search == other).to be_false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Base do
|
4
|
+
|
5
|
+
context "identity map enabled" do
|
6
|
+
before do
|
7
|
+
Wayback.identity_map = Wayback::IdentityMap
|
8
|
+
object = Wayback::Base.new(:id => 1)
|
9
|
+
@base = Wayback::Base.store(object)
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
Wayback.identity_map = false
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".identity_map" do
|
17
|
+
it "returns an instance of the identity map" do
|
18
|
+
expect(Wayback::Base.identity_map).to be_a Wayback::IdentityMap
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".fetch" do
|
23
|
+
it "returns existing objects" do
|
24
|
+
expect(Wayback::Base.fetch(:id => 1)).to be
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises an error on objects that don't exist" do
|
28
|
+
expect{Wayback::Base.fetch(:id => 6)}.to raise_error Wayback::Error::IdentityMapKeyError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe ".store" do
|
33
|
+
it "stores Wayback::Base objects" do
|
34
|
+
object = Wayback::Base.new(:id => 4)
|
35
|
+
expect(Wayback::Base.store(object)).to be_a Wayback::Base
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".fetch_or_new" do
|
40
|
+
it "returns existing objects" do
|
41
|
+
expect(Wayback::Base.fetch_or_new(:id => 1)).to be
|
42
|
+
end
|
43
|
+
it "creates new objects and stores them" do
|
44
|
+
expect(Wayback::Base.fetch_or_new(:id => 2)).to be
|
45
|
+
expect(Wayback::Base.fetch(:id => 2)).to be
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#[]" do
|
50
|
+
it "calls methods using [] with symbol" do
|
51
|
+
expect(@base[:object_id]).to be_an Integer
|
52
|
+
end
|
53
|
+
it "calls methods using [] with string" do
|
54
|
+
expect(@base['object_id']).to be_an Integer
|
55
|
+
end
|
56
|
+
it "returns nil for missing method" do
|
57
|
+
expect(@base[:foo]).to be_nil
|
58
|
+
expect(@base['foo']).to be_nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#to_hash" do
|
63
|
+
it "returns a hash" do
|
64
|
+
expect(@base.to_hash).to be_a Hash
|
65
|
+
expect(@base.to_hash[:id]).to eq 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "identical objects" do
|
70
|
+
it "have the same object_id" do
|
71
|
+
expect(@base.object_id).to eq Wayback::Base.fetch(:id => 1).object_id
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
context "identity map disabled" do
|
78
|
+
before(:all) do
|
79
|
+
Wayback.identity_map = false
|
80
|
+
end
|
81
|
+
after(:all) do
|
82
|
+
Wayback.identity_map = Wayback::IdentityMap
|
83
|
+
end
|
84
|
+
|
85
|
+
describe ".identity_map" do
|
86
|
+
it "returns nil" do
|
87
|
+
expect(Wayback::Base.identity_map).to be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe ".fetch" do
|
92
|
+
it "returns nil" do
|
93
|
+
expect(Wayback::Base.fetch(:id => 1)).to be_nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe ".store" do
|
98
|
+
it "returns an instance of the object" do
|
99
|
+
expect(Wayback::Base.store(Wayback::Base.new(:id => 1))).to be_a Wayback::Base
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe ".fetch_or_new" do
|
104
|
+
it "creates new objects" do
|
105
|
+
expect(Wayback::Base.fetch_or_new(:id => 2)).to be
|
106
|
+
expect(Wayback.identity_map).to be_false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#attrs' do
|
112
|
+
it 'returns a hash of attributes' do
|
113
|
+
expect(Wayback::Base.new(:id => 1).attrs).to eq({:id => 1})
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Client do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
Wayback::Client.new(:consumer_key => "CK", :consumer_secret => "CS", :oauth_token => "OT", :oauth_token_secret => "OS")
|
7
|
+
end
|
8
|
+
|
9
|
+
context "with module configuration" do
|
10
|
+
|
11
|
+
before do
|
12
|
+
Wayback.configure do |config|
|
13
|
+
Wayback::Configurable.keys.each do |key|
|
14
|
+
config.send("#{key}=", key)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
Wayback.reset!
|
21
|
+
end
|
22
|
+
|
23
|
+
it "inherits the module configuration" do
|
24
|
+
client = Wayback::Client.new
|
25
|
+
Wayback::Configurable.keys.each do |key|
|
26
|
+
expect(client.instance_variable_get(:"@#{key}")).to eq key
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with class configuration" do
|
31
|
+
|
32
|
+
before do
|
33
|
+
@configuration = {
|
34
|
+
:connection_options => {:timeout => 10},
|
35
|
+
:endpoint => 'http://xolator.com/',
|
36
|
+
:middleware => Proc.new{},
|
37
|
+
:identity_map => ::Hash
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
context "during initialization" do
|
42
|
+
it "overrides the module configuration" do
|
43
|
+
client = Wayback::Client.new(@configuration)
|
44
|
+
Wayback::Configurable.keys.each do |key|
|
45
|
+
expect(client.instance_variable_get(:"@#{key}")).to eq @configuration[key]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "after initialization" do
|
51
|
+
it "overrides the module configuration after initialization" do
|
52
|
+
client = Wayback::Client.new
|
53
|
+
client.configure do |config|
|
54
|
+
@configuration.each do |key, value|
|
55
|
+
config.send("#{key}=", value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
Wayback::Configurable.keys.each do |key|
|
59
|
+
expect(client.instance_variable_get(:"@#{key}")).to eq @configuration[key]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#delete" do
|
68
|
+
before do
|
69
|
+
stub_delete("/custom/delete").with(:query => {:deleted => "object"})
|
70
|
+
end
|
71
|
+
it "allows custom delete requests" do
|
72
|
+
subject.delete("/custom/delete", {:deleted => "object"})
|
73
|
+
expect(a_delete("/custom/delete").with(:query => {:deleted => "object"})).to have_been_made
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#put" do
|
78
|
+
before do
|
79
|
+
stub_put("/custom/put").with(:body => {:updated => "object"})
|
80
|
+
end
|
81
|
+
it "allows custom put requests" do
|
82
|
+
subject.put("/custom/put", {:updated => "object"})
|
83
|
+
expect(a_put("/custom/put").with(:body => {:updated => "object"})).to have_been_made
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#post" do
|
88
|
+
before do
|
89
|
+
stub_post("/custom/post").with(:body => {:updated => "object"})
|
90
|
+
end
|
91
|
+
it "allows custom post requests" do
|
92
|
+
subject.post("/custom/post", {:updated => "object"})
|
93
|
+
expect(a_post("/custom/post").with(:body => {:updated => "object"})).to have_been_made
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#connection" do
|
98
|
+
it "looks like Faraday connection" do
|
99
|
+
expect(subject.send(:connection)).to respond_to(:run_request)
|
100
|
+
end
|
101
|
+
it "memoizes the connection" do
|
102
|
+
c1, c2 = subject.send(:connection), subject.send(:connection)
|
103
|
+
expect(c1.object_id).to eq c2.object_id
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#request" do
|
108
|
+
it "catches Faraday errors" do
|
109
|
+
subject.stub!(:connection).and_raise(Faraday::Error::ClientError.new("Oops"))
|
110
|
+
expect{subject.send(:request, :get, "/path")}.to raise_error Wayback::Error::ClientError
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Error::ClientError do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@client = Wayback::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
Wayback::Error::ClientError.errors.each do |status, exception|
|
10
|
+
[nil, "error"].each do |body|
|
11
|
+
context "when HTTP status is #{status} and body is #{body.inspect}" do
|
12
|
+
before do
|
13
|
+
body_message = '<wayback><error><title>Hrm.</title><message>Wayback Machine doesn't have that page archived.</message></error></wayback>' unless body.nil?
|
14
|
+
stub_get("/list/timemap/link/gleu.ch").to_return(:body => body_message, :status => status)
|
15
|
+
end
|
16
|
+
it "raises #{exception.name}" do
|
17
|
+
expect{@client.list('gleu.ch')}.to raise_error exception
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Error::ServerError do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@client = Wayback::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
Wayback::Error::ServerError.errors.each do |status, exception|
|
10
|
+
context "when HTTP status is #{status}" do
|
11
|
+
before do
|
12
|
+
stub_get("/list/timemap/link/gleu.ch").to_return(:status => status)
|
13
|
+
end
|
14
|
+
it "raises #{exception.name}" do
|
15
|
+
expect{@client.list('gleu.ch')}.to raise_error exception
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Error do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
it "wraps another error class" do
|
7
|
+
begin
|
8
|
+
raise Faraday::Error::ClientError.new("Oops")
|
9
|
+
rescue Faraday::Error::ClientError
|
10
|
+
begin
|
11
|
+
raise Wayback::Error
|
12
|
+
rescue Wayback::Error => error
|
13
|
+
expect(error.message).to eq "Oops"
|
14
|
+
expect(error.wrapped_exception.class).to eq Faraday::Error::ClientError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Wayback::Identity do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
it "raises an ArgumentError when type is not specified" do
|
7
|
+
expect{Wayback::Identity.new}.to raise_error ArgumentError
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "identity map enabled" do
|
12
|
+
before do
|
13
|
+
Wayback.identity_map = Wayback::IdentityMap
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
Wayback.identity_map = false
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ".fetch" do
|
21
|
+
it "returns existing objects" do
|
22
|
+
Wayback::Identity.store(Wayback::Identity.new(:id => 1))
|
23
|
+
expect(Wayback::Identity.fetch(:id => 1)).to be
|
24
|
+
end
|
25
|
+
|
26
|
+
it "raises an error on objects that don't exist" do
|
27
|
+
expect{Wayback::Identity.fetch(:id => 6)}.to raise_error Wayback::Error::IdentityMapKeyError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#==" do
|
33
|
+
it "returns true when objects IDs are the same" do
|
34
|
+
one = Wayback::Identity.new(:id => 1, :screen_name => "gleuch")
|
35
|
+
two = Wayback::Identity.new(:id => 1, :screen_name => "ohjia")
|
36
|
+
expect(one == two).to be_true
|
37
|
+
end
|
38
|
+
it "returns false when objects IDs are different" do
|
39
|
+
one = Wayback::Identity.new(:id => 1)
|
40
|
+
two = Wayback::Identity.new(:id => 2)
|
41
|
+
expect(one == two).to be_false
|
42
|
+
end
|
43
|
+
it "returns false when classes are different" do
|
44
|
+
one = Wayback::Identity.new(:id => 1)
|
45
|
+
two = Wayback::Base.new(:id => 1)
|
46
|
+
expect(one == two).to be_false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|