vermonster 0.1.1
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 +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
|