asana 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.
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
1
  *.gem
2
2
  *.rbc
3
+ *.un~
4
+ .DS_Store
3
5
  .bundle
4
6
  .config
5
7
  .yardoc
@@ -11,9 +13,8 @@ doc/
11
13
  lib/bundler/man
12
14
  pkg
13
15
  rdoc
16
+ spec/fixtures/cassettes
14
17
  spec/reports
15
18
  test/tmp
16
19
  test/version_tmp
17
20
  tmp
18
- .DS_Store
19
- *.un~
@@ -0,0 +1,5 @@
1
+ guard 'minitest' do
2
+ watch(%r|^lib/(.*/)?([^/]+)\.rb$|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
3
+ watch(%r|^spec/spec_helper\.rb|) { "spec" }
4
+ watch(%r|^spec/(.*)\/?(.*)_spec\.rb|)
5
+ end
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Asana
2
2
 
3
- TODO: Write a gem description
3
+ This gem is a simple Ruby wrapper for the Asana REST API. It uses
4
+ [ActiveResource][] to provide a simple, familiar interface for accessing
5
+ your Asana account.
6
+
7
+ To learn more, check out the [Asana API Documentation][].
4
8
 
5
9
  ## Installation
6
10
 
@@ -18,7 +22,140 @@ Or install it yourself as:
18
22
 
19
23
  ## Usage
20
24
 
21
- TODO: Write usage instructions here
25
+ In order to access Asana, you need to provide your [API key][].
26
+
27
+
28
+ ```ruby
29
+ Asana.configure do |client|
30
+ client.api_key = 'your_asana_api_key'
31
+ end
32
+ ```
33
+
34
+ As a sanity check, you can fetch the object representing your user.
35
+
36
+ ```ruby
37
+ Asana::User.me
38
+ ```
39
+
40
+ ### [Users][]
41
+
42
+ > A user object represents an account in Asana that can be given access to
43
+ > various workspaces, projects, and tasks.
44
+ >
45
+ > Like other objects in the system, users are referred to by numerical IDs.
46
+ > However, the special string identifier me can be used anywhere a user ID is
47
+ > accepted, to refer to the current authenticated user.
48
+
49
+ **Note:** It is not possible to create, update, or delete a user from
50
+ the API.
51
+
52
+ ```ruby
53
+ # Get users from all of your workspaces
54
+ users = Asana::User.all
55
+
56
+ # Get a specific user
57
+ user = Asana::User.find(:id)
58
+
59
+ # Get the user associated with the API key being used
60
+ user = Asana::User.me
61
+
62
+ # Get all users in a given workspace
63
+ workspace = Asana::Workspace.find(:workspace_id)
64
+ users = workspace.users
65
+ ```
66
+
67
+ ### [Workspaces][]
68
+
69
+ > A workspace is the most basic organizational unit in Asana. All projects
70
+ > and tasks have an associated workspace.
71
+
72
+ **Note:** It is not possible to create or delete a workspace from the API.
73
+
74
+ ```ruby
75
+ # Get all workspaces
76
+ workspaces = Asana::Workspace.all
77
+
78
+ # Get a specific workspace
79
+ workspace = Asana::Workspace.find(:id)
80
+
81
+ # Get all projects in a given workspace
82
+ projects = workspace.projects
83
+
84
+ # Get all tasks in a given workspace and assigned to the given user
85
+ tasks = workspace.tasks(:user_id)
86
+
87
+ # Get all users with access to a given workspace
88
+ users = workspace.users
89
+
90
+ # Create a new task in a given workspace and assign it to the current user
91
+ workspace.create_task(task_settings)
92
+ ```
93
+
94
+ ### [Projects][]
95
+
96
+ > A project represents a prioritized list of tasks in Asana. It exists in a
97
+ > single workspace and is accessible to a subset of users in that workspace
98
+ > depending on its permissions.
99
+
100
+ **Note:** It is not possible to create a project from the API.
101
+
102
+ ```ruby
103
+ # Get all projects
104
+ projects = Asana::Project.all
105
+
106
+ # Get a specific project
107
+ project = Asana::Project.find(:id)
108
+
109
+ # Get all projects in a given workspace
110
+ workspace = Asana::Workspace.find(:workspace_id)
111
+ projects = workspace.projects
112
+ ```
113
+
114
+ ### [Tasks][]
115
+
116
+ > The task is the basic object around which many operations in Asana are
117
+ > centered. In the Asana application, multiple tasks populate the middle
118
+ > pane according to some view parameters, and the set of selected tasks
119
+ > determine the more detailed information presented in the details pane.
120
+
121
+ ```ruby
122
+ # Get all tasks in a given project
123
+ project = Asana::Project(:project_id)
124
+ tasks = project.tasks
125
+
126
+ # Get all tasks in a given workspace
127
+ workspace = Asana::Workspace(:workspace_id)
128
+ tasks = workspace.tasks
129
+
130
+ # Get all stories for a given task
131
+ task = tasks.first
132
+ stories = task.stories
133
+
134
+ # Create a new task in a given workspace and assign it to the current user
135
+ workspace.create_task(task_settings)
136
+
137
+ # Create a new story for the given task
138
+ task.create_story(story_settings)
139
+ ```
140
+
141
+ ### [Stories][]
142
+
143
+ > A story represents an activity associated with an object in the Asana
144
+ > system. Stories are generated by the system whenever users take actions
145
+ > such as creating or assigning tasks, or moving tasks between projects.
146
+ > Comments are also a form of user-generated story.
147
+
148
+ **Note:** It is not possible to update a story from the API.
149
+
150
+ ```ruby
151
+ # Get all stories for a given task
152
+ project = Asana::Project(:project_id)
153
+ task = project.tasks.first
154
+ stories = task.stories
155
+
156
+ # Create a new story for the given task
157
+ task.create_story(story_settings)
158
+ ```
22
159
 
23
160
  ## Contributing
24
161
 
@@ -27,3 +164,12 @@ TODO: Write usage instructions here
27
164
  3. Commit your changes (`git commit -am 'Added some feature'`)
28
165
  4. Push to the branch (`git push origin my-new-feature`)
29
166
  5. Create new Pull Request
167
+
168
+ [API key]: http://app.asana.com/-/account_api
169
+ [ActiveResource]: http://api.rubyonrails.org/classes/ActiveResource/Base.html
170
+ [Asana API Documentation]: http://developer.asana.com/documentation/
171
+ [Users]: http://developer.asana.com/documentation/#users
172
+ [Workspaces]: http://developer.asana.com/documentation/#workspaces
173
+ [Projects]: http://developer.asana.com/documentation/#projects
174
+ [Tasks]: http://developer.asana.com/documentation/#tasks
175
+ [Stories]: http://developer.asana.com/documentation/#stories
@@ -10,6 +10,12 @@ Gem::Specification.new do |gem|
10
10
 
11
11
  gem.add_dependency 'activeresource', '~> 3.2.3'
12
12
 
13
+ gem.add_development_dependency 'growl', '~> 1.0.3'
14
+ gem.add_development_dependency 'guard-minitest', '~> 0.5.0'
15
+ gem.add_development_dependency 'minitest', '~> 2.12.1'
16
+ gem.add_development_dependency 'vcr', '~> 2.1.0'
17
+ gem.add_development_dependency 'webmock', '~> 1.8.6'
18
+
13
19
  gem.files = `git ls-files`.split($\)
14
20
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
21
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
@@ -5,6 +5,15 @@ module Asana
5
5
  def check_prefix_options(options)
6
6
  end
7
7
 
8
+ def custom_method_collection_url(method_name, options = {})
9
+ prefix_options, query_options = split_options(options)
10
+ if method_name
11
+ "#{prefix(prefix_options)}#{collection_name}/#{method_name}.#{format.extension}#{query_string(query_options)}"
12
+ else
13
+ "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}"
14
+ end
15
+ end
16
+
8
17
  def parent_resources(*resources)
9
18
  @parent_resources = resources
10
19
  end
@@ -6,5 +6,9 @@ module Asana
6
6
  parent_resources :workspace
7
7
  all(*args)
8
8
  end
9
+
10
+ def tasks
11
+ Task.all_by_project(:params => { :project_id => self.id })
12
+ end
9
13
  end
10
14
  end
@@ -13,5 +13,11 @@ module Asana
13
13
  def stories
14
14
  Story.all_by_task(:params => { :task_id => self.id })
15
15
  end
16
+
17
+ def create_story(*args)
18
+ story = Story.new
19
+ query_options = { :task => self.id }
20
+ Task.post("#{self.id}/stories", query_options.merge(args.first), story.to_json)
21
+ end
16
22
  end
17
23
  end
@@ -3,13 +3,13 @@ module Asana
3
3
  alias :save :method_not_allowed
4
4
  alias :destroy :method_not_allowed
5
5
 
6
- def self.me
7
- get(:me)
8
- end
9
-
10
6
  def self.all_by_workspace(*args)
11
7
  parent_resources :workspace
12
8
  all(*args)
13
9
  end
10
+
11
+ def self.me
12
+ User.new(get(:me))
13
+ end
14
14
  end
15
15
  end
@@ -7,8 +7,15 @@ module Asana
7
7
  Project.all_by_workspace(:params => { :workspace_id => self.id })
8
8
  end
9
9
 
10
- def tasks
11
- Task.all_by_workspace(:params => { :workspace_id => self.id })
10
+ def tasks(assignee)
11
+ query_options = { :workspace => self.id, :assignee => assignee }
12
+ Task.all_by_workspace(:params => query_options)
13
+ end
14
+
15
+ def create_task(*args)
16
+ task = Task.new
17
+ query_options = { :workspace => self.id, :assignee => 'me' }
18
+ Task.post(nil, query_options.merge(args.first), task.to_json)
12
19
  end
13
20
 
14
21
  def users
@@ -1,3 +1,3 @@
1
1
  module Asana
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ module Asana
4
+ describe Project do
5
+
6
+ before do
7
+ VCR.insert_cassette('projects', :record => :new_episodes)
8
+ Asana.configure do |c|
9
+ c.api_key = ENV['ASANA_API_KEY']
10
+ end
11
+ end
12
+
13
+ after do
14
+ VCR.eject_cassette
15
+ end
16
+
17
+ describe '.all' do
18
+ it 'should return all of the user\'s projects' do
19
+ projects = Project.all
20
+ projects.must_be_instance_of Array
21
+ projects.first.must_be_instance_of Project
22
+ end
23
+ end
24
+
25
+ describe '.all_by_workspace' do
26
+ it 'should return all projects for the given workspace' do
27
+ workspace = Workspace.all.first
28
+ projects = workspace.projects
29
+ projects.must_be_instance_of Array
30
+ projects.first.must_be_instance_of Project
31
+ end
32
+ end
33
+
34
+ describe '.create' do
35
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
36
+ project = Project.new
37
+ lambda { project.save }.must_raise ActiveResource::MethodNotAllowed
38
+ end
39
+ end
40
+
41
+ describe '#tasks' do
42
+ it 'should return all tasks for the given project' do
43
+ projects = Project.all.first
44
+ tasks = projects.tasks
45
+ tasks.must_be_instance_of Array
46
+ tasks.first.must_be_instance_of Task
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ module Asana
4
+ describe Story do
5
+
6
+ before do
7
+ VCR.insert_cassette('stories', :record => :new_episodes)
8
+ Asana.configure do |c|
9
+ c.api_key = ENV['ASANA_API_KEY']
10
+ end
11
+ end
12
+
13
+ after do
14
+ VCR.eject_cassette
15
+ end
16
+
17
+ describe '#create_story' do
18
+ it 'should create a new story for the given task' do
19
+ task = Project.all.first.tasks.first
20
+ story = task.create_story(:text => 'foo')
21
+ story.must_be_instance_of Net::HTTPCreated
22
+ end
23
+ end
24
+
25
+ describe '#update' do
26
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
27
+ story = Project.all.first.tasks.first.stories.first
28
+ lambda { story.save }.must_raise ActiveResource::MethodNotAllowed
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module Asana
4
+ describe Task do
5
+
6
+ before do
7
+ VCR.insert_cassette('tasks', :record => :new_episodes)
8
+ Asana.configure do |c|
9
+ c.api_key = ENV['ASANA_API_KEY']
10
+ end
11
+ end
12
+
13
+ after do
14
+ VCR.eject_cassette
15
+ end
16
+
17
+ describe '#stories' do
18
+ it 'should return all stories for the given task' do
19
+ task = Project.all.first.tasks.first
20
+ stories = task.stories
21
+ stories.must_be_instance_of Array
22
+ stories.first.must_be_instance_of Story
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ module Asana
4
+ describe User do
5
+
6
+ before do
7
+ VCR.insert_cassette('users', :record => :new_episodes)
8
+ Asana.configure do |c|
9
+ c.api_key = ENV['ASANA_API_KEY']
10
+ end
11
+ end
12
+
13
+ after do
14
+ VCR.eject_cassette
15
+ end
16
+
17
+ describe '.all' do
18
+ it 'should return all users for all of the user\'s workspaces' do
19
+ users = User.all
20
+ users.must_be_instance_of Array
21
+ users.first.must_be_instance_of User
22
+ end
23
+ end
24
+
25
+ describe '.all_by_workspace' do
26
+ it 'should return all users for the given workspace' do
27
+ user = User.me
28
+ workspace = user.workspaces.first
29
+ users = workspace.users
30
+ users.must_be_instance_of Array
31
+ users.first.must_be_instance_of User
32
+ end
33
+ end
34
+
35
+ describe '.find' do
36
+ it 'should return the user with the given ID' do
37
+ user = User.me
38
+ user = User.find(user.id)
39
+ user.wont_be_nil
40
+ user.must_be_instance_of User
41
+ end
42
+ end
43
+
44
+ describe '.me' do
45
+ it 'should return the user associated with the given API key' do
46
+ user = User.me
47
+ user.wont_be_nil
48
+ user.must_be_instance_of User
49
+ end
50
+ end
51
+
52
+ describe '#save' do
53
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
54
+ user = User.me
55
+ lambda { user.save }.must_raise ActiveResource::MethodNotAllowed
56
+ end
57
+ end
58
+
59
+ describe '#update' do
60
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
61
+ user = User.me
62
+ lambda { user.update_attribute(:name, 'foo') }.must_raise ActiveResource::MethodNotAllowed
63
+ end
64
+ end
65
+
66
+ describe '#destroy' do
67
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
68
+ user = User.me
69
+ lambda { user.destroy }.must_raise ActiveResource::MethodNotAllowed
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ module Asana
4
+ describe Workspace do
5
+
6
+ before do
7
+ VCR.insert_cassette('workspaces', :record => :new_episodes)
8
+ Asana.configure do |c|
9
+ c.api_key = ENV['ASANA_API_KEY']
10
+ end
11
+ end
12
+
13
+ after do
14
+ VCR.eject_cassette
15
+ end
16
+
17
+ describe '.all' do
18
+ it 'should return all of the user\'s workspaces' do
19
+ workspaces = Workspace.all
20
+ workspaces.must_be_instance_of Array
21
+ workspaces.first.must_be_instance_of Workspace
22
+ end
23
+ end
24
+
25
+ describe '#create_task' do
26
+ it 'should create a new task for the given workspace' do
27
+ workspace = Workspace.all.first
28
+ task = workspace.create_task(:name => 'foo')
29
+ task.must_be_instance_of Net::HTTPCreated
30
+ end
31
+ end
32
+
33
+ describe '#projects' do
34
+ it 'should return all projects for the given workspace' do
35
+ workspace = Workspace.all.first
36
+ projects = workspace.projects
37
+ projects.must_be_instance_of Array
38
+ projects.first.must_be_instance_of Project
39
+ end
40
+ end
41
+
42
+ describe '#tasks' do
43
+ it 'should return all tasks for the given workspace' do
44
+ workspace = Workspace.all.first
45
+ user = User.all.first
46
+ tasks = workspace.tasks(user.id)
47
+ tasks.must_be_instance_of Array
48
+ tasks.first.must_be_instance_of Task
49
+ end
50
+ end
51
+
52
+ describe '#users' do
53
+ it 'should return all users for the given workspace' do
54
+ workspace = Workspace.all.first
55
+ users = workspace.users
56
+ users.must_be_instance_of Array
57
+ users.first.must_be_instance_of User
58
+ end
59
+ end
60
+
61
+ describe '#create' do
62
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
63
+ workspace = Workspace.new
64
+ lambda { workspace.save }.must_raise ActiveResource::MethodNotAllowed
65
+ end
66
+ end
67
+
68
+ describe '#destroy' do
69
+ it 'should raise an ActiveResource::MethodNotAllowed exception' do
70
+ workspace = Workspace.all.first
71
+ lambda { workspace.destroy }.must_raise ActiveResource::MethodNotAllowed
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,9 @@
1
+ require 'minitest/autorun'
2
+ require 'vcr'
3
+ require 'asana'
4
+
5
+ VCR.configure do |c|
6
+ c.cassette_library_dir = 'spec/fixtures/cassettes'
7
+ c.hook_into :webmock
8
+ c.filter_sensitive_data('<API_KEY>') { ENV['ASANA_API_KEY'] }
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asana
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-19 00:00:00.000000000 Z
12
+ date: 2012-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activeresource
@@ -27,6 +27,86 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 3.2.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: growl
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.3
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.3
46
+ - !ruby/object:Gem::Dependency
47
+ name: guard-minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.5.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.12.1
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.12.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: vcr
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 2.1.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 2.1.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: webmock
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 1.8.6
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 1.8.6
30
110
  description: Ruby wrapper for the Asana REST API
31
111
  email:
32
112
  - ryan@rbright.net
@@ -36,6 +116,7 @@ extra_rdoc_files: []
36
116
  files:
37
117
  - .gitignore
38
118
  - Gemfile
119
+ - Guardfile
39
120
  - LICENSE
40
121
  - README.md
41
122
  - Rakefile
@@ -49,6 +130,12 @@ files:
49
130
  - lib/asana/resources/user.rb
50
131
  - lib/asana/resources/workspace.rb
51
132
  - lib/asana/version.rb
133
+ - spec/asana/resources/project_spec.rb
134
+ - spec/asana/resources/story_spec.rb
135
+ - spec/asana/resources/task_spec.rb
136
+ - spec/asana/resources/user_spec.rb
137
+ - spec/asana/resources/workspace_spec.rb
138
+ - spec/spec_helper.rb
52
139
  homepage: http://github.com/rbright/asana
53
140
  licenses: []
54
141
  post_install_message:
@@ -73,5 +160,11 @@ rubygems_version: 1.8.21
73
160
  signing_key:
74
161
  specification_version: 3
75
162
  summary: Ruby wrapper for the Asana REST API
76
- test_files: []
163
+ test_files:
164
+ - spec/asana/resources/project_spec.rb
165
+ - spec/asana/resources/story_spec.rb
166
+ - spec/asana/resources/task_spec.rb
167
+ - spec/asana/resources/user_spec.rb
168
+ - spec/asana/resources/workspace_spec.rb
169
+ - spec/spec_helper.rb
77
170
  has_rdoc: