bcx 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +1 -1
  3. data/README.md +64 -15
  4. data/Rakefile +5 -1
  5. data/bcx.gemspec +5 -0
  6. data/lib/bcx.rb +7 -2
  7. data/lib/bcx/client.rb +11 -4
  8. data/lib/bcx/configuration.rb +9 -0
  9. data/lib/bcx/resources/person.rb +13 -0
  10. data/lib/bcx/resources/project.rb +40 -2
  11. data/lib/bcx/resources/todo.rb +37 -0
  12. data/lib/bcx/resources/todolist.rb +40 -1
  13. data/lib/bcx/response_error.rb +17 -0
  14. data/lib/bcx/version.rb +1 -1
  15. data/spec/bcx/client_spec.rb +40 -0
  16. data/spec/bcx/project_spec.rb +65 -0
  17. data/spec/bcx/todolist_spec.rb +75 -0
  18. data/spec/cassettes/Bcx_Resources_Project/DELETE_/projects/2937644/should_delete_a_project.yml +105 -0
  19. data/spec/cassettes/Bcx_Resources_Project/GET_/projects/2937644/should_have_the_correct_id.yml +60 -0
  20. data/spec/cassettes/Bcx_Resources_Project/GET_/projects/2937644/should_return_a_hash.yml +60 -0
  21. data/spec/cassettes/Bcx_Resources_Project/GET_/projects/archived/should_be_an_array.yml +58 -0
  22. data/spec/cassettes/Bcx_Resources_Project/GET_/projects/archived/should_be_empty.yml +58 -0
  23. data/spec/cassettes/Bcx_Resources_Project/GET_/projects/first_project_should_have_the_correct_id.yml +59 -0
  24. data/spec/cassettes/Bcx_Resources_Project/GET_/projects/should_be_an_array.yml +59 -0
  25. data/spec/cassettes/Bcx_Resources_Project/POST_/projects/should_create_a_new_project.yml +63 -0
  26. data/spec/cassettes/Bcx_Resources_Project/PUT_/projects/2937644/should_update_an_existing_project.yml +58 -0
  27. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/1/todolists/completed_json/first_todolist_should_have_the_correct_id.yml +59 -0
  28. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/1/todolists/completed_json/should_be_an_array.yml +59 -0
  29. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/123/todolists/456_json/should_have_the_correct_id.yml +67 -0
  30. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/123/todolists/456_json/should_return_a_hash.yml +67 -0
  31. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/2937644/todolists_json/first_todolist_should_have_the_correct_id.yml +114 -0
  32. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/2937644/todolists_json/should_be_an_array.yml +114 -0
  33. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/2956584/todolists/completed_json/first_todolist_should_have_the_correct_id.yml +59 -0
  34. data/spec/cassettes/Bcx_Resources_Todolist/GET_/projects/2956584/todolists/completed_json/should_be_an_array.yml +59 -0
  35. data/spec/cassettes/Bcx_Resources_Todolist/GET_/todolists/completed_json/first_todolist_should_have_the_correct_id.yml +60 -0
  36. data/spec/cassettes/Bcx_Resources_Todolist/GET_/todolists/completed_json/should_be_an_array.yml +60 -0
  37. data/spec/cassettes/Bcx_Resources_Todolist/GET_/todolists_json/first_todolist_should_have_the_correct_id.yml +60 -0
  38. data/spec/cassettes/Bcx_Resources_Todolist/GET_/todolists_json/should_be_an_array.yml +60 -0
  39. data/spec/cassettes/Bcx_Resources_Todolist/projects/123/todolists_json/should_create_a_new_todolist.yml +62 -0
  40. data/spec/spec_helper.rb +21 -0
  41. metadata +103 -8
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in bcx.gemspec
4
4
  gemspec
5
5
 
6
- gem 'rapidash', path: '/Users/paul/Sites/rapidash'
6
+ gem 'rapidash', github: 'paulspringett/rapidash', branch: 'error-handling'
data/README.md CHANGED
@@ -1,29 +1,78 @@
1
- # Bcx
1
+ ## Bcx
2
2
 
3
- TODO: Write a gem description
3
+ > NB. This is still alpha software and may not work as expected. It's also missing a lot of the Basecamp endpoints. Please feel free to contribute!
4
4
 
5
- ## Installation
5
+ Fully-fledged Ruby API wrapper for Basecamp Next
6
6
 
7
- Add this line to your application's Gemfile:
7
+ ```
8
+ ___________________ ____ ___
9
+ \______ \_ ___ \\ \/ /
10
+ | | _/ \ \/ \ /
11
+ | | \ \____/ \
12
+ |______ /\______ /___/\ \
13
+ \/ \/ \_/
14
+ ```
8
15
 
9
- gem 'bcx'
16
+ ### Installation
10
17
 
11
- And then execute:
18
+ ```shell
19
+ $ gem install bcx
20
+ ```
12
21
 
13
- $ bundle
22
+ Or if you are using Bundler
14
23
 
15
- Or install it yourself as:
24
+ ```ruby
25
+ gem 'bcx'
26
+ ```
16
27
 
17
- $ gem install bcx
28
+ ### Usage
18
29
 
19
- ## Usage
30
+ You can connect to the Basecamp API using the Bcx client. The client provides authentication over HTTP or OAuth.
20
31
 
21
- TODO: Write usage instructions here
32
+ #### HTTP Basic Auth
22
33
 
23
- ## Contributing
34
+ ```ruby
35
+ client = Bcx::Client.new(:http, login: 'username', password: 'secret')
36
+ ```
37
+
38
+ #### OAuth
39
+
40
+ ```ruby
41
+ client = Bcx::Client.new(:oauth, client_id: '1234567890', client_secret: '831994c4170', access_token: 'b02ff9345c3')
42
+ ```
43
+
44
+ You can get a `client_id` and `client_secret` from https://integrate.37signals.com/
45
+
46
+ ### Resources
47
+
48
+ See the [full resource documentation](#todo) for all available API endpoints.
49
+
50
+ #### Bang operators
51
+
52
+ It's important to understand the use of bang methods when using Bcx. Each resource can be called with or without a `!`.
53
+
54
+ **Without the bang** you can chain and build endpoint calls:
55
+
56
+ ```ruby
57
+ client.projects(123).todolists
58
+ # => #<Bcx::Resources::Todolist ...>
59
+
60
+ client.projects(123).todolists.url
61
+ # => "projects/123/todolists"
62
+ ```
63
+
64
+ **With the bang** you can hit the API endpoint over the network and fetch data:
65
+
66
+ ```ruby
67
+ client.projects(123).todolists!
68
+ # => [#<Hashie::Mash id=456 ...>, #<Hashie::Mash id=789 ...>]
69
+ ```
70
+
71
+ ### Contributing
24
72
 
25
73
  1. Fork it
26
74
  2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Added some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
75
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
76
+ 4. Write your tests and check everything passes
77
+ 5. Push to the branch (`git push origin my-new-feature`)
78
+ 6. Create new Pull Request (into the development branch)
data/Rakefile CHANGED
@@ -1,2 +1,6 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task default: [:spec]
data/bcx.gemspec CHANGED
@@ -16,4 +16,9 @@ Gem::Specification.new do |gem|
16
16
  gem.version = Bcx::VERSION
17
17
 
18
18
  gem.add_runtime_dependency 'rapidash', '~> 0.2.0'
19
+
20
+ gem.add_development_dependency 'rake'
21
+ gem.add_development_dependency 'rspec'
22
+ gem.add_development_dependency 'simplecov'
23
+ gem.add_development_dependency 'vcr'
19
24
  end
data/lib/bcx.rb CHANGED
@@ -3,13 +3,15 @@ require 'bcx/version'
3
3
 
4
4
  module Bcx
5
5
  autoload :Configuration, 'bcx/configuration'
6
- autoload :Client, 'bcx/client'
7
6
 
8
7
  module Resources
9
- autoload :Project, 'bcx/resources/project'
8
+ autoload :Todo, 'bcx/resources/todo'
10
9
  autoload :Todolist, 'bcx/resources/todolist'
10
+ autoload :Project, 'bcx/resources/project'
11
11
  end
12
12
 
13
+ autoload :Client, 'bcx/client'
14
+
13
15
  class << self
14
16
  attr_accessor :configuration
15
17
  end
@@ -19,3 +21,6 @@ module Bcx
19
21
  yield(configuration)
20
22
  end
21
23
  end
24
+
25
+ require 'bcx/response_error'
26
+ Rapidash.response_exception_class = Bcx::ResponseError
data/lib/bcx/client.rb CHANGED
@@ -1,15 +1,22 @@
1
1
  module Bcx
2
2
  class Client < Rapidash::Client
3
- @account = Bcx.configuration.account
4
- @api_version = Bcx.configuration.api_version
5
-
6
- site "https://basecamp.com/#{@account}/api/#{@api_version}/"
7
3
  extension :json
8
4
 
5
+ raise_errors
6
+
9
7
  resource :projects, class_name: 'Bcx::Resources::Project'
8
+ resource :todolists, class_name: 'Bcx::Resources::Todolist'
10
9
 
11
10
  def initialize(auth_method, options = {})
11
+ @account = Bcx.configuration.account
12
+ @api_version = Bcx.configuration.api_version
13
+
14
+ self.class.site("https://basecamp.com/#{@account}/api/#{@api_version}/")
12
15
  self.class.method(auth_method)
16
+
17
+ options[:uid] ||= options[:client_id]
18
+ options[:secret] ||= options[:client_secret]
19
+
13
20
  super(options)
14
21
  end
15
22
 
@@ -1,4 +1,13 @@
1
1
  module Bcx
2
+
3
+ # Bcx::Configuration
4
+ # Provides a configuration block for setting up the Bcx client
5
+ # Example:
6
+ #
7
+ # Bcx.configure do |config|
8
+ # config.account = '1234567890'
9
+ # end
10
+ #
2
11
  class Configuration
3
12
  attr_accessor :account, :api_version
4
13
 
@@ -0,0 +1,13 @@
1
+ module Bcx
2
+ module Resources
3
+
4
+ # Get todolists with assigned todos for a person
5
+ # GET /people/1/assigned_todos.json
6
+ #
7
+ # client.people(1).assigned_todos
8
+ #
9
+ class Person < Rapidash::Base
10
+
11
+ end
12
+ end
13
+ end
@@ -1,9 +1,47 @@
1
1
  module Bcx
2
2
  module Resources
3
+
4
+ # Bcx::Resources::Project
5
+ # Provides access to projects resoource and other nested resources
6
+ #
7
+ # Fetch all projects
8
+ # GET /projects.json
9
+ #
10
+ # client.projects!
11
+ #
12
+ # Fetch archived projects
13
+ # GET /projects/archived.json
14
+ #
15
+ # clients.projects.archived!
16
+ #
17
+ # Fetch single project with ID of 123
18
+ # GET /projects/123.json
19
+ #
20
+ # client.projects!(123)
21
+ #
22
+ # Create a project
23
+ # POST /projects.json
24
+ #
25
+ # client.projects.create!(name: 'Acme project', description: 'This is a new project')
26
+ #
27
+ # Update an existing project
28
+ # PUT /projects/123.json
29
+ #
30
+ # client.projects(123).update!(description: 'A new description')
31
+ #
32
+ # Delete a project
33
+ # DELETE /projects/123.json
34
+ #
35
+ # client.projects(123).delete!
36
+ #
3
37
  class Project < Rapidash::Base
4
- root :project
38
+ resource :todolists
39
+ resource :todos
5
40
 
6
- resource :todolists, class_name: 'Bcx::Resources::Todolist'
41
+ def archived!
42
+ @url += '/archived'
43
+ call!
44
+ end
7
45
  end
8
46
  end
9
47
  end
@@ -0,0 +1,37 @@
1
+ module Bcx
2
+ module Resources
3
+
4
+ # Bcx::Resources::Todo
5
+ # Provides access to todolist resoource both at the client level and per-project
6
+ #
7
+ # Get todos for a todolist
8
+ # GET /todolists/1.json
9
+ #
10
+ # todolist = client.todolists!(1)
11
+ # todolist.todos.remaining
12
+ # todolist.todos.completed
13
+ #
14
+ # Get a specific todo
15
+ # GET /projects/1/todos/2.json
16
+ #
17
+ # client.projects(1).todos!(2)
18
+ #
19
+ # Create a todo
20
+ # POST /projects/1/todolists/2/todos.json
21
+ #
22
+ # client.projects(1).todolists(2).todos.create!(content: 'Update copy text')
23
+ #
24
+ # Update a todo
25
+ # PUT /projects/1/todos/2.json
26
+ #
27
+ # client.projects(1).todos(2).update!(completed: true)
28
+ #
29
+ # Delete a todo
30
+ # DELETE /projects/1/todos/2.json
31
+ #
32
+ # client.projects(1).todos(2).delete!
33
+ #
34
+ class Todo < Rapidash::Base
35
+ end
36
+ end
37
+ end
@@ -1,7 +1,46 @@
1
1
  module Bcx
2
2
  module Resources
3
+
4
+ # Bcx::Resources::Todolist
5
+ # Provides access to todolist resoource both at the client level and per-project
6
+ #
7
+ # Get all todolists for a project
8
+ # GET /projects/123/todolists.json
9
+ #
10
+ # client.projects(123).todolists!
11
+ #
12
+ # Get all completed todolists for a project
13
+ # GET /projects/1/todolists/completed.json
14
+ #
15
+ # client.projects(123).todolists.completed!
16
+ #
17
+ # Get todolists for all projects
18
+ # GET /todolists.json
19
+ #
20
+ # client.todolists!
21
+ #
22
+ # Get completed todolists for all projects
23
+ # GET /todolists/completed.json
24
+ #
25
+ # client.todolists.completed!
26
+ #
27
+ # Get specific todolist including the todos
28
+ # GET /projects/123/todolists/456.json
29
+ #
30
+ # client.projects(123).todolists!(456)
31
+ #
32
+ # Create a new todolist
33
+ # POST /projects/1/todolists.json
34
+ #
35
+ # client.projects(123).todolists.create!(name: 'My todolist', description: 'This is a todolist')
36
+ #
3
37
  class Todolist < Rapidash::Base
4
- root :todolist
38
+ resource :todos, class_name: 'Bcx::Resources::Todo'
39
+
40
+ def completed!
41
+ @url += '/completed'
42
+ call!
43
+ end
5
44
  end
6
45
  end
7
46
  end
@@ -0,0 +1,17 @@
1
+ module Bcx
2
+ class ResponseError < Rapidash::ResponseError
3
+
4
+ def errors
5
+ return body if body.kind_of?(String)
6
+
7
+ messages = []
8
+
9
+ body.each_pair do |attribute, msgs|
10
+ msgs.each { |msg| messages.push "#{attribute} #{msg}" }
11
+ end
12
+
13
+ messages.join(', ')
14
+ end
15
+
16
+ end
17
+ end
data/lib/bcx/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bcx
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bcx::Client do
4
+
5
+ let(:client) { Bcx::Client.new(:http, login: 'bcx-test-user', password: 'secret') }
6
+
7
+ describe "http auth" do
8
+ it "should assign login" do
9
+ expect(client.login).to eq 'bcx-test-user'
10
+ end
11
+
12
+ it "should assign password" do
13
+ expect(client.password).to eq 'secret'
14
+ end
15
+
16
+ it "should build a Faraday connection" do
17
+ expect(client.connection).not_to be_nil
18
+ end
19
+ end
20
+
21
+ # TODO: test handling to reponse errors, with error codes
22
+ # it "should fail for invalid attributes" do
23
+ # expect { client.projects.create!(name: '') }.to raise_error { |error|
24
+ # expect(error).to be_a Bcx::ResponseError
25
+ # expect(error.status).to eq 422
26
+ # }
27
+ # end
28
+
29
+ # Rescue a response error example
30
+ # begin
31
+ # project = client.projects.create!(name: 'foo')
32
+ # rescue Bcx::ResponseError => response
33
+ # puts response.status
34
+ # => 422
35
+ # puts response.body
36
+ # => "Name cannot be blank"
37
+ # end
38
+
39
+
40
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bcx::Resources::Project, :vcr do
4
+ let(:client) { Bcx::Client.new(:http, login: 'bcx-test-user', password: 'secret') }
5
+
6
+ describe "GET /projects" do
7
+ let(:projects) { client.projects! }
8
+
9
+ it "should be an array" do
10
+ expect(projects).to be_an Array
11
+ end
12
+
13
+ it "first project should have the correct id" do
14
+ expect(projects.first.id).to eq 2937644
15
+ end
16
+ end
17
+
18
+ describe "GET /projects/archived" do
19
+ let(:projects) { client.projects.archived! }
20
+
21
+ it "should be an array" do
22
+ expect(projects).to be_an Array
23
+ end
24
+
25
+ it "should be empty" do
26
+ expect(projects).to be_empty
27
+ end
28
+ end
29
+
30
+ describe "GET /projects/2937644" do
31
+ let(:project) { client.projects!(2937644) }
32
+
33
+ it "should return a hash" do
34
+ expect(project).to be_a Hashie::Mash
35
+ end
36
+
37
+ it "should have the correct id" do
38
+ expect(project.id).to eq 2937644
39
+ end
40
+ end
41
+
42
+ describe "POST /projects" do
43
+ it "should create a new project" do
44
+ project = client.projects.create!(name: 'New project', description: 'A new project created over the API')
45
+ expect(project.created_at).not_to be_blank
46
+ end
47
+ end
48
+
49
+ describe "PUT /projects/2937644" do
50
+ it "should update an existing project" do
51
+ project = client.projects(2937644).update!(description: 'New description')
52
+ expect(project.description).to eq 'New description'
53
+ end
54
+ end
55
+
56
+ describe "DELETE /projects/2937644" do
57
+ it "should delete a project" do
58
+ client.projects(2937644).delete!
59
+ expect { client.projects!(2937644) }.to raise_error { |error|
60
+ expect(error).to be_a Bcx::ResponseError
61
+ expect(error.status).to eq 404
62
+ }
63
+ end
64
+ end
65
+ end