totter 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +17 -0
  2. data/.travis.yml +4 -0
  3. data/Contributing.markdown +19 -0
  4. data/Gemfile +22 -0
  5. data/LICENSE +22 -0
  6. data/Rakefile +21 -0
  7. data/Readme.markdown +49 -0
  8. data/lib/totter.rb +26 -0
  9. data/lib/totter/client.rb +152 -0
  10. data/lib/totter/client/choices.rb +74 -0
  11. data/lib/totter/client/decisions.rb +91 -0
  12. data/lib/totter/client/slugs.rb +19 -0
  13. data/lib/totter/client/timelines.rb +16 -0
  14. data/lib/totter/client/users.rb +54 -0
  15. data/lib/totter/client/votes.rb +25 -0
  16. data/lib/totter/error.rb +51 -0
  17. data/lib/totter/version.rb +4 -0
  18. data/test/cassettes/choices/create_choice_upload.yml +85 -0
  19. data/test/cassettes/choices/create_for_image.yml +87 -0
  20. data/test/cassettes/choices/destroy.yml +122 -0
  21. data/test/cassettes/choices/show.yml +42 -0
  22. data/test/cassettes/decisions/analytics.yml +85 -0
  23. data/test/cassettes/decisions/create.yml +44 -0
  24. data/test/cassettes/decisions/destroy.yml +81 -0
  25. data/test/cassettes/decisions/flag.yml +81 -0
  26. data/test/cassettes/decisions/publish.yml +129 -0
  27. data/test/cassettes/decisions/show.yml +84 -0
  28. data/test/cassettes/decisions/unflag.yml +122 -0
  29. data/test/cassettes/slugs/show.yml +75 -0
  30. data/test/cassettes/timelines/global.yml +165 -0
  31. data/test/cassettes/users/following.yml +194 -0
  32. data/test/cassettes/users/me.yml +43 -0
  33. data/test/cassettes/users/user.yml +49 -0
  34. data/test/cassettes/votes/create.yml +96 -0
  35. data/test/support/client_macros.rb +5 -0
  36. data/test/test_helper.rb +24 -0
  37. data/test/totter/client/choices_test.rb +48 -0
  38. data/test/totter/client/decisions_test.rb +77 -0
  39. data/test/totter/client/slugs_test.rb +11 -0
  40. data/test/totter/client/timelines_test.rb +9 -0
  41. data/test/totter/client/users_test.rb +36 -0
  42. data/test/totter/client/votes_test.rb +15 -0
  43. data/test/totter/client_test.rb +31 -0
  44. data/test/totter_test.rb +17 -0
  45. data/totter.gemspec +24 -0
  46. metadata +155 -0
