bcx 0.0.1 → 0.0.2

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 (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