totter 0.2.3 → 0.2.4

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.
data/Readme.markdown CHANGED
@@ -6,7 +6,9 @@ All networking is done with Net::HTTP so you don't have to worry about version c
6
6
 
7
7
  Read the [documentation](http://rubydoc.info/github/seesawco/totter-rb/master/frames) online.
8
8
 
9
- [![Build Status](https://travis-ci.org/seesawco/totter-rb.png?branch=master)](https://travis-ci.org/seesawco/totter-rb) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/seesawco/totter-rb)
9
+ [![Build Status](https://travis-ci.org/seesawco/totter-rb.png?branch=master)](https://travis-ci.org/seesawco/totter-rb)
10
+
11
+ [![Code Climate](https://codeclimate.com/github/seesawco/totter-rb.png)](https://codeclimate.com/github/seesawco/totter-rb)
10
12
 
11
13
  ## Installation
12
14
 
@@ -2,17 +2,22 @@ module Totter
2
2
  class Client
3
3
  # Client methods for working with timelines
4
4
  module Timelines
5
+ # Default options sent with every timeline request unless otherwise specified.
6
+ DEFAULT_TIMELINE_OPTIONS = {
7
+ limit: 20
8
+ }
9
+
5
10
  # Get recent decisions from the global timeline.
6
11
  #
7
12
  # @param options [Hash] Parameters for returning selected items
8
13
  # @option options [Numeric] :limit Number of items to return. Default is 20
9
14
  # @option options [String] :since A user_id/decision_id pair in the format '1,15' when paging forward
10
15
  # @option options [String] :until A user_id/decision_id pair in the format '1,15' when paging backwards
11
- # @return [Array]
16
+ # @return [Array] An array of `Hashie::Mash` objects representing decisions
12
17
  # @example
13
18
  # Seesaw.global_timeline(limit: 20, since: '1,15')
14
- def global_timeline(options = default_options)
15
- get "timelines/global", options
19
+ def global_timeline(options = DEFAULT_TIMELINE_OPTIONS)
20
+ get 'timelines/global', options
16
21
  end
17
22
 
18
23
  # Get recent decisions from a hashtag timeline
@@ -22,11 +27,11 @@ module Totter
22
27
  # @option options [Numeric] :limit Number of items to return. Default is 20
23
28
  # @option options [String] :since A user_id/decision_id pair in the format '1,15' when paging forward
24
29
  # @option options [String] :until A user_id/decision_id pair in the format '1,15' when paging backwards
25
- # @return [Array]
30
+ # @return [Array] An array of `Hashie::Mash` objects representing decisions
26
31
  # @example
27
32
  # Seesaw.global_timeline(limit: 20, since: '1,15')
28
- def hashtag_timeline(hashtag, options = default_options)
29
- get "timelines/global", options.merge({hashtag: hashtag})
33
+ def hashtag_timeline(hashtag, options = DEFAULT_TIMELINE_OPTIONS)
34
+ get 'timelines/global', options.merge({hashtag: hashtag})
30
35
  end
31
36
 
32
37
  # Get recent decisions from a sticker timeline
@@ -39,8 +44,8 @@ module Totter
39
44
  # @return [Array]
40
45
  # @example
41
46
  # Seesaw.global_timeline(limit: 20, since: '1,15')
42
- def sticker_timeline(sticker, options = default_options)
43
- get "timelines/global", options.merge({sticker: sticker})
47
+ def sticker_timeline(sticker, options = DEFAULT_TIMELINE_OPTIONS)
48
+ get 'timelines/global', options.merge({sticker: sticker})
44
49
  end
45
50
 
46
51
  # Search for published items
@@ -50,11 +55,11 @@ module Totter
50
55
  # @option options [Numeric] :limit Number of items to return. Default is 20
51
56
  # @option options [String] :since A user_id/decision_id pair in the format '1,15' when paging forward
52
57
  # @option options [String] :until A user_id/decision_id pair in the format '1,15' when paging backwards
53
- # @return [Array]
58
+ # @return [Array] An array of `Hashie::Mash` objects representing decisions
54
59
  # @example
55
60
  # Seesaw.global_timeline(limit: 20, since: '1,15')
56
- def search_timeline(query, options = default_options)
57
- get "timelines/search", options.merge({query: query})
61
+ def search_timeline(query, options = DEFAULT_TIMELINE_OPTIONS)
62
+ get 'timelines/search', options.merge({query: query})
58
63
  end
59
64
 
60
65
  # Get recent decisions from the flagged-for-review timeline
@@ -63,19 +68,25 @@ module Totter
63
68
  # @option options [Numeric] :limit Number of items to return. Default is 20
64
69
  # @option options [String] :since A user_id/decision_id pair in the format '1,15' when paging forward
65
70
  # @option options [String] :until A user_id/decision_id pair in the format '1,15' when paging backwards
66
- # @return [Array]
71
+ # @return [Array] An array of `Hashie::Mash` objects representing decisions
67
72
  # @example
68
73
  # Seesaw.global_timeline(limit: 20, since: '1,15')
69
- def flagged_timeline(options = default_options)
70
- get "timelines/flagged", options
74
+ def flagged_timeline(options = DEFAULT_TIMELINE_OPTIONS)
75
+ get 'timelines/flagged', options
71
76
  end
72
77
 
73
- private
74
-
75
- def default_options
76
- {
77
- limit: 20
78
- }
78
+ # Get recent decisions from a given user.
79
+ #
80
+ # @param user_id [Fixnum] The user ID for the timeline you are trying to view.
81
+ # @param options [Hash] Parameters for returning selected items
82
+ # @option options [Numeric] :limit Number of items to return. Default is 20
83
+ # @option options [String] :since A user_id/decision_id pair in the format '1,15' when paging forward
84
+ # @option options [String] :until A user_id/decision_id pair in the format '1,15' when paging backwards
85
+ # @return [Array] An array of `Hashie::Mash` objects representing decisions
86
+ # @example
87
+ # Seesaw.user_timeline(4, limit: 20, since: '1,15')
88
+ def user_timeline(user_id, options = DEFAULT_TIMELINE_OPTIONS)
89
+ get "users/#{user_id}/timelines/user", options
79
90
  end
80
91
  end
81
92
  end
data/lib/totter/client.rb CHANGED
@@ -1,21 +1,10 @@
1
- require 'net/http'
2
- require 'net/https'
3
- require 'uri'
4
- require 'multi_json'
5
- require 'hashie'
6
- require 'addressable/uri'
7
-
8
- require 'totter/client/users'
9
- require 'totter/client/decisions'
10
- require 'totter/client/slugs'
11
- require 'totter/client/timelines'
12
- require 'totter/client/choices'
13
- require 'totter/client/votes'
14
- require 'totter/client/avatars'
1
+ require 'totter/transport'
15
2
 
16
3
  module Totter
17
4
  # API client for interacting with the Seesaw API
18
5
  class Client
6
+ Dir[File.expand_path('../client/*.rb', __FILE__)].each { |f| require f }
7
+
19
8
  include Totter::Client::Decisions
20
9
  include Totter::Client::Users
21
10
  include Totter::Client::Slugs
@@ -28,10 +17,11 @@ module Totter
28
17
  attr_reader :api_scheme
29
18
  attr_reader :api_host
30
19
  attr_reader :api_version
20
+ attr_reader :transport
31
21
 
32
22
  # Initialize a new client.
33
23
  #
34
- # @param options [Hash] optionally specify `:access_token`, `:api_scheme`, `:api_host`, `:api_version`, or `:client_token`
24
+ # @param options [Hash] optionally specify `:access_token`, `:api_scheme`, `:api_host`, `:api_version`, `:client_token`, or `:transport`.
35
25
  def initialize(options = {})
36
26
  options = { access_token: options } if options.is_a? String
37
27
 
@@ -40,6 +30,12 @@ module Totter
40
30
  @api_host = (options[:api_host] or 'api.seesaw.co')
41
31
  @api_version = (options[:api_version] or 1)
42
32
  @client_token = options[:client_token] if options[:client_token]
33
+ @transport = (options[:transport] or :http)
34
+
35
+ # Include transport
36
+ transport_module = Totter::Transport::TRANSPORT_MAP[@transport]
37
+ raise 'Invalid transport' unless transport_module
38
+ self.extend transport_module
43
39
  end
44
40
 
45
41
  # API base URL.
@@ -62,105 +58,5 @@ module Totter
62
58
  def ssl?
63
59
  @api_scheme == 'https'
64
60
  end
65
-
66
- private
67
-
68
- def http
69
- return @http if @http
70
-
71
- uri = URI.parse(self.base_url)
72
- @http = Net::HTTP.new(uri.host, uri.port)
73
- @http.use_ssl = self.ssl?
74
- @http
75
- end
76
-
77
- def request(method, path, params = nil)
78
- uri = Addressable::URI.parse("#{self.base_url}#{path}")
79
-
80
- # if the request requires parameters in the query string, merge them in
81
- if params and !can_post_data?(method)
82
- uri.query_values = (uri.query_values || {}).merge(params)
83
- end
84
-
85
- # Build request
86
- request = build_request(method, uri)
87
-
88
- # Add headers
89
- request['Authorization'] = "Bearer #{self.access_token}" if authenticated?
90
- request['X-Seesaw-Client-Token'] = @client_token if @client_token
91
- request['Content-Type'] = 'application/json'
92
-
93
- # Add params as JSON if they exist
94
- request.body = MultiJson.dump(params) if can_post_data?(method) and params
95
-
96
- # Request
97
- response = http.request(request)
98
-
99
- # Check for errors
100
- handle_error(response)
101
-
102
- # Return the raw response object
103
- response
104
- end
105
-
106
- def build_request(method, uri)
107
- case method
108
- when :get
109
- Net::HTTP::Get.new(uri.request_uri)
110
- when :post
111
- Net::HTTP::Post.new(uri.request_uri)
112
- when :put
113
- Net::HTTP::Put.new(uri.request_uri)
114
- when :delete
115
- Net::HTTP::Delete.new(uri.request_uri)
116
- end
117
- end
118
-
119
- def handle_error(response)
120
- # Find error or return
121
- return unless error = Totter::ERROR_MAP[response.code.to_i]
122
-
123
- # Try to add a useful message
124
- message = nil
125
- begin
126
- message = MultiJson.load(response.body)['error_description']
127
- rescue MultiJson::DecodeError => e
128
- end
129
-
130
- # Raise error
131
- raise error.new(message)
132
- end
133
-
134
- def json_request(*args)
135
- # Preform request
136
- response = request(*args)
137
-
138
- # Parse JSON
139
- object = MultiJson.load(response.body)
140
-
141
- # Hash
142
- return Hashie::Mash.new(object) if object.is_a? Hash
143
-
144
- # Array
145
- return object.map { |h| Hashie::Mash.new(h) } if object.is_a? Array
146
-
147
- # Fallback incase it's not a hash or array
148
- object
149
- end
150
-
151
- def boolean_from_response(*args)
152
- response = request(*args)
153
- (200..299).include? response.code.to_i
154
- end
155
-
156
- def can_post_data?(method)
157
- [:post, :put].include?(method)
158
- end
159
-
160
- [:get, :post, :put, :delete].each do |method|
161
- define_method method do |*args|
162
- json_request(method, *args)
163
- end
164
- end
165
61
  end
166
62
  end
@@ -0,0 +1,113 @@
1
+ module Totter
2
+ module Transport
3
+ # Default HTTP API transport adapter
4
+ module HTTP
5
+ require 'net/http'
6
+ require 'net/https'
7
+ require 'uri'
8
+ require 'multi_json'
9
+ require 'hashie'
10
+
11
+ private
12
+
13
+ def http
14
+ return @http if @http
15
+
16
+ uri = URI.parse(self.base_url)
17
+ @http = Net::HTTP.new(uri.host, uri.port)
18
+ @http.use_ssl = self.ssl?
19
+ @http
20
+ end
21
+
22
+ def request(method, path, params = nil)
23
+ uri = URI.parse("#{self.base_url}#{path}")
24
+
25
+ # if the request requires parameters in the query string, merge them in
26
+ if params and !can_post_data?(method)
27
+ query_values = uri.query ? URI.decode_www_form(uri.query).inject({}) {|h,(k,v)| h[k]=v; h} : {}
28
+ uri.query = URI.encode_www_form (query_values || {}).merge(params)
29
+ end
30
+
31
+ # Build request
32
+ request = build_request(method, uri)
33
+
34
+ # Add headers
35
+ request['Authorization'] = "Bearer #{self.access_token}" if authenticated?
36
+ request['X-Seesaw-Client-Token'] = @client_token if @client_token
37
+ request['Content-Type'] = 'application/json'
38
+
39
+ # Add params as JSON if they exist
40
+ request.body = MultiJson.dump(params) if can_post_data?(method) and params
41
+
42
+ # Request
43
+ response = http.request(request)
44
+
45
+ # Check for errors
46
+ handle_error(response)
47
+
48
+ # Return the raw response object
49
+ response
50
+ end
51
+
52
+ def build_request(method, uri)
53
+ case method
54
+ when :get
55
+ Net::HTTP::Get.new(uri.request_uri)
56
+ when :post
57
+ Net::HTTP::Post.new(uri.request_uri)
58
+ when :put
59
+ Net::HTTP::Put.new(uri.request_uri)
60
+ when :delete
61
+ Net::HTTP::Delete.new(uri.request_uri)
62
+ end
63
+ end
64
+
65
+ def handle_error(response)
66
+ # Find error or return
67
+ return unless error = Totter::ERROR_MAP[response.code.to_i]
68
+
69
+ # Try to add a useful message
70
+ message = nil
71
+ begin
72
+ message = MultiJson.load(response.body)['error_description']
73
+ rescue MultiJson::DecodeError => e
74
+ end
75
+
76
+ # Raise error
77
+ raise error.new(message)
78
+ end
79
+
80
+ def json_request(*args)
81
+ # Preform request
82
+ response = request(*args)
83
+
84
+ # Parse JSON
85
+ object = MultiJson.load(response.body)
86
+
87
+ # Hash
88
+ return Hashie::Mash.new(object) if object.is_a? Hash
89
+
90
+ # Array
91
+ return object.map { |h| Hashie::Mash.new(h) } if object.is_a? Array
92
+
93
+ # Fallback incase it's not a hash or array
94
+ object
95
+ end
96
+
97
+ def boolean_from_response(*args)
98
+ response = request(*args)
99
+ (200..299).include? response.code.to_i
100
+ end
101
+
102
+ def can_post_data?(method)
103
+ [:post, :put].include?(method)
104
+ end
105
+
106
+ [:get, :post, :put, :delete].each do |method|
107
+ define_method method do |*args|
108
+ json_request(method, *args)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,11 @@
1
+ module Totter
2
+ # Transports are a way for the client to communicate with the API.
3
+ module Transport
4
+ Dir[File.expand_path('../transport/*.rb', __FILE__)].each { |f| require f }
5
+
6
+ # Transport adapter map
7
+ TRANSPORT_MAP = {
8
+ http: Totter::Transport::HTTP
9
+ }
10
+ end
11
+ end
@@ -1,4 +1,4 @@
1
1
  module Totter
2
2
  # Verion of the Totter gem
3
- VERSION = '0.2.3'
3
+ VERSION = '0.2.4'
4
4
  end
@@ -0,0 +1,46 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://localhost:5000/v1/users/4/timelines/user?limit=20
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
+ X-Pusher-Channel:
24
+ - timeline-user-4
25
+ Content-Type:
26
+ - application/json; charset=utf-8
27
+ X-Ua-Compatible:
28
+ - IE=Edge
29
+ Etag:
30
+ - ! '"d751713988987e9331980363e24189ce"'
31
+ Cache-Control:
32
+ - max-age=0, private, must-revalidate
33
+ X-Request-Id:
34
+ - aeaaf8b6b674667481f04ef39c7f0812
35
+ X-Runtime:
36
+ - '0.009301'
37
+ Connection:
38
+ - close
39
+ Server:
40
+ - thin 1.5.0 codename Knife
41
+ body:
42
+ encoding: US-ASCII
43
+ string: ! '[]'
44
+ http_version:
45
+ recorded_at: Tue, 05 Feb 2013 16:21:27 GMT
46
+ recorded_with: VCR 2.4.0
@@ -34,4 +34,11 @@ class TimelinesTest < Totter::TestCase
34
34
  assert_equal 1, local_client.flagged_timeline.length
35
35
  end
36
36
  end
37
+
38
+ def test_user
39
+ VCR.use_cassette 'timelines/user' do
40
+ client = local_client
41
+ assert_equal 0, local_client.user_timeline(4).length
42
+ end
43
+ end
37
44
  end
data/totter.gemspec CHANGED
@@ -21,5 +21,4 @@ Gem::Specification.new do |gem|
21
21
  gem.required_ruby_version = '>= 1.9.2'
22
22
  gem.add_dependency 'multi_json', '~> 1.5.0'
23
23
  gem.add_dependency 'hashie', '~> 1.2.0'
24
- gem.add_dependency 'addressable', '~> 2.3.0'
25
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: totter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-04 00:00:00.000000000 Z
13
+ date: 2013-02-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: multi_json
@@ -44,22 +44,6 @@ dependencies:
44
44
  - - ~>
45
45
  - !ruby/object:Gem::Version
46
46
  version: 1.2.0
47
- - !ruby/object:Gem::Dependency
48
- name: addressable
49
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ~>
53
- - !ruby/object:Gem::Version
54
- version: 2.3.0
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
60
- - - ~>
61
- - !ruby/object:Gem::Version
62
- version: 2.3.0
63
47
  description: Ruby gem for working with the Seesaw API.
64
48
  email:
65
49
  - sam@soff.es
@@ -85,6 +69,8 @@ files:
85
69
  - lib/totter/client/users.rb
86
70
  - lib/totter/client/votes.rb
87
71
  - lib/totter/error.rb
72
+ - lib/totter/transport.rb
73
+ - lib/totter/transport/http.rb
88
74
  - lib/totter/version.rb
89
75
  - test/cassettes/avatars/create.yml
90
76
  - test/cassettes/avatars/destroy.yml
@@ -107,6 +93,7 @@ files:
107
93
  - test/cassettes/timelines/hashtags.yml
108
94
  - test/cassettes/timelines/search.yml
109
95
  - test/cassettes/timelines/stickers.yml
96
+ - test/cassettes/timelines/user.yml
110
97
  - test/cassettes/users/following.yml
111
98
  - test/cassettes/users/me.yml
112
99
  - test/cassettes/users/update.yml
@@ -143,6 +130,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
130
  - - ! '>='
144
131
  - !ruby/object:Gem::Version
145
132
  version: '0'
133
+ segments:
134
+ - 0
135
+ hash: 3570192698254323384
146
136
  requirements: []
147
137
  rubyforge_project:
148
138
  rubygems_version: 1.8.23
@@ -171,6 +161,7 @@ test_files:
171
161
  - test/cassettes/timelines/hashtags.yml
172
162
  - test/cassettes/timelines/search.yml
173
163
  - test/cassettes/timelines/stickers.yml
164
+ - test/cassettes/timelines/user.yml
174
165
  - test/cassettes/users/following.yml
175
166
  - test/cassettes/users/me.yml
176
167
  - test/cassettes/users/update.yml