@@ -0,0 +1,19 @@
1
+ module Totter
2
+ class Client
3
+ # Client methods for working with slugs
4
+ module Slugs
5
+ # Get a slug.
6
+ #
7
+ # @param id [String] the slug id
8
+ # @param unique_id [String] an optional tracking string
9
+ # @return [Hashie::Mash]
10
+ # @example
11
+ # Seesaw.slug('d/3I0n0g')
12
+ def slug(id, unique_id = nil)
13
+ path = "slugs/#{id}"
14
+ path += "?unique_id=#{unique_id}" if unique_id
15
+ get path
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ module Totter
2
+ class Client
3
+ # Client methods for working with timelines
4
+ module Timelines
5
+ # Get recent decisions from the global timeline.
6
+ #
7
+ # @param limit [Fixnum] Number of decisions to return.
8
+ # @return [Array]
9
+ # @example
10
+ # Seesaw.recent_decisions
11
+ def global_timeline(limit = 10)
12
+ get "timelines/global?limit=#{limit}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ module Totter
2
+ class Client
3
+ # Client methods for working with users
4
+ module Users
5
+ # Get the current user
6
+ #
7
+ # Requires authenticatied client.
8
+ #
9
+ # @return [Hashie::Mash]
10
+ # @see Totter::Client
11
+ # @example
12
+ # client.me
13
+ def me
14
+ get 'me'
15
+ end
16
+
17
+ # Get a single user
18
+ #
19
+ # @param user [String] A Seeaw username or ID.
20
+ # @return [Hashie::Mash]
21
+ # @example
22
+ # Seesaw.user('soffes')
23
+ def user(user)
24
+ get "users/#{user}"
25
+ end
26
+
27
+ # Follow a user.
28
+ #
29
+ # Requires authenticatied client.
30
+ #
31
+ # @param user [String] Username or ID of the user to follow.
32
+ # @return [Boolean] True if follow was successful, false otherwise.
33
+ # @see Totter::Client
34
+ # @example
35
+ # client.follow('gotwalt')
36
+ def follow(user)
37
+ boolean_from_response :post, "users/#{user}/follow"
38
+ end
39
+
40
+ # Unfollow a user.
41
+ #
42
+ # Requires authenticatied client.
43
+ #
44
+ # @param user [String] Username or ID of the user to unfollow.
45
+ # @return [Boolean] True if unfollow was successful, false otherwise.
46
+ # @see Totter::Client
47
+ # @example
48
+ # client.unfollow('kyle')
49
+ def unfollow(user)
50
+ boolean_from_response :post, "users/#{user}/unfollow"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ module Totter
2
+ class Client
3
+ # Client methods for working with votes
4
+ module Votes
5
+ # Create a vote.
6
+ #
7
+ # @param decision_user_id [Fixnum] the decision's owner's ID
8
+ # @param decision_id [Fixnum] the decision's ID
9
+ # @param choice_id [Fixnum] the choice's ID
10
+ # @param options [Hash] specifiy `:unique_id` or `:invitation_slug`
11
+ def create_vote(decision_user_id, decision_id, choice_id, options = {})
12
+ unique_id = options[:unique_id]
13
+ raise UniqueIDRequired unless unique_id or self.authenticated?
14
+
15
+ path = "users/#{decision_user_id}/decisions/#{decision_id}/votes"
16
+ params = { choice_id: choice_id, unique_id: unique_id }
17
+
18
+ slug = options[:invitation_slug]
19
+ params[:invitation] = { slug: slug } if slug and slug[0] == 'i'
20
+
21
+ post path, params
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ module Totter
2
+ # Standard Totter error
3
+ class Error < StandardError; end
4
+
5
+ # Raised when Totter returns a 400 HTTP status code
6
+ class BadRequest < Error; end
7
+
8
+ # Raised when Totter returns a 401 HTTP status code
9
+ class Unauthorized < Error; end
10
+
11
+ # Raised when Totter returns a 403 HTTP status code
12
+ class Forbidden < Error; end
13
+
14
+ # Raised when Totter returns a 404 HTTP status code
15
+ class NotFound < Error; end
16
+
17
+ # Raised when Totter returns a 406 HTTP status code
18
+ class NotAcceptable < Error; end
19
+
20
+ # Raised when Totter returns a 422 HTTP status code
21
+ class UnprocessableEntity < Error; end
22
+
23
+ # Raised when Totter returns a 500 HTTP status code
24
+ class InternalServerError < Error; end
25
+
26
+ # Raised when Totter returns a 501 HTTP status code
27
+ class NotImplemented < Error; end
28
+
29
+ # Raised when Totter returns a 502 HTTP status code
30
+ class BadGateway < Error; end
31
+
32
+ # Raised when Totter returns a 503 HTTP status code
33
+ class ServiceUnavailable < Error; end
34
+
35
+ # Raised when a unique ID is required but not provided
36
+ class UniqueIDRequired < Error; end
37
+
38
+ # Status code to exception map
39
+ ERROR_MAP = {
40
+ 400 => Totter::BadRequest,
41
+ 401 => Totter::Unauthorized,
42
+ 403 => Totter::Forbidden,
43
+ 404 => Totter::NotFound,
44
+ 406 => Totter::NotAcceptable,
45
+ 422 => Totter::UnprocessableEntity,
46
+ 500 => Totter::InternalServerError,
47
+ 501 => Totter::NotImplemented,
48
+ 502 => Totter::BadGateway,
49
+ 503 => Totter::ServiceUnavailable
50
+ }
51
+ end
@@ -0,0 +1,4 @@
1
+ module Totter
2
+ # Verion of the Totter gem
3
+ VERSION = '0.2.0'
4
+ end
@@ -0,0 +1,85 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:5000/v1/users/1/decisions
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ Authorization:
15
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
16
+ Content-Type:
17
+ - application/json
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Content-Type:
24
+ - application/json; charset=utf-8
25
+ X-Ua-Compatible:
26
+ - IE=Edge
27
+ Etag:
28
+ - ! '"fe72872af6d81e7ab492d6b1ee9e2abd"'
29
+ Cache-Control:
30
+ - max-age=0, private, must-revalidate
31
+ X-Request-Id:
32
+ - a82f122c9397d644523d410f90be50c7
33
+ X-Runtime:
34
+ - '0.027279'
35
+ Connection:
36
+ - close
37
+ Server:
38
+ - thin 1.5.0 codename Knife
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"created_at":"2013-01-30T21:44:41Z","final_vote_id":null,"flag_count":null,"id":32,"is_private":false,"meta":null,"published_at":null,"question":null,"updated_at":"2013-01-30T21:44:41Z","user_id":1,"pusher_channel":"decision-1-32","timeline_key":"1,32","analytics":{"views":0,"unique_viewers":0,"referrers":{},"votes":{},"total_votes":0},"user_vote":null,"choices":[],"invitations":[],"user":{"biography":null,"created_at":"2013-01-23T03:22:06Z","family_name":null,"given_name":null,"id":1,"meta":null,"moderated_decisions_count":null,"updated_at":"2013-01-23T03:22:06Z","username":null,"website":null,"avatar_url":"https://recess-dev.s3.amazonaws.com/default_avatars/v1/photo_1.png","full_name":"1","short_name":"1","display_name":"1","short_display_name":"1","analytics":{"votes":0,"decisions":0,"followers":0,"following":0}},"slug":"d/2r2v2A"}'
42
+ http_version:
43
+ recorded_at: Wed, 30 Jan 2013 21:44:41 GMT
44
+ - request:
45
+ method: post
46
+ uri: http://localhost:5000/v1/users/1/decisions/32/choices
47
+ body:
48
+ encoding: US-ASCII
49
+ string: ''
50
+ headers:
51
+ Accept:
52
+ - ! '*/*'
53
+ User-Agent:
54
+ - Ruby
55
+ Authorization:
56
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
57
+ Content-Type:
58
+ - application/json
59
+ response:
60
+ status:
61
+ code: 200
62
+ message: OK
63
+ headers:
64
+ Content-Type:
65
+ - application/json; charset=utf-8
66
+ X-Ua-Compatible:
67
+ - IE=Edge
68
+ Etag:
69
+ - ! '"02b23992abdf817ee5c383ca29056d3b"'
70
+ Cache-Control:
71
+ - max-age=0, private, must-revalidate
72
+ X-Request-Id:
73
+ - 0666dd6a3a6bcbfa11b75f33fab2c63c
74
+ X-Runtime:
75
+ - '0.022490'
76
+ Connection:
77
+ - close
78
+ Server:
79
+ - thin 1.5.0 codename Knife
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ! '{"created_at":"2013-01-30T21:44:41Z","decision_id":32,"decision_user_id":1,"id":19,"meta":null,"position":1,"subject":null,"type":"ImageChoice","updated_at":"2013-01-30T21:44:41Z","image_uri":"https://s3.amazonaws.com/","upload":{"url":"https://recess-dev.s3.amazonaws.com/","params":{"AWSAccessKeyId":"AKIAIYAL2IUDRW6PBPUQ","key":"gotwalt-pro.sf.gotwalt.com/decisions/32/19/1359582281/${filename}","policy":"eyJleHBpcmF0aW9uIjoiMjAxMy0wMS0zMFQyMjo0NDo0MVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJyZWNlc3MtZGV2In0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCJnb3R3YWx0LXByby5zZi5nb3R3YWx0LmNvbS9kZWNpc2lvbnMvMzIvMTkvMTM1OTU4MjI4MS8iXSx7ImFjbCI6InB1YmxpYy1yZWFkIn0seyJzdWNjZXNzX2FjdGlvbl9yZWRpcmVjdCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC92MS91c2Vycy8xL2RlY2lzaW9ucy8zMi9jaG9pY2VzLzMwNDAybzBMMTgyZjJGMTYzMC9zMyJ9LFsiY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3Nl1dfQ==","signature":"2Sgsgg8nWp2A7FP6fG0EEN6MztY=","acl":"public-read","success_action_redirect":"http://localhost:5000/v1/users/1/decisions/32/choices/30402o0L182f2F1630/s3"}}}'
83
+ http_version:
84
+ recorded_at: Wed, 30 Jan 2013 21:44:41 GMT
85
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,87 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:5000/v1/users/1/decisions
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ Authorization:
15
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
16
+ Content-Type:
17
+ - application/json
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Content-Type:
24
+ - application/json; charset=utf-8
25
+ X-Ua-Compatible:
26
+ - IE=Edge
27
+ Etag:
28
+ - ! '"17c9b6356fae36d9b359dd0e2e56915f"'
29
+ Cache-Control:
30
+ - max-age=0, private, must-revalidate
31
+ X-Request-Id:
32
+ - fddf25eccf2dea50779bcc1268429bea
33
+ X-Runtime:
34
+ - '0.075714'
35
+ Connection:
36
+ - close
37
+ Server:
38
+ - thin 1.5.0 codename Knife
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"created_at":"2013-01-30T21:44:41Z","final_vote_id":null,"flag_count":null,"id":33,"is_private":false,"meta":null,"published_at":null,"question":null,"updated_at":"2013-01-30T21:44:41Z","user_id":1,"pusher_channel":"decision-1-33","timeline_key":"1,33","analytics":{"views":0,"unique_viewers":0,"referrers":{},"votes":{},"total_votes":0},"user_vote":null,"choices":[],"invitations":[],"user":{"biography":null,"created_at":"2013-01-23T03:22:06Z","family_name":null,"given_name":null,"id":1,"meta":null,"moderated_decisions_count":null,"updated_at":"2013-01-23T03:22:06Z","username":null,"website":null,"avatar_url":"https://recess-dev.s3.amazonaws.com/default_avatars/v1/photo_1.png","full_name":"1","short_name":"1","display_name":"1","short_display_name":"1","analytics":{"votes":0,"decisions":0,"followers":0,"following":0}},"slug":"d/1W362T"}'
42
+ http_version:
43
+ recorded_at: Wed, 30 Jan 2013 21:44:41 GMT
44
+ - request:
45
+ method: post
46
+ uri: http://localhost:5000/v1/users/1/decisions/33/choices
47
+ body:
48
+ encoding: UTF-8
49
+ string: ! '{"choice":{"type":"image","image_url":"http://recess.s3.amazonaws.com/default_avatars/v1/photo_1.png","subject":"Test
50
+ Image","meta":{"link_url":"http://seesaw.co","link_title":"Seesaw"}}}'
51
+ headers:
52
+ Accept:
53
+ - ! '*/*'
54
+ User-Agent:
55
+ - Ruby
56
+ Authorization:
57
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
58
+ Content-Type:
59
+ - application/json
60
+ response:
61
+ status:
62
+ code: 200
63
+ message: OK
64
+ headers:
65
+ Content-Type:
66
+ - application/json; charset=utf-8
67
+ X-Ua-Compatible:
68
+ - IE=Edge
69
+ Etag:
70
+ - ! '"6bd2e538cb6c096628df5e5e8c52b8bb"'
71
+ Cache-Control:
72
+ - max-age=0, private, must-revalidate
73
+ X-Request-Id:
74
+ - 6cab0f1f8d22dedc4920106aed2852ff
75
+ X-Runtime:
76
+ - '0.604433'
77
+ Connection:
78
+ - close
79
+ Server:
80
+ - thin 1.5.0 codename Knife
81
+ body:
82
+ encoding: US-ASCII
83
+ string: ! '{"created_at":"2013-01-30T21:44:41Z","decision_id":33,"decision_user_id":1,"id":20,"meta":{"link_url":"http://seesaw.co","link_title":"Seesaw"},"position":1,"subject":"Test
84
+ Image","type":"ImageChoice","updated_at":"2013-01-30T21:44:41Z","image_uri":"https://recess-dev.s3.amazonaws.com/gotwalt-pro.sf.gotwalt.com/decisions/33/20/1359582281/photo.png"}'
85
+ http_version:
86
+ recorded_at: Wed, 30 Jan 2013 21:44:41 GMT
87
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,122 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:5000/v1/users/1/decisions
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ Authorization:
15
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
16
+ Content-Type:
17
+ - application/json
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Content-Type:
24
+ - application/json; charset=utf-8
25
+ X-Ua-Compatible:
26
+ - IE=Edge
27
+ Etag:
28
+ - ! '"a065c212f634cce169159f9e66c40e42"'
29
+ Cache-Control:
30
+ - max-age=0, private, must-revalidate
31
+ X-Request-Id:
32
+ - 11b81d00325361beeb6dda08b5eca88d
33
+ X-Runtime:
34
+ - '0.027600'
35
+ Connection:
36
+ - close
37
+ Server:
38
+ - thin 1.5.0 codename Knife
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"created_at":"2013-01-30T21:45:41Z","final_vote_id":null,"flag_count":null,"id":34,"is_private":false,"meta":null,"published_at":null,"question":null,"updated_at":"2013-01-30T21:45:41Z","user_id":1,"pusher_channel":"decision-1-34","timeline_key":"1,34","analytics":{"views":0,"unique_viewers":0,"referrers":{},"votes":{},"total_votes":0},"user_vote":null,"choices":[],"invitations":[],"user":{"biography":null,"created_at":"2013-01-23T03:22:06Z","family_name":null,"given_name":null,"id":1,"meta":null,"moderated_decisions_count":null,"updated_at":"2013-01-23T03:22:06Z","username":null,"website":null,"avatar_url":"https://recess-dev.s3.amazonaws.com/default_avatars/v1/photo_1.png","full_name":"1","short_name":"1","display_name":"1","short_display_name":"1","analytics":{"votes":0,"decisions":0,"followers":0,"following":0}},"slug":"d/3H2Y0T"}'
42
+ http_version:
43
+ recorded_at: Wed, 30 Jan 2013 21:45:42 GMT
44
+ - request:
45
+ method: post
46
+ uri: http://localhost:5000/v1/users/1/decisions/34/choices
47
+ body:
48
+ encoding: US-ASCII
49
+ string: ''
50
+ headers:
51
+ Accept:
52
+ - ! '*/*'
53
+ User-Agent:
54
+ - Ruby
55
+ Authorization:
56
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
57
+ Content-Type:
58
+ - application/json
59
+ response:
60
+ status:
61
+ code: 200
62
+ message: OK
63
+ headers:
64
+ Content-Type:
65
+ - application/json; charset=utf-8
66
+ X-Ua-Compatible:
67
+ - IE=Edge
68
+ Etag:
69
+ - ! '"ee3e37e9de385d6218a89aa990e974a7"'
70
+ Cache-Control:
71
+ - max-age=0, private, must-revalidate
72
+ X-Request-Id:
73
+ - d89c73e6a43d0a2deb90538b92533b0f
74
+ X-Runtime:
75
+ - '0.021898'
76
+ Connection:
77
+ - close
78
+ Server:
79
+ - thin 1.5.0 codename Knife
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ! '{"created_at":"2013-01-30T21:45:42Z","decision_id":34,"decision_user_id":1,"id":21,"meta":null,"position":1,"subject":null,"type":"ImageChoice","updated_at":"2013-01-30T21:45:42Z","image_uri":"https://s3.amazonaws.com/","upload":{"url":"https://recess-dev.s3.amazonaws.com/","params":{"AWSAccessKeyId":"AKIAIYAL2IUDRW6PBPUQ","key":"gotwalt-pro.sf.gotwalt.com/decisions/34/21/1359582342/${filename}","policy":"eyJleHBpcmF0aW9uIjoiMjAxMy0wMS0zMFQyMjo0NTo0MloiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJyZWNlc3MtZGV2In0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCJnb3R3YWx0LXByby5zZi5nb3R3YWx0LmNvbS9kZWNpc2lvbnMvMzQvMjEvMTM1OTU4MjM0Mi8iXSx7ImFjbCI6InB1YmxpYy1yZWFkIn0seyJzdWNjZXNzX2FjdGlvbl9yZWRpcmVjdCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMC92MS91c2Vycy8xL2RlY2lzaW9ucy8zNC9jaG9pY2VzLzN6MzgzRDJwM2szajJEMkkwVi9zMyJ9LFsiY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3Nl1dfQ==","signature":"L+fuJLNpquy1z/dQgkDFanvhEWY=","acl":"public-read","success_action_redirect":"http://localhost:5000/v1/users/1/decisions/34/choices/3z383D2p3k3j2D2I0V/s3"}}}'
83
+ http_version:
84
+ recorded_at: Wed, 30 Jan 2013 21:45:42 GMT
85
+ - request:
86
+ method: delete
87
+ uri: http://localhost:5000/v1/users/1/decisions/34/choices/21
88
+ body:
89
+ encoding: US-ASCII
90
+ string: ''
91
+ headers:
92
+ Accept:
93
+ - ! '*/*'
94
+ User-Agent:
95
+ - Ruby
96
+ Authorization:
97
+ - Bearer 9774e653f7b3c1de5f21b61adc08ba24
98
+ Content-Type:
99
+ - application/json
100
+ response:
101
+ status:
102
+ code: 204
103
+ message: No Content
104
+ headers:
105
+ X-Ua-Compatible:
106
+ - IE=Edge
107
+ Cache-Control:
108
+ - no-cache
109
+ X-Request-Id:
110
+ - a7961b4c7ba620f19eeab109ac8b2378
111
+ X-Runtime:
112
+ - '0.013544'
113
+ Connection:
114
+ - close
115
+ Server:
116
+ - thin 1.5.0 codename Knife
117
+ body:
118
+ encoding: US-ASCII
119
+ string: ''
120
+ http_version:
121
+ recorded_at: Wed, 30 Jan 2013 21:45:42 GMT
122
+ recorded_with: VCR 2.4.0