vermonster 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +43 -0
- data/README.markdown +105 -0
- data/Rakefile +15 -0
- data/lib/vermonster/authentication.rb +49 -0
- data/lib/vermonster/lists.rb +51 -0
- data/lib/vermonster/tasks.rb +58 -0
- data/lib/vermonster/users.rb +27 -0
- data/lib/vermonster/version.rb +3 -0
- data/lib/vermonster.rb +40 -0
- data/spec/fixtures/cassettes/authentication.yml +104 -0
- data/spec/fixtures/cassettes/lists.yml +391 -0
- data/spec/fixtures/cassettes/tasks.yml +826 -0
- data/spec/fixtures/cassettes/users.yml +117 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/vermonster/authentication_spec.rb +54 -0
- data/spec/vermonster/lists_spec.rb +107 -0
- data/spec/vermonster/tasks_spec.rb +119 -0
- data/spec/vermonster/users_spec.rb +59 -0
- data/vermonster.gemspec +29 -0
- metadata +152 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
vermonster (0.1.1)
|
5
|
+
faraday (~> 0.8.0)
|
6
|
+
faraday_middleware (~> 0.8.8)
|
7
|
+
hashie (~> 1.2.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
addressable (2.2.8)
|
13
|
+
crack (0.3.1)
|
14
|
+
diff-lcs (1.1.3)
|
15
|
+
faraday (0.8.1)
|
16
|
+
multipart-post (~> 1.1)
|
17
|
+
faraday_middleware (0.8.8)
|
18
|
+
faraday (>= 0.7.4, < 0.9)
|
19
|
+
hashie (1.2.0)
|
20
|
+
multipart-post (1.1.5)
|
21
|
+
rake (0.9.2.2)
|
22
|
+
rspec (2.11.0)
|
23
|
+
rspec-core (~> 2.11.0)
|
24
|
+
rspec-expectations (~> 2.11.0)
|
25
|
+
rspec-mocks (~> 2.11.0)
|
26
|
+
rspec-core (2.11.0)
|
27
|
+
rspec-expectations (2.11.1)
|
28
|
+
diff-lcs (~> 1.1.3)
|
29
|
+
rspec-mocks (2.11.1)
|
30
|
+
vcr (2.2.3)
|
31
|
+
webmock (1.8.7)
|
32
|
+
addressable (>= 2.2.7)
|
33
|
+
crack (>= 0.1.7)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
ruby
|
37
|
+
|
38
|
+
DEPENDENCIES
|
39
|
+
rake
|
40
|
+
rspec
|
41
|
+
vcr
|
42
|
+
vermonster!
|
43
|
+
webmock
|
data/README.markdown
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Vermonster
|
2
|
+
|
3
|
+
Vermonster is a way to consume the [Cheddar API](https://cheddarapp.com/developer).
|
4
|
+
|
5
|
+
**Want Python instead? Check out [vermonster-py](https://github.com/jpennell/vermonster-py).**
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
cheddar = Vermonster::Client.new(:id => "client-id", :secret => "client-secret")
|
11
|
+
```
|
12
|
+
|
13
|
+
|
14
|
+
### Authentication
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# Get the URL for the user to authorize the application (all parameters optional).
|
18
|
+
url = cheddar.authorize_url(:callback => "http://github.com", :state => "Foobar")
|
19
|
+
|
20
|
+
# Do whatever to send the user to that URL...
|
21
|
+
# It redirects back to whatever you set as the callback URL.
|
22
|
+
|
23
|
+
# In your controller (or wherever Cheddar sent the user back to),
|
24
|
+
# request the token with the code Cheddar sent back.
|
25
|
+
cheddar.token!(code)
|
26
|
+
|
27
|
+
# Or, if you're just using your own user with your own
|
28
|
+
# user token...
|
29
|
+
cheddar.use_token!("your-user-token")
|
30
|
+
|
31
|
+
# You're now authorized!
|
32
|
+
cheddar.authorized?
|
33
|
+
```
|
34
|
+
|
35
|
+
|
36
|
+
### Lists
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# Get all of your lists.
|
40
|
+
lists = cheddar.lists.all
|
41
|
+
|
42
|
+
# Get a list "Foobar" with the ID of 42.
|
43
|
+
foobar = cheddar.lists.find(42)
|
44
|
+
|
45
|
+
# Get the tasks in that list.
|
46
|
+
tasks = foobar.tasks
|
47
|
+
|
48
|
+
# Update that list.
|
49
|
+
foobar.update(:title => "Foosbar")
|
50
|
+
|
51
|
+
# Create a new list called "Foobaz".
|
52
|
+
foobaz = cheddar.lists.create(:title => "Foobaz")
|
53
|
+
|
54
|
+
# Reorder your lists.
|
55
|
+
cheddar.lists.reorder([42, 12, 35])
|
56
|
+
```
|
57
|
+
|
58
|
+
|
59
|
+
### Tasks
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
# Get all the tasks in a list.
|
63
|
+
tasks = cheddar.lists.find(42).tasks
|
64
|
+
|
65
|
+
# Find a single task.
|
66
|
+
task = cheddar.tasks.find(4242)
|
67
|
+
|
68
|
+
# Update that task.
|
69
|
+
task.update(:text => "Foo to the bar.")
|
70
|
+
|
71
|
+
# Create a task in list 42.
|
72
|
+
awesome = cheddar.tasks.create(42, :text => "Be awesome!")
|
73
|
+
|
74
|
+
# Reorder task in list 42.
|
75
|
+
cheddar.tasks.reorder(42, [54, 23, 42])
|
76
|
+
|
77
|
+
# Archive completed items in list 42.
|
78
|
+
cheddar.tasks.archive(42)
|
79
|
+
|
80
|
+
# Archive all items in list 42.
|
81
|
+
cheddar.tasks.archive!(42)
|
82
|
+
|
83
|
+
# Move to another list.
|
84
|
+
awesome.move(32)
|
85
|
+
```
|
86
|
+
|
87
|
+
|
88
|
+
### User
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
# Get information about the authorized user.
|
92
|
+
cheddar.me
|
93
|
+
```
|
94
|
+
|
95
|
+
|
96
|
+
## Contributing
|
97
|
+
|
98
|
+
Vermonster is under active development, and we would really appreciate you helping us out! Here's how.
|
99
|
+
|
100
|
+
1. Fork this repository.
|
101
|
+
2. Take a look [at the issues](https://github.com/eturk/vermonster/issues). What needs to be done?
|
102
|
+
3. Make a topic branch for what you want to do. Bonus points for referencing an issue (like `2-authentication`).
|
103
|
+
4. Make your changes.
|
104
|
+
5. Create a Pull Request.
|
105
|
+
6. Profit!
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
|
+
t.rspec_opts = %w(-fs --color)
|
6
|
+
end
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
namespace :vcr do
|
11
|
+
desc "Delete all of the saves cassettes"
|
12
|
+
task :clear do
|
13
|
+
exec("rm -rf spec/fixtures/cassettes/*")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Vermonster
|
2
|
+
module Authentication
|
3
|
+
# Returns the URL for authorizing the user.
|
4
|
+
def authorize_url(options={})
|
5
|
+
url = "https://api.cheddarapp.com/oauth/authorize?client_id=#{@client[:id]}"
|
6
|
+
|
7
|
+
options.each do |key, value|
|
8
|
+
url = url << "&#{key}=#{value}"
|
9
|
+
end
|
10
|
+
|
11
|
+
url
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get the token for the user.
|
15
|
+
def token!(code)
|
16
|
+
Vermonster::Client.connection.basic_auth(@client[:id], @client[:secret])
|
17
|
+
|
18
|
+
response = Vermonster::Client.connection.post "/oauth/token", { :grant_type => "authorization_code", :code => code }
|
19
|
+
|
20
|
+
if response.body["access_token"]
|
21
|
+
@client = @client.merge(:token => response.body["access_token"])
|
22
|
+
|
23
|
+
self.connect!(@client[:token])
|
24
|
+
|
25
|
+
authorized?
|
26
|
+
else
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Skip the code and just use the developer's user access token.
|
32
|
+
def use_token!(token)
|
33
|
+
@client = @client.merge(:token => token)
|
34
|
+
|
35
|
+
self.connect!(@client[:token])
|
36
|
+
|
37
|
+
authorized?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Check if authorized or not.
|
41
|
+
def authorized?
|
42
|
+
if Vermonster::Client.connection.get("me").status == 200
|
43
|
+
true
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Vermonster
|
2
|
+
module Lists
|
3
|
+
def lists
|
4
|
+
self.class::List
|
5
|
+
end
|
6
|
+
|
7
|
+
class List < Hash
|
8
|
+
def initialize(options = {})
|
9
|
+
self.merge!(options)
|
10
|
+
|
11
|
+
options.each do |(attr, val)|
|
12
|
+
instance_variable_set("@#{attr}", val)
|
13
|
+
instance_eval "def #{attr}() @#{attr} end"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Note this overrides Hash#update. Use Hash#merge! instead.
|
18
|
+
def update(options = {})
|
19
|
+
self.merge!(Vermonster::Client.connection.put("lists/#{self["id"]}", "{\"list\": #{options.to_json}}").body)
|
20
|
+
end
|
21
|
+
|
22
|
+
def tasks
|
23
|
+
Vermonster::Tasks::Task.from_list(self["id"])
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def all
|
28
|
+
lists_raw = Vermonster::Client.connection.get("lists").body
|
29
|
+
lists = []
|
30
|
+
lists_raw.each do |list|
|
31
|
+
lists.push(List.new(list))
|
32
|
+
end
|
33
|
+
|
34
|
+
lists
|
35
|
+
end
|
36
|
+
|
37
|
+
def find(id)
|
38
|
+
List.new(Vermonster::Client.connection.get("lists/#{id}").body)
|
39
|
+
end
|
40
|
+
|
41
|
+
def create(options = {})
|
42
|
+
List.new(Vermonster::Client.connection.post("lists", "{\"list\": #{options.to_json}}").body)
|
43
|
+
end
|
44
|
+
|
45
|
+
def reorder(lists)
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Vermonster
|
2
|
+
module Tasks
|
3
|
+
def tasks
|
4
|
+
self.class::Task
|
5
|
+
end
|
6
|
+
|
7
|
+
class Task < Hash
|
8
|
+
def initialize(options = {})
|
9
|
+
self.merge!(options)
|
10
|
+
|
11
|
+
options.each do |(attr, val)|
|
12
|
+
instance_variable_set("@#{attr}", val)
|
13
|
+
instance_eval "def #{attr}() @#{attr} end"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Note this overrides Hash#update. Use Hash#merge! instead.
|
18
|
+
def update(options = {})
|
19
|
+
self.merge!(Vermonster::Client.connection.put("tasks/#{self["id"]}", "{\"task\": #{options.to_json}}").body)
|
20
|
+
end
|
21
|
+
|
22
|
+
def move(list)
|
23
|
+
self.replace(Vermonster::Client.connection.put("tasks/#{self["id"]}/move", "{\"task\": { \"list_id\": #{list} } }").body)
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def from_list(id)
|
28
|
+
tasks_raw = Vermonster::Client.connection.get("lists/#{id}/tasks").body
|
29
|
+
tasks = []
|
30
|
+
tasks_raw.each do |task|
|
31
|
+
tasks.push(Task.new(task))
|
32
|
+
end
|
33
|
+
|
34
|
+
tasks
|
35
|
+
end
|
36
|
+
|
37
|
+
def find(id)
|
38
|
+
Task.new(Vermonster::Client.connection.get("tasks/#{id}").body)
|
39
|
+
end
|
40
|
+
|
41
|
+
def create(list, options = {})
|
42
|
+
Task.new(Vermonster::Client.connection.post("lists/#{list}/tasks", "{\"task\": #{options.to_json}}").body)
|
43
|
+
end
|
44
|
+
|
45
|
+
def reorder(list, options = {})
|
46
|
+
end
|
47
|
+
|
48
|
+
def archive(list)
|
49
|
+
Vermonster::Client.connection.post("lists/#{list}/tasks/archive_completed")
|
50
|
+
end
|
51
|
+
|
52
|
+
def archive!(list)
|
53
|
+
Vermonster::Client.connection.post("lists/#{list}/tasks/archive_all")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Vermonster
|
2
|
+
module Users
|
3
|
+
def me
|
4
|
+
self.users.me
|
5
|
+
end
|
6
|
+
|
7
|
+
def users
|
8
|
+
self.class::User
|
9
|
+
end
|
10
|
+
|
11
|
+
class User < Hash
|
12
|
+
def initialize(options = {})
|
13
|
+
self.merge!(options)
|
14
|
+
|
15
|
+
options.each do |(attr, val)|
|
16
|
+
instance_variable_set("@#{attr}", val)
|
17
|
+
instance_eval "def #{attr}() @#{attr} end"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.me
|
22
|
+
User.new(Vermonster::Client.connection.get("me").body)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
data/lib/vermonster.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
require 'vermonster/authentication'
|
6
|
+
require 'vermonster/lists'
|
7
|
+
require 'vermonster/tasks'
|
8
|
+
require 'vermonster/users'
|
9
|
+
|
10
|
+
module Vermonster
|
11
|
+
class Client
|
12
|
+
attr_accessor :client
|
13
|
+
|
14
|
+
def initialize(options={})
|
15
|
+
@client = options
|
16
|
+
|
17
|
+
self.connect!
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect!(token = nil)
|
21
|
+
@@connection = Faraday.new(:url => "https://api.cheddarapp.com/v1") do |f|
|
22
|
+
f.headers["Authorization"] = "Bearer #{token}" if !token.nil?
|
23
|
+
f.request :json
|
24
|
+
f.response :json, :content_type => /\bjson$/
|
25
|
+
f.adapter Faraday.default_adapter
|
26
|
+
end
|
27
|
+
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.connection
|
32
|
+
@@connection
|
33
|
+
end
|
34
|
+
|
35
|
+
include Authentication
|
36
|
+
include Lists
|
37
|
+
include Tasks
|
38
|
+
include Users
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.cheddarapp.com/v1/me
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- Bearer 6e8c9e570805e75d683a963b1290116a
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- ! '*/*'
|
16
|
+
User-Agent:
|
17
|
+
- Ruby
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Access-Control-Allow-Headers:
|
24
|
+
- ! '*,X-Pusher-Socket-ID,Content-Type,Authorization'
|
25
|
+
Access-Control-Allow-Methods:
|
26
|
+
- GET, POST, PUT, OPTIONS
|
27
|
+
Access-Control-Allow-Origin:
|
28
|
+
- ! '*'
|
29
|
+
Access-Control-Max-Age:
|
30
|
+
- '86400'
|
31
|
+
Access-Control-Request-Method:
|
32
|
+
- ! '*'
|
33
|
+
Cache-Control:
|
34
|
+
- must-revalidate, private, max-age=0
|
35
|
+
Content-Type:
|
36
|
+
- application/json; charset=utf-8
|
37
|
+
Date:
|
38
|
+
- Sun, 29 Jul 2012 23:38:27 GMT
|
39
|
+
Etag:
|
40
|
+
- ! '"ef42e623e164e34871846180e276f9de"'
|
41
|
+
Server:
|
42
|
+
- thin 1.4.1 codename Chromeo
|
43
|
+
X-Rack-Cache:
|
44
|
+
- miss
|
45
|
+
X-Request-Id:
|
46
|
+
- 6ef32226d03bdf001084760c54c846d7
|
47
|
+
X-Runtime:
|
48
|
+
- '0.030929'
|
49
|
+
X-Ua-Compatible:
|
50
|
+
- IE=Edge,chrome=1
|
51
|
+
Content-Length:
|
52
|
+
- '354'
|
53
|
+
Connection:
|
54
|
+
- keep-alive
|
55
|
+
body:
|
56
|
+
encoding: US-ASCII
|
57
|
+
string: ! '{"created_at":"2012-07-18T19:33:13Z","first_name":null,"has_plus":false,"id":13055,"last_name":null,"updated_at":"2012-07-18T19:33:13Z","username":"vermonster","url":"https://api.cheddarapp.com/v1/users/13055","socket":{"auth_url":"https://api.cheddarapp.com/pusher/auth","api_key":"675f10a650f18b4eb0a8","app_id":"15197","channel":"private-user-13055"}}'
|
58
|
+
http_version:
|
59
|
+
recorded_at: Sun, 29 Jul 2012 23:38:27 GMT
|
60
|
+
- request:
|
61
|
+
method: get
|
62
|
+
uri: https://api.cheddarapp.com/v1/me
|
63
|
+
body:
|
64
|
+
encoding: US-ASCII
|
65
|
+
string: ''
|
66
|
+
headers:
|
67
|
+
Accept-Encoding:
|
68
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
69
|
+
Accept:
|
70
|
+
- ! '*/*'
|
71
|
+
User-Agent:
|
72
|
+
- Ruby
|
73
|
+
response:
|
74
|
+
status:
|
75
|
+
code: 401
|
76
|
+
message: Unauthorized
|
77
|
+
headers:
|
78
|
+
Cache-Control:
|
79
|
+
- no-cache
|
80
|
+
Content-Type:
|
81
|
+
- application/json; charset=utf-8
|
82
|
+
Date:
|
83
|
+
- Sun, 29 Jul 2012 23:38:27 GMT
|
84
|
+
Server:
|
85
|
+
- thin 1.4.1 codename Chromeo
|
86
|
+
X-Rack-Cache:
|
87
|
+
- miss
|
88
|
+
X-Request-Id:
|
89
|
+
- 09075fb8096e51115c5273212bd24679
|
90
|
+
X-Runtime:
|
91
|
+
- '0.004310'
|
92
|
+
X-Ua-Compatible:
|
93
|
+
- IE=Edge,chrome=1
|
94
|
+
Content-Length:
|
95
|
+
- '85'
|
96
|
+
Connection:
|
97
|
+
- keep-alive
|
98
|
+
body:
|
99
|
+
encoding: US-ASCII
|
100
|
+
string: ! '{"error":"not_authorized","error_description":"This method requires
|
101
|
+
authentication."}'
|
102
|
+
http_version:
|
103
|
+
recorded_at: Sun, 29 Jul 2012 23:38:28 GMT
|
104
|
+
recorded_with: VCR 2.2.3
|