minmb-teambox-client 0.4.0

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.
Files changed (42) hide show
  1. data/Gemfile +11 -0
  2. data/Gemfile.lock +54 -0
  3. data/History +6 -0
  4. data/License +20 -0
  5. data/README.rdoc +30 -0
  6. data/Rakefile +44 -0
  7. data/VERSION +1 -0
  8. data/examples/conversation.rb +12 -0
  9. data/examples/task.rb +17 -0
  10. data/examples/users.rb +19 -0
  11. data/lib/teambox-client/models/activity.rb +27 -0
  12. data/lib/teambox-client/models/comment.rb +55 -0
  13. data/lib/teambox-client/models/conversation.rb +26 -0
  14. data/lib/teambox-client/models/divider.rb +15 -0
  15. data/lib/teambox-client/models/invitation.rb +21 -0
  16. data/lib/teambox-client/models/membership.rb +15 -0
  17. data/lib/teambox-client/models/note.rb +15 -0
  18. data/lib/teambox-client/models/organization.rb +18 -0
  19. data/lib/teambox-client/models/page.rb +20 -0
  20. data/lib/teambox-client/models/page_slot.rb +16 -0
  21. data/lib/teambox-client/models/person.rb +19 -0
  22. data/lib/teambox-client/models/project.rb +52 -0
  23. data/lib/teambox-client/models/task.rb +66 -0
  24. data/lib/teambox-client/models/task_list.rb +26 -0
  25. data/lib/teambox-client/models/teambox_data.rb +16 -0
  26. data/lib/teambox-client/models/upload.rb +27 -0
  27. data/lib/teambox-client/models/user.rb +11 -0
  28. data/lib/teambox-client/reference_list.rb +49 -0
  29. data/lib/teambox-client/result_set.rb +72 -0
  30. data/lib/teambox-client/teambox.rb +288 -0
  31. data/lib/teambox-client/teambox_oauth.rb +37 -0
  32. data/lib/teambox-client.rb +8 -0
  33. data/minmb-teambox-client.gemspec +96 -0
  34. data/spec/client_spec.rb +17 -0
  35. data/spec/conversation_spec.rb +29 -0
  36. data/spec/project_spec.rb +11 -0
  37. data/spec/resource_spec.rb +77 -0
  38. data/spec/result_set_spec.rb +55 -0
  39. data/spec/spec_helper.rb +7 -0
  40. data/spec/task_lists_spec.rb +17 -0
  41. data/spec/tasks_spec.rb +18 -0
  42. metadata +251 -0
@@ -0,0 +1,27 @@
1
+ module Teambox
2
+ class Upload < Teambox::Resource
3
+ def user
4
+ get_or_make_reference('User', @data, 'user_id')
5
+ end
6
+
7
+ def project
8
+ get_or_make_reference('Project', @data, 'project_id')
9
+ end
10
+
11
+ def page
12
+ get_or_make_reference('Project', @data, 'project_id')
13
+ end
14
+
15
+ def page_slot
16
+ get_or_make_reference('PageSlot', @data, 'page_slot_id')
17
+ end
18
+
19
+ def comment
20
+ get_or_make_reference('Comment', @data, 'comment_id')
21
+ end
22
+
23
+ def url #:nodoc:
24
+ "/projects/#{@data['project_id']}/#{@data['id']}"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module Teambox
2
+ class User < Teambox::Resource
3
+ def name
4
+ "#{@data['first_name']} #{@data['last_name']}"
5
+ end
6
+
7
+ def url #:nodoc:
8
+ "/users/#{@data['id']}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,49 @@
1
+ # Methods for handling references list
2
+ module ReferenceList
3
+ # Generate references hash from JSON data
4
+ def generate_references(data)
5
+ @references = {}
6
+ @references.tap { |h| data.each {|ref| h[ref['type'] + ref['id'].to_s] = Teambox.create_model(ref['type'], ref, self) } }
7
+ end
8
+
9
+ # References resource in the current Teambox::ResultSet
10
+ def set_reference(klass, resource)
11
+ real_resource = if resource.is_a? Teambox::Resource
12
+ resource
13
+ else
14
+ Teambox.const_get(klass).new(resource, self)
15
+ end
16
+
17
+ @references[klass.to_s + real_resource.id.to_s] = real_resource
18
+ real_resource
19
+ end
20
+
21
+ # Gets a referenced object. e.g:
22
+ # get_reference('User', 1)
23
+ def get_reference(klass, id)
24
+ @references[klass.to_s + (id||'').to_s]
25
+ end
26
+
27
+ # get reference based on data. Makes new resource if reference does not exist. e.g.
28
+ # get_or_make_reference('User', @data, 'user_id')
29
+ def get_or_make_reference(klass, data, field_id)
30
+ get_reference(klass, data[field_id]) || set_reference(klass, {}.merge({'id' => data[field_id]}))
31
+ end
32
+
33
+ # get a list of references based on data. Makes a new resource for each references which doesnot exist.
34
+ def get_or_make_references(klass, data, field_id, field_data=nil)
35
+ if data[field_data]
36
+ data[field_data].map do |object|
37
+ get_reference(klass, object['id']) ||
38
+ set_reference(klass, object)
39
+ end
40
+ elsif data[field_id]
41
+ data[field_id].map do |object_id|
42
+ get_reference(klass, object_id) ||
43
+ set_reference(klass, {'id' => object_id})
44
+ end
45
+ else
46
+ []
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,72 @@
1
+ module Teambox
2
+ # This represents a list of objects along with referenced objects returned by the API.
3
+ #
4
+ # == Basic Usage
5
+ #
6
+ # A Teambox::ResultSet is usually returned from a get request from Teambox::Client. e.g.:
7
+ #
8
+ # list = client.get('/projects') # Teambox::ResultSet
9
+ # puts "Returned #{list.length} projects"
10
+ #
11
+ # The Teambox API only returns a limited amount of objects per request (currently 50),
12
+ # so the methods prev, next, and empty? are provided to navigate the list of objects.
13
+ # e.g. To get all projects, you can use something like:
14
+ #
15
+ # project_list = []
16
+ # list = client.get('/projects')
17
+ # while !list.empty?
18
+ # items += list.objects
19
+ # list = list.prev
20
+ # end
21
+ #
22
+ class ResultSet
23
+ include ReferenceList
24
+ attr_reader :first_id, :last_id, :client, :references, :objects
25
+
26
+ def initialize(client, request, objects, references) #:nodoc:
27
+ @client = client
28
+ @request = request
29
+ generate_references(references)
30
+ @objects = objects.map { |o| Teambox.create_model(o['type'], o, self) }
31
+
32
+ id_list = objects.map{|obj| obj['id']}.sort
33
+ @first_id = id_list[0]
34
+ @last_id = id_list[-1]
35
+ end
36
+
37
+ # Yields for each object
38
+ def each(&block)
39
+ @objects.each(&block)
40
+ end
41
+
42
+ # Yields for each object
43
+ def map(&block)
44
+ @objects.map(&block)
45
+ end
46
+
47
+ # Length of object list
48
+ def length
49
+ @objects.length
50
+ end
51
+
52
+ # Is the object list empty?
53
+ def empty?
54
+ @objects.length == 0
55
+ end
56
+
57
+ # Gets older items as a Teambox::ResultSet
58
+ def prev
59
+ @client.get(@request[:url], {}, :query => (@request[:query]).merge(:max_id => @first_id))
60
+ end
61
+
62
+ # Gets newer items as a Teambox::ResultSet
63
+ def next
64
+ @client.get(@request[:url], {}, :query => (@request[:query]).merge(:since_id => @last_id))
65
+ end
66
+
67
+ # Indexes into object array
68
+ def [](idx)
69
+ @objects[idx]
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,288 @@
1
+ # Teambox API wrapper. See Teambox::Client for more details.
2
+ module Teambox
3
+ # This is the entrypoint to the Teambox API.
4
+ #
5
+ # == Basic Usage
6
+ #
7
+ # Create a Teambox::Client, passing in your authentication detials in :auth.
8
+ # Then use one of the helper methods to get data.
9
+ #
10
+ # client = Teambox::Client.new(:auth => {:user => 'frank', :password => 'papapa'})
11
+ # client.current_user # == frank
12
+ # client.project('earthworks')
13
+ #
14
+ # The methods get, post, put, delete, and safe_get are provided in case you want to
15
+ # access an API method not covered by a helper. e.g.:
16
+ #
17
+ # client.get('/account')
18
+ #
19
+ # The API will either return a Teambox::Resource, or a Teambox::ResultSet in the case of
20
+ # index methods.
21
+ #
22
+ # Errors returned by the api are thrown as a Teambox::APIError, so beware of this when writing
23
+ # your api code.
24
+ #
25
+ # begin
26
+ # client.project('earthworks').create_conversation(:name => 'Serious discussion', :body => 'We need a serious discussion')
27
+ # rescue Teambox::APIError => e
28
+ # puts "Something went wrong: #{e.inspect}"
29
+ # end
30
+ #
31
+ # == OAuth authentication
32
+ #
33
+ # To authenticate via OAuth (currently not supported on teambox.com), you will need
34
+ # to pass in your consumer key, secret, and redirect url in :auth. Then use authorize_url
35
+ # and authorize to complete authentication.
36
+ #
37
+ # client = Teambox::Client.new(:auth => {
38
+ # :oauth_app_id => 'h6K1Ru9sVFbPGEK5v9gQFPHTNZ5IRsVCGNeGENQ3',
39
+ # :oauth_app_secret => 'fec4x9P7atC666JzF6WEZIeY6pVv1lCp6aLfVJBw',
40
+ # :redirect_uri => 'http://www.myapp.com/auth/teambox'})
41
+ # client.authorize_url # Open this in your browser
42
+ # client.authenticate(:oauth_verifier => '1234') # Code returned from teambox
43
+ #
44
+ #
45
+ class Client
46
+ include HTTParty
47
+ include Teambox::OAuth
48
+
49
+ # Initializes the Teambox client
50
+ def initialize(opts = {})
51
+ opts[:base_uri] ||= 'https://teambox.com/api/1'
52
+ self.class.base_uri(opts[:base_uri])
53
+
54
+ @base_uri = opts[:base_uri]
55
+ @auth = opts[:auth] || {}
56
+ @consumer = consumer if oauth?
57
+
58
+ authenticate(opts[:auth])
59
+ end
60
+
61
+ # Returns true if oauth is being used for authentication
62
+ def oauth?
63
+ !@auth[:oauth_app_id].nil?
64
+ end
65
+
66
+ # Returns the URL required to authenticate access if using OAuth
67
+ def authorize_url(opts={})
68
+ if oauth?
69
+ @consumer.web_server.authorize_url({:redirect_uri => @auth[:redirect_uri]}.merge(opts))
70
+ else
71
+ nil
72
+ end
73
+ end
74
+
75
+ # Authenticates the client with teambox
76
+ def authenticate(opts={})
77
+ @current_user = nil
78
+ if oauth?
79
+ if opts[:oauth_verifier]
80
+ authorize_from_request(opts[:oauth_verifier])
81
+ elsif opts[:oauth_token]
82
+ @auth.merge!({:oauth_token => opts[:oauth_token]})
83
+ authorize_from_access
84
+ end
85
+ else
86
+ if opts[:user]
87
+ @auth.merge!({:user => opts[:user], :password => opts[:password]})
88
+ self.class.basic_auth(@auth[:user], @auth[:password])
89
+ end
90
+ end
91
+
92
+ !current_user.nil?
93
+ end
94
+
95
+ # Is the client is authenticated?
96
+ def authenticated?
97
+ !current_user.nil?
98
+ end
99
+
100
+ # Current user the client is logged in as
101
+ def current_user
102
+ @current_user ||= safe_get('/account')
103
+ end
104
+
105
+ # Performs a GET on path
106
+ def get(path, query={}, options={})
107
+ api_unwrap perform_request(:get, path, {:query => query}.merge(options)), {:url => path, :query => query}
108
+ end
109
+
110
+ # Performs a POST on path
111
+ def post(path, query={}, options={})
112
+ api_unwrap perform_request(:post, path, {:body => query}.merge(options)), {:url => path, :body => query}
113
+ end
114
+
115
+ # Performs a PUT on path
116
+ def put(path, query={}, options={})
117
+ api_unwrap perform_request(:put, path, {:body => query}.merge(options)), {:url => path, :body => query}
118
+ end
119
+
120
+ # Performs a DELETE on path
121
+ def delete(path, query={}, options={})
122
+ api_unwrap perform_request(:delete, path, {:body => query}.merge(options)), {:url => path, :body => query}
123
+ end
124
+
125
+ # Performs a GET on path, catching any exceptions
126
+ def safe_get(path, query={}, options={})
127
+ api_unwrap(perform_request(:get, path, {:query => query}.merge(options)), {:url => path, :query => query}) rescue nil
128
+ end
129
+
130
+ # urls
131
+
132
+ # Gets a list Teambox::Project corresponding to the current users project list
133
+ def projects(query={})
134
+ get('/projects', query)
135
+ end
136
+
137
+ # Gets a Teambox::Project by id or permalink
138
+ def project(id)
139
+ get("/projects/#{id}")
140
+ end
141
+
142
+ protected
143
+
144
+ # Internal request handler
145
+ def perform_request(method, path, options)
146
+ options[:headers] ||= {}
147
+ headers = options[:headers]
148
+
149
+ options[:query] ||= {}
150
+ options[:query][:access_token] = @access_token.token if @access_token
151
+ self.class.send(method, path, options)
152
+ end
153
+
154
+ # Decodes response and returns appropriate API object
155
+ def api_unwrap(response, request={})
156
+ data = JSON.parse(response.body) rescue nil
157
+ if [200, 201, 202].include? response.response.code.to_i
158
+ raise StandardError.new('Please update your Teambox') unless response.has_key?('type')
159
+ if data['type'] == 'List'
160
+ ResultSet.new(self, request, data['objects'], data['references'])
161
+ else
162
+ Teambox.create_model(data['type'], data, ResultSet.new(self, request, [], []))
163
+ end
164
+ else
165
+ error_list = data ? data['errors'] : {'type' => 'UnknownError', 'message' => data}
166
+ error_list['type'] = error_list['type'][0] if error_list['type'].is_a? Array
167
+ error_list['message'] = error_list['message'][0] if error_list['message'].is_a? Array
168
+ raise APIError.new(response.response.code, error_list)
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ # Exception handling for API Errors
175
+ class APIError < StandardError
176
+ attr_reader :error_type # Type of error. See the API Docs for a list of error types
177
+ attr_reader :status_code # HTTP status code returned
178
+ def initialize(status_code, details)
179
+ @error_type = details['type'].to_sym
180
+ @status_code = status_code
181
+ super(details['message'] || details['type'])
182
+ end
183
+ end
184
+
185
+ # Exception handling unknown Teambox::Resource types
186
+ class UnknownResourceError < APIError
187
+ def initialize(type)
188
+ super(200, {'type' => 'UnknownResource', :message => "Unknown Resource #{type}"})
189
+ end
190
+ end
191
+
192
+ def self.create_model(type, data, list=nil) #:nodoc:
193
+ klass = const_get(type.to_sym) rescue nil
194
+ if klass
195
+ klass.new data, list
196
+ else
197
+ throw UnknownResourceError.new(type)
198
+ end
199
+ end
200
+
201
+ # Represents an object located on Teambox.
202
+ #
203
+ # Most resources belonging to a Teambox::Project can be modified, in which case you can use
204
+ # the save, destroy, and reload methods.
205
+ #
206
+ # All attributes are exposed by the method_missing handler.
207
+ class Resource
208
+ include ReferenceList
209
+
210
+ attr_accessor :list, :data
211
+ attr_reader :references
212
+
213
+ def initialize(data, result_list=nil)
214
+ @data = data
215
+ @list = result_list || ResultSet.new(nil, nil, [], [])
216
+ if @data['references']
217
+ generate_references(@data['references'])
218
+ else
219
+ @references = result_list ? result_list.references : {}
220
+ end
221
+ end
222
+
223
+ def id
224
+ @data['id']
225
+ end
226
+
227
+ # The time this object was created
228
+ def created_at
229
+ @data.has_key?('created_at') ? Time.parse(data['created_at']) : nil
230
+ end
231
+
232
+ # The last time this object was updated
233
+ def updated_at
234
+ @data.has_key?('updated_at') ? Time.parse(data['updated_at']) : nil
235
+ end
236
+
237
+ def next #:nodoc:
238
+ nil
239
+ end
240
+
241
+ def prev #:nodoc:
242
+ nil
243
+ end
244
+
245
+ # Location of this object on teambox, used for updating
246
+ def url
247
+ nil
248
+ end
249
+
250
+ # Reloads the resource from source data
251
+ # @returns self
252
+ def reload
253
+ if @list.client && url
254
+ updated = @list.client.get(url) rescue nil
255
+ unless updated.nil?
256
+ @data = updated.data
257
+ end
258
+ end
259
+ self
260
+ end
261
+
262
+ # Saves the resource to teambox
263
+ # @returns true if saved
264
+ def save
265
+ if @list.client && url
266
+ updated = @list.client.put(url, @data) rescue nil
267
+ return true unless updated.nil?
268
+ end
269
+ false
270
+ end
271
+
272
+ # Destroys the resource on teambox
273
+ def destroy
274
+ @list.client.delete(url) if @list.client && url
275
+ true
276
+ end
277
+
278
+ def method_missing(method, *args, &block) #:nodoc:
279
+ @data.include?(method.to_s) ? @data[method.to_s] : super
280
+ end
281
+
282
+ def inspect
283
+ "#<#{self.class} @data=#{@data.inspect} list=#{@list.object_id}>"
284
+ end
285
+ end
286
+ end
287
+
288
+ Dir[File.expand_path('models/*.rb', File.dirname(__FILE__))].each { |f| require f }
@@ -0,0 +1,37 @@
1
+ module Teambox
2
+ # Methods used to authenticate with OAuth on teambox.com. Normally you won't have to call these.
3
+ module OAuth
4
+ attr_accessor :access_token
5
+
6
+ # OAuth consumer required for authentication
7
+ def consumer
8
+ return nil if @auth[:oauth_app_id].nil?
9
+ @consumer ||= OAuth2::Client.new(@auth[:oauth_app_id], @auth[:oauth_app_secret],
10
+ :site => consumer_url,
11
+ :access_token_path => consumer_url+'oauth/token',
12
+ :authorize_path => consumer_url+'oauth/authorize?response_type=code')
13
+ end
14
+
15
+ def consumer_url
16
+ uri = URI.parse(self.class.base_uri)
17
+ uri.path = '/'
18
+ uri.to_s
19
+ end
20
+
21
+ # Is the client authorized via OAuth?
22
+ def authorized?
23
+ !@access_token.nil?
24
+ end
25
+
26
+ def authorize_from_request(verifier)
27
+ @access_token = consumer.web_server.get_access_token(verifier, :redirect_uri => @auth[:redirect_uri], :grant_type => 'authorization_code')
28
+ @auth[:oauth_token] = @access_token.token
29
+ @access_token
30
+ end
31
+
32
+ # Authorizes the client from an existing OAuth token
33
+ def authorize_from_access
34
+ @access_token = ::OAuth2::AccessToken.new(nil, @auth[:oauth_token])
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ require "httparty"
2
+ require "json"
3
+ require "oauth2"
4
+ require "uri"
5
+
6
+
7
+ directory = File.expand_path(File.dirname(__FILE__))
8
+ %w(teambox_oauth reference_list teambox result_set).each { |lib| require File.join(directory, 'teambox-client', lib) }
@@ -0,0 +1,96 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "minmb-teambox-client"
8
+ s.version = "0.4.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Pablo Villalba", "James Urquhart", "Martin H\u{e4}ger"]
12
+ s.date = "2012-08-28"
13
+ s.description = "Provides methods to read and write to Teambox for ruby apps"
14
+ s.email = "martin.hager@minmb.se"
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "History",
22
+ "License",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "examples/conversation.rb",
27
+ "examples/task.rb",
28
+ "examples/users.rb",
29
+ "lib/teambox-client.rb",
30
+ "lib/teambox-client/models/activity.rb",
31
+ "lib/teambox-client/models/comment.rb",
32
+ "lib/teambox-client/models/conversation.rb",
33
+ "lib/teambox-client/models/divider.rb",
34
+ "lib/teambox-client/models/invitation.rb",
35
+ "lib/teambox-client/models/membership.rb",
36
+ "lib/teambox-client/models/note.rb",
37
+ "lib/teambox-client/models/organization.rb",
38
+ "lib/teambox-client/models/page.rb",
39
+ "lib/teambox-client/models/page_slot.rb",
40
+ "lib/teambox-client/models/person.rb",
41
+ "lib/teambox-client/models/project.rb",
42
+ "lib/teambox-client/models/task.rb",
43
+ "lib/teambox-client/models/task_list.rb",
44
+ "lib/teambox-client/models/teambox_data.rb",
45
+ "lib/teambox-client/models/upload.rb",
46
+ "lib/teambox-client/models/user.rb",
47
+ "lib/teambox-client/reference_list.rb",
48
+ "lib/teambox-client/result_set.rb",
49
+ "lib/teambox-client/teambox.rb",
50
+ "lib/teambox-client/teambox_oauth.rb",
51
+ "minmb-teambox-client.gemspec",
52
+ "spec/client_spec.rb",
53
+ "spec/conversation_spec.rb",
54
+ "spec/project_spec.rb",
55
+ "spec/resource_spec.rb",
56
+ "spec/result_set_spec.rb",
57
+ "spec/spec_helper.rb",
58
+ "spec/task_lists_spec.rb",
59
+ "spec/tasks_spec.rb"
60
+ ]
61
+ s.homepage = "http://github.com/minmb/teambox-ruby-client"
62
+ s.require_paths = ["lib"]
63
+ s.rubygems_version = "1.8.24"
64
+ s.summary = "A ruby gem wrapper for Teambox API"
65
+
66
+ if s.respond_to? :specification_version then
67
+ s.specification_version = 3
68
+
69
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
70
+ s.add_runtime_dependency(%q<minmb-teambox-client>, [">= 0"])
71
+ s.add_development_dependency(%q<rake>, [">= 0"])
72
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
73
+ s.add_development_dependency(%q<rspec>, [">= 0"])
74
+ s.add_runtime_dependency(%q<httparty>, ["~> 0.7.4"])
75
+ s.add_runtime_dependency(%q<oauth2>, ["~> 0.1.1"])
76
+ s.add_runtime_dependency(%q<json>, ["~> 1.5.1"])
77
+ else
78
+ s.add_dependency(%q<minmb-teambox-client>, [">= 0"])
79
+ s.add_dependency(%q<rake>, [">= 0"])
80
+ s.add_dependency(%q<jeweler>, [">= 0"])
81
+ s.add_dependency(%q<rspec>, [">= 0"])
82
+ s.add_dependency(%q<httparty>, ["~> 0.7.4"])
83
+ s.add_dependency(%q<oauth2>, ["~> 0.1.1"])
84
+ s.add_dependency(%q<json>, ["~> 1.5.1"])
85
+ end
86
+ else
87
+ s.add_dependency(%q<minmb-teambox-client>, [">= 0"])
88
+ s.add_dependency(%q<rake>, [">= 0"])
89
+ s.add_dependency(%q<jeweler>, [">= 0"])
90
+ s.add_dependency(%q<rspec>, [">= 0"])
91
+ s.add_dependency(%q<httparty>, ["~> 0.7.4"])
92
+ s.add_dependency(%q<oauth2>, ["~> 0.1.1"])
93
+ s.add_dependency(%q<json>, ["~> 1.5.1"])
94
+ end
95
+ end
96
+
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Teambox::Client do
4
+ before do
5
+ @client = make_teambox_client
6
+ end
7
+
8
+ it "should authenticate" do
9
+ @client.authenticated?.should == true
10
+ end
11
+
12
+ it "should return the current user" do
13
+ user = @client.current_user
14
+ user.class.should == Teambox::User
15
+ user.username.should == 'frank'
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Teambox::Conversation do
4
+ before do
5
+ @client = make_teambox_client
6
+ @project = @client.project('earthworks')
7
+ end
8
+
9
+ it "should query conversations" do
10
+ @project.conversations.length.should_not == 0
11
+ end
12
+
13
+ it "should make a conversation" do
14
+ conversation = @project.create_conversation({:name => 'Hello', :body => 'World'})
15
+ conversation.name.should == 'Hello'
16
+ end
17
+
18
+ it "should list recent comments in a conversation" do
19
+ recent_comments = @project.conversations[0].recent_comments
20
+ recent_comments.length.should > 0
21
+ recent_comments.each {|c| c.class.should == Teambox::Comment}
22
+ end
23
+
24
+ it "should list the first comment in a conversation" do
25
+ comment = @project.conversations[0].first_comment
26
+ comment.should_not == nil
27
+ comment.class.should == Teambox::Comment
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Teambox::Project do
4
+ before do
5
+ @client = make_teambox_client
6
+ end
7
+
8
+ it "should query a project" do
9
+ @client.project('earthworks').permalink.should == 'earthworks'
10
+ end
11
+ end