datacatalog 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/CHANGES.md +2 -0
- data/LICENSE.md +11 -0
- data/README.md +31 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/datacatalog.gemspec +68 -0
- data/doc/api_key_spec_for_rest_api.txt +54 -0
- data/doc/api_key_spec_for_ruby_api.rb +26 -0
- data/doc/mocking_options.md +20 -0
- data/lib/datacatalog.rb +28 -0
- data/lib/datacatalog/api_key.rb +7 -0
- data/lib/datacatalog/base.rb +68 -0
- data/lib/datacatalog/source.rb +30 -0
- data/lib/datacatalog/user.rb +94 -0
- data/sandbox_api.yml.example +2 -0
- data/spec/api_key_spec.rb +1 -0
- data/spec/base_spec.rb +184 -0
- data/spec/source_spec.rb +101 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/user_spec.rb +208 -0
- metadata +91 -0
data/.gitignore
ADDED
data/CHANGES.md
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Copyright (c) 2009, Sunlight Foundation.
|
2
|
+
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
8
|
+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
9
|
+
* Neither the name of Sunlight Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
10
|
+
|
11
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Ruby Gem for the National Data Catalog API
|
2
|
+
|
3
|
+
Under heavy development.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
For now, the gem will not be packaged. Instead, install it manually:
|
8
|
+
|
9
|
+
$ git clone git clone git://github.com/sunlightlabs/ruby-datacatalog.git
|
10
|
+
$ cd ruby-datacatalog
|
11
|
+
$ gem build datacatalog.gemspec
|
12
|
+
$ gem install datacatalog-0.1.0.gem
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
require 'rubygems'
|
17
|
+
require 'datacatalog'
|
18
|
+
|
19
|
+
DataCatalog.api_key = 'c40505247a5e308a24d70a0118f76534b543795b'
|
20
|
+
|
21
|
+
## Running Specs
|
22
|
+
|
23
|
+
We're not mocking out any of the web API calls in the specs. Instead, we expect developers who wish to run the specs to download and run a local sandbox instance of the [Data Catalog API](http://github.com/sunlightlabs/datacatalog-api), a Sinatra app:
|
24
|
+
|
25
|
+
git clone git://github.com/sunlightlabs/datacatalog-api.git
|
26
|
+
|
27
|
+
Get the app running like any normal Sinatra app, so you can choose to use thin or Passenger or new hotness like [Unicorn](http://unicorn.bogomips.org/). Some special considerations:
|
28
|
+
|
29
|
+
1. We recommend creating a `sandbox` entry in `datacatalog-api`'s `config.yml`.
|
30
|
+
2. Run `RACK_ENV=sandbox rake db:ensure_admin` in the `datacatalog-api` project to create a super admin for the API instance.
|
31
|
+
3. Back here in `ruby-datacatalog`, use the example file in `spec/` to create your own `spec/sandbox_api.yml` with the API key of the admin and your local URI.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "datacatalog"
|
8
|
+
gem.summary = %Q{Wrapper for the National Data Catalog API}
|
9
|
+
gem.description = %Q{Ruby library that wraps the National Data Catalog API}
|
10
|
+
gem.email = "luigi@sunlightfoundation.com"
|
11
|
+
gem.homepage = "http://github.com/sunlightlabs/datacatalog"
|
12
|
+
gem.authors = ["Luigi Montanez", "David James"]
|
13
|
+
gem.add_development_dependency "rspec"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
if File.exist?('VERSION')
|
40
|
+
version = File.read('VERSION')
|
41
|
+
else
|
42
|
+
version = ""
|
43
|
+
end
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "datacatalog #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/datacatalog.gemspec
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{datacatalog}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Luigi Montanez", "David James"]
|
12
|
+
s.date = %q{2009-10-05}
|
13
|
+
s.description = %q{Ruby library that wraps the National Data Catalog API}
|
14
|
+
s.email = %q{luigi@sunlightfoundation.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.md",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"CHANGES.md",
|
22
|
+
"LICENSE.md",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"datacatalog.gemspec",
|
27
|
+
"doc/api_key_spec_for_rest_api.txt",
|
28
|
+
"doc/api_key_spec_for_ruby_api.rb",
|
29
|
+
"doc/mocking_options.md",
|
30
|
+
"lib/datacatalog.rb",
|
31
|
+
"lib/datacatalog/api_key.rb",
|
32
|
+
"lib/datacatalog/base.rb",
|
33
|
+
"lib/datacatalog/source.rb",
|
34
|
+
"lib/datacatalog/user.rb",
|
35
|
+
"sandbox_api.yml.example",
|
36
|
+
"spec/api_key_spec.rb",
|
37
|
+
"spec/base_spec.rb",
|
38
|
+
"spec/source_spec.rb",
|
39
|
+
"spec/spec.opts",
|
40
|
+
"spec/spec_helper.rb",
|
41
|
+
"spec/user_spec.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/sunlightlabs/datacatalog}
|
44
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
45
|
+
s.require_paths = ["lib"]
|
46
|
+
s.rubygems_version = %q{1.3.5}
|
47
|
+
s.summary = %q{Wrapper for the National Data Catalog API}
|
48
|
+
s.test_files = [
|
49
|
+
"spec/api_key_spec.rb",
|
50
|
+
"spec/base_spec.rb",
|
51
|
+
"spec/source_spec.rb",
|
52
|
+
"spec/spec_helper.rb",
|
53
|
+
"spec/user_spec.rb"
|
54
|
+
]
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
58
|
+
s.specification_version = 3
|
59
|
+
|
60
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
61
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
64
|
+
end
|
65
|
+
else
|
66
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
A user has a built-in, primary API key.
|
2
|
+
A user also has secondary API keys.
|
3
|
+
|
4
|
+
API keys fall into these categories:
|
5
|
+
1. "primary" API key
|
6
|
+
- created and controlled by system
|
7
|
+
- cannot be deleted by users
|
8
|
+
- used by the Data Catalog Web Application
|
9
|
+
- can be rekeyed by user
|
10
|
+
2. application keys
|
11
|
+
- created and controlled by users
|
12
|
+
- can be rekeyed by user
|
13
|
+
- do not provide user-specific credentials:
|
14
|
+
- favorites
|
15
|
+
- comments
|
16
|
+
3. valet keys
|
17
|
+
- created and controlled by users
|
18
|
+
- can be rekeyed by user
|
19
|
+
- provide user-specific credentials
|
20
|
+
- favorites
|
21
|
+
- comments
|
22
|
+
|
23
|
+
GET /users/1/api_keys
|
24
|
+
# get all API keys
|
25
|
+
:type => :primary
|
26
|
+
:type => :application
|
27
|
+
:type => :valet
|
28
|
+
|
29
|
+
GET /users/1/api_keys?type=primary
|
30
|
+
# just returns the primary key
|
31
|
+
|
32
|
+
GET /users/1/api_keys?type=application
|
33
|
+
# returns an array of application keys. [] if none.
|
34
|
+
|
35
|
+
GET /users/1/api_keys?type=valet
|
36
|
+
# returns an array of the valet keys. [] if none.
|
37
|
+
|
38
|
+
POST /users/1/api_keys
|
39
|
+
# create a new API key
|
40
|
+
|
41
|
+
PUT /users/1/api_keys/12345
|
42
|
+
# update an existing API key
|
43
|
+
|
44
|
+
PUT /users/1/api_keys/12345?regenerate_api_key=true
|
45
|
+
# rekey an API key
|
46
|
+
|
47
|
+
DELETE /users/1/api_keys/12345
|
48
|
+
# delete an existing API key
|
49
|
+
# return 403 Forbidden if attempting to delete a primary key
|
50
|
+
|
51
|
+
# -----
|
52
|
+
|
53
|
+
POST /users
|
54
|
+
A a primary key API should be generated automatically.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# I want to get a user's primary API key
|
2
|
+
user = DataCatalog::User.find(user_id)
|
3
|
+
user.primary_api_key
|
4
|
+
user.application_api_keys
|
5
|
+
user.valet_api_keys
|
6
|
+
|
7
|
+
# I want to generate a new API key for a user
|
8
|
+
user.generate_api_key!(:type => "application", :purpose => "To be awesome.") # sets user to the updated object
|
9
|
+
|
10
|
+
# I want to update an API key
|
11
|
+
user.update_api_key!("173f938237a93e9393b365c3",
|
12
|
+
:type => "application",
|
13
|
+
:purpose => "To be more awesome.") # sets user to the updated object
|
14
|
+
|
15
|
+
# I want to delete an API key of a user
|
16
|
+
user.delete_api_key!("173f938237a93e9393b365c3") # returns: true / exception
|
17
|
+
|
18
|
+
# I want to get all API keys of a single user
|
19
|
+
user.api_keys # returns: array of keys
|
20
|
+
|
21
|
+
# ^^^^^^^^^^^^ DONE ^^^^^^^^^^^^^^^
|
22
|
+
|
23
|
+
# vvvvvvvvvv NOT DONE vvvvvvvvvvvvv
|
24
|
+
|
25
|
+
# Given an API key, I want to see what user it corresponds to, if any.
|
26
|
+
DataCatalog::User.find_by_api_key("7a93e93b365ca93e9393b365c3") # returns: User object
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Ruby wrapper API mocking options
|
2
|
+
|
3
|
+
## 1. Machinist
|
4
|
+
|
5
|
+
* Use Machinist as an object factory for HTTParty::Response and DataCatalog::* objects.
|
6
|
+
* Big question: Can HTTParty::Response object methods be appropriately mocked out by Machinist?
|
7
|
+
* Will need to keep objects in sync with the live API
|
8
|
+
|
9
|
+
## 2. FakeWeb
|
10
|
+
|
11
|
+
* Use FakeWeb to fake out the HTTP responses
|
12
|
+
* Will need to know the details of the JSON bodies, but HTTParty wraps all that for us.
|
13
|
+
* Will need to keep the JSON output (and headers + status codes) in sync with the live API
|
14
|
+
|
15
|
+
## 3. Local Sandbox API
|
16
|
+
|
17
|
+
* Use a locally running sandbox API that mocks out the real API
|
18
|
+
* Each spec will need to build up needed objects in the API, then tear them down at the end.
|
19
|
+
* Much slower than in-memory solutions above.
|
20
|
+
* To keep in sync with live API, just need to refresh API codebase.
|
data/lib/datacatalog.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require 'httparty'
|
4
|
+
require 'mash'
|
5
|
+
|
6
|
+
module DataCatalog
|
7
|
+
mattr_accessor :api_key, :base_uri
|
8
|
+
class Error < RuntimeError; end
|
9
|
+
class BadRequest < Error; end # 400
|
10
|
+
class Unauthorized < Error; end # 401
|
11
|
+
class Forbidden < Error; end # 403
|
12
|
+
class NotFound < Error; end # 404
|
13
|
+
class Conflict < Error; end # 409
|
14
|
+
class InternalServerError < Error; end # 500
|
15
|
+
class ApiKeyNotConfigured < Error; end
|
16
|
+
class CannotDeletePrimaryApiKey < Error; end
|
17
|
+
|
18
|
+
def self.with_key(temp_key)
|
19
|
+
original_key = DataCatalog.api_key
|
20
|
+
DataCatalog.api_key = temp_key
|
21
|
+
yield
|
22
|
+
DataCatalog.api_key = original_key
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
require "#{File.dirname(__FILE__)}/datacatalog/base.rb"
|
28
|
+
Dir["#{File.dirname(__FILE__)}/datacatalog/*.rb"].each { |source_file| require source_file }
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Base < Mash
|
4
|
+
|
5
|
+
include HTTParty
|
6
|
+
format :json
|
7
|
+
|
8
|
+
def self.set_base_uri
|
9
|
+
default_options[:base_uri] = HTTParty.normalize_base_uri(DataCatalog.base_uri || 'api.nationaldatacatalog.com')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.set_api_key
|
13
|
+
if DataCatalog.api_key.blank?
|
14
|
+
raise ApiKeyNotConfigured, "Use DataCatalog.api_key = '...'"
|
15
|
+
end
|
16
|
+
default_options[:default_params] = {} if default_options[:default_params].nil?
|
17
|
+
default_options[:default_params].merge!({ :api_key => DataCatalog.api_key })
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.set_up!
|
21
|
+
set_base_uri
|
22
|
+
set_api_key
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.check_status_code(response)
|
26
|
+
case response.code
|
27
|
+
when 400: raise BadRequest, error_message(response)
|
28
|
+
when 401: raise Unauthorized, error_message(response)
|
29
|
+
when 403: raise Forbidden, error_message(response)
|
30
|
+
when 404: raise NotFound, error_message(response)
|
31
|
+
when 409: raise Conflict, error_message(response)
|
32
|
+
when 500: raise InternalServerError, error_message(response)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.error_message(response)
|
37
|
+
parsed_body = JSON.parse(response.body)
|
38
|
+
if parsed_body.empty?
|
39
|
+
"Response was empty"
|
40
|
+
elsif parsed_body["errors"]
|
41
|
+
parsed_body["errors"].inspect
|
42
|
+
else
|
43
|
+
response.body
|
44
|
+
end
|
45
|
+
rescue JSON::ParserError
|
46
|
+
"Unable to parse: #{response.body.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.response_for
|
50
|
+
response = yield
|
51
|
+
check_status_code(response)
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.build_object(response)
|
56
|
+
return nil if response.nil? || response.empty?
|
57
|
+
new(response)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.about
|
61
|
+
default_options[:default_params] = {}
|
62
|
+
set_base_uri
|
63
|
+
build_object(response_for { get('/') })
|
64
|
+
end
|
65
|
+
|
66
|
+
end # class Base
|
67
|
+
|
68
|
+
end # module DataCatalog
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Source < DataCatalog::Base
|
4
|
+
|
5
|
+
def self.create(params={})
|
6
|
+
set_up!
|
7
|
+
build_object(response_for { post("/sources", :query => params) })
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.all
|
11
|
+
set_up!
|
12
|
+
response_for{ get("/sources") }.map do |source|
|
13
|
+
build_object(source)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.update(source_id, params={})
|
18
|
+
set_up!
|
19
|
+
build_object(response_for { put("/sources/#{source_id}", :query => params) })
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.destroy(source_id)
|
23
|
+
set_up!
|
24
|
+
response = response_for { delete("/sources/#{source_id}") }
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class User < DataCatalog::Base
|
4
|
+
|
5
|
+
def self.all
|
6
|
+
set_up!
|
7
|
+
response_for{ get("/users") }.map do |user|
|
8
|
+
build_object(user)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.find(id)
|
13
|
+
set_up!
|
14
|
+
user = build_object(response_for { get("/users/#{id}") })
|
15
|
+
user.api_keys = response_for { get("/users/#{id}/keys") }.map do |key|
|
16
|
+
DataCatalog::ApiKey.build_object(key)
|
17
|
+
end if user
|
18
|
+
user
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find_by_api_key(api_key)
|
22
|
+
user = nil
|
23
|
+
DataCatalog.with_key(api_key) do
|
24
|
+
set_up!
|
25
|
+
checkup = build_object(response_for { get("/checkup") })
|
26
|
+
user = find(checkup.user_id)
|
27
|
+
end
|
28
|
+
user
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.create(params={})
|
32
|
+
set_up!
|
33
|
+
user = build_object(response_for { post("/users", :query => params) })
|
34
|
+
user.api_keys = response_for { get("/users/#{user.id}/keys") }.map do |key|
|
35
|
+
DataCatalog::ApiKey.build_object(key)
|
36
|
+
end if user
|
37
|
+
user
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.update(user_id, params)
|
41
|
+
set_up!
|
42
|
+
build_object(response_for { put("/users/#{user_id}", :query => params) })
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.destroy(user_id)
|
46
|
+
set_up!
|
47
|
+
response = response_for { delete("/users/#{user_id}") }
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_api_key!(params)
|
52
|
+
self.class.set_up!
|
53
|
+
|
54
|
+
response = self.class.response_for do
|
55
|
+
self.class.post("/users/#{self.id}/keys", :query => params )
|
56
|
+
end
|
57
|
+
update_api_keys
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_api_key!(api_key_id)
|
62
|
+
self.class.set_up!
|
63
|
+
|
64
|
+
response = self.class.response_for do
|
65
|
+
self.class.delete("/users/#{self.id}/keys/#{api_key_id}")
|
66
|
+
end
|
67
|
+
update_api_keys
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
def update_api_key!(api_key_id, params)
|
72
|
+
self.class.set_up!
|
73
|
+
|
74
|
+
response = self.class.response_for do
|
75
|
+
self.class.put("/users/#{self.id}/keys/#{api_key_id}", :query => params)
|
76
|
+
end
|
77
|
+
update_api_keys
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def update_api_keys
|
84
|
+
self.api_keys = self.class.response_for { self.class.get("/users/#{self.id}/keys") }.map do |key|
|
85
|
+
DataCatalog::ApiKey.build_object(key)
|
86
|
+
end
|
87
|
+
updated_user = DataCatalog::User.find(self.id)
|
88
|
+
self.application_api_keys = updated_user.application_api_keys
|
89
|
+
self.valet_api_keys = updated_user.valet_api_keys
|
90
|
+
end
|
91
|
+
|
92
|
+
end # class User
|
93
|
+
|
94
|
+
end # module DataCatalog
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe DataCatalog do
|
4
|
+
|
5
|
+
describe "module accessors" do
|
6
|
+
|
7
|
+
it "should access the API Key" do
|
8
|
+
DataCatalog.api_key = 'flurfeneugen'
|
9
|
+
DataCatalog.api_key.should == 'flurfeneugen'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should access the base URI" do
|
13
|
+
DataCatalog.base_uri = 'somehost.com'
|
14
|
+
DataCatalog.base_uri.should == 'somehost.com'
|
15
|
+
end
|
16
|
+
|
17
|
+
end # describe "accessors"
|
18
|
+
|
19
|
+
describe ".with_key" do
|
20
|
+
|
21
|
+
it "should set the API key within the block" do
|
22
|
+
DataCatalog.api_key = 'flurfeneugen'
|
23
|
+
temp_value = 'not_temp_key'
|
24
|
+
|
25
|
+
DataCatalog.with_key('temp_key') do
|
26
|
+
temp_value = DataCatalog.api_key
|
27
|
+
end
|
28
|
+
|
29
|
+
temp_value.should == 'temp_key'
|
30
|
+
DataCatalog.api_key.should == 'flurfeneugen'
|
31
|
+
end
|
32
|
+
|
33
|
+
end # describe ".with_key"
|
34
|
+
|
35
|
+
end # describe DataCatalog
|
36
|
+
|
37
|
+
describe DataCatalog::Base do
|
38
|
+
|
39
|
+
before(:each) { setup_api }
|
40
|
+
|
41
|
+
describe ".set_base_uri" do
|
42
|
+
|
43
|
+
it "should set and normalize the base URI" do
|
44
|
+
DataCatalog.base_uri = 'notherhost.com'
|
45
|
+
DataCatalog::Base.set_base_uri
|
46
|
+
DataCatalog::Base.default_options[:base_uri].should == 'http://notherhost.com'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should set the base URI to the default if it's not explicitly defined" do
|
50
|
+
DataCatalog.base_uri = nil
|
51
|
+
DataCatalog::Base.set_base_uri
|
52
|
+
DataCatalog::Base.default_options[:base_uri].should == 'http://api.nationaldatacatalog.com'
|
53
|
+
end
|
54
|
+
|
55
|
+
end # describe ".set_base_uri"
|
56
|
+
|
57
|
+
describe ".set_api_key" do
|
58
|
+
|
59
|
+
it "should set the API key" do
|
60
|
+
DataCatalog.api_key = 'flurfeneugen'
|
61
|
+
DataCatalog::Base.set_api_key
|
62
|
+
DataCatalog::Base.default_options[:default_params].should include(:api_key => 'flurfeneugen')
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should raise exception when attempting to set the API key but none is set" do
|
66
|
+
DataCatalog.api_key = nil
|
67
|
+
executing do
|
68
|
+
DataCatalog::Base.set_api_key
|
69
|
+
end.should raise_error(DataCatalog::ApiKeyNotConfigured)
|
70
|
+
end
|
71
|
+
|
72
|
+
end # describe ".set_default_params"
|
73
|
+
|
74
|
+
describe ".set_up!" do
|
75
|
+
|
76
|
+
it "should set both the base URI and API key" do
|
77
|
+
DataCatalog.base_uri = 'somehost.com'
|
78
|
+
DataCatalog.api_key = 'flurfeneugen'
|
79
|
+
DataCatalog::Base.set_up!
|
80
|
+
DataCatalog::Base.default_options[:base_uri].should == 'http://somehost.com'
|
81
|
+
DataCatalog::Base.default_options[:default_params].should include(:api_key => 'flurfeneugen')
|
82
|
+
end
|
83
|
+
|
84
|
+
end # describe ".set_up!"
|
85
|
+
|
86
|
+
describe ".build_object" do
|
87
|
+
|
88
|
+
it "should create an object when a filled hash is passed in" do
|
89
|
+
base_object = DataCatalog::Base.build_object(:name => "John Smith", :email => "john@email.com")
|
90
|
+
base_object.should be_an_instance_of(DataCatalog::Base)
|
91
|
+
base_object.email.should == "john@email.com"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return nil when an empty hash is passed in" do
|
95
|
+
base_object = DataCatalog::Base.build_object({})
|
96
|
+
base_object.should be_nil
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should return nil when nil is passed in" do
|
100
|
+
base_object = DataCatalog::Base.build_object(nil)
|
101
|
+
base_object.should be_nil
|
102
|
+
end
|
103
|
+
|
104
|
+
end # describe ".build_object!"
|
105
|
+
|
106
|
+
describe ".about" do
|
107
|
+
|
108
|
+
it "should return information about the API" do
|
109
|
+
base_object = DataCatalog::Base.about
|
110
|
+
base_object.should be_an_instance_of(DataCatalog::Base)
|
111
|
+
base_object.name.should == "National Data Catalog API"
|
112
|
+
end
|
113
|
+
|
114
|
+
end # describe ".about"
|
115
|
+
|
116
|
+
describe ".check_status_code" do
|
117
|
+
|
118
|
+
it "should return nil on 200 OK" do
|
119
|
+
response = HTTParty::Response.new(nil, '{"foo":"bar"}', 200, 'OK', {})
|
120
|
+
DataCatalog::Base.check_status_code(response).should be_nil
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should raise BadRequest on 400 Bad Request" do
|
124
|
+
response = HTTParty::Response.new(nil, '[]', 400, 'Bad Request', {})
|
125
|
+
executing do
|
126
|
+
DataCatalog::Base.check_status_code(response)
|
127
|
+
end.should raise_error(DataCatalog::BadRequest)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should raise Unauthorized on 401 Unauthorized" do
|
131
|
+
response = HTTParty::Response.new(nil, '', 401, 'Unauthorized', {})
|
132
|
+
executing do
|
133
|
+
DataCatalog::Base.check_status_code(response)
|
134
|
+
end.should raise_error(DataCatalog::Unauthorized)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should raise NotFound on 404 Not Found" do
|
138
|
+
response = HTTParty::Response.new(nil, '[]', 404, 'Not Found', {})
|
139
|
+
executing do
|
140
|
+
DataCatalog::Base.check_status_code(response)
|
141
|
+
end.should raise_error(DataCatalog::NotFound)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should raise InternalServerError on 500 Internal Server Error" do
|
145
|
+
response = HTTParty::Response.new(nil, '', 500, 'Internal Server Error', {})
|
146
|
+
executing do
|
147
|
+
DataCatalog::Base.check_status_code(response)
|
148
|
+
end.should raise_error(DataCatalog::InternalServerError)
|
149
|
+
end
|
150
|
+
|
151
|
+
end # describe ".check_status_code"
|
152
|
+
|
153
|
+
describe ".error_message" do
|
154
|
+
|
155
|
+
it "should return an 'Unable to parse:' message when body is blank" do
|
156
|
+
response = HTTParty::Response.new(nil, '', 404, 'Not Found', {})
|
157
|
+
DataCatalog::Base.error_message(response).should == %(Unable to parse: "")
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should return 'Response was empty' when body is an empty JSON object" do
|
161
|
+
response = HTTParty::Response.new(nil, '{}', 404, 'Not Found', {})
|
162
|
+
DataCatalog::Base.error_message(response).should == "Response was empty"
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should return 'Response was empty' when body is an empty array" do
|
166
|
+
response = HTTParty::Response.new(nil, '[]', 404, 'Not Found', {})
|
167
|
+
DataCatalog::Base.error_message(response).should == "Response was empty"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should return the contents of the errors hash when it exists" do
|
171
|
+
errors = '{"errors":["bad_error"]}'
|
172
|
+
response = HTTParty::Response.new(nil, errors, 400, 'Bad Request', {})
|
173
|
+
DataCatalog::Base.error_message(response).should == '["bad_error"]'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should return the contents of the response body when no errors hash exists" do
|
177
|
+
errors = '{"foo":["bar"]}'
|
178
|
+
response = HTTParty::Response.new(nil, errors, 400, 'Bad Request', {})
|
179
|
+
DataCatalog::Base.error_message(response).should == '{"foo":["bar"]}'
|
180
|
+
end
|
181
|
+
|
182
|
+
end # describe ".error_message"
|
183
|
+
|
184
|
+
end # describe DataCatalog::Base
|
data/spec/source_spec.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe DataCatalog::Source do
|
4
|
+
|
5
|
+
def create_source(params={})
|
6
|
+
valid_params = {
|
7
|
+
:title => "Some FCC Data",
|
8
|
+
:url => "http://fcc.gov/somedata.csv"
|
9
|
+
}
|
10
|
+
DataCatalog::Source.create(valid_params.merge(params))
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
setup_api
|
15
|
+
clean_slate
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".all" do
|
19
|
+
before do
|
20
|
+
%w(FCC NASA DOE).each do |name|
|
21
|
+
DataCatalog::Source.create({
|
22
|
+
:title => "#{name} Data",
|
23
|
+
:url => "http://#{name.downcase}.gov/data.xml"
|
24
|
+
})
|
25
|
+
end
|
26
|
+
@sources = DataCatalog::Source.all
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return an enumeration of sources" do
|
30
|
+
@sources.each do |source|
|
31
|
+
source.should be_an_instance_of(DataCatalog::Source)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return correct titles" do
|
36
|
+
expected = ["FCC Data", "NASA Data", "DOE Data"]
|
37
|
+
@sources.map(&:title).sort.should == expected.sort
|
38
|
+
end
|
39
|
+
end # describe ".all"
|
40
|
+
|
41
|
+
describe ".create" do
|
42
|
+
it "should create a new source from basic params" do
|
43
|
+
source = create_source
|
44
|
+
source.should be_an_instance_of(DataCatalog::Source)
|
45
|
+
source.url.should == "http://fcc.gov/somedata.csv"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should create a new source from custom params" do
|
49
|
+
source = create_source({ :custom => {
|
50
|
+
"0" => {
|
51
|
+
:label => "License",
|
52
|
+
:description => "License",
|
53
|
+
:type => "string",
|
54
|
+
:value => "Public Domain"
|
55
|
+
}
|
56
|
+
}})
|
57
|
+
source.should be_an_instance_of(DataCatalog::Source)
|
58
|
+
source.url.should == "http://fcc.gov/somedata.csv"
|
59
|
+
source.custom.should == {
|
60
|
+
"0" => {
|
61
|
+
"label" => "License",
|
62
|
+
"description" => "License",
|
63
|
+
"type" => "string",
|
64
|
+
"value" => "Public Domain"
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end # describe ".all"
|
69
|
+
|
70
|
+
describe ".update" do
|
71
|
+
before do
|
72
|
+
@source = create_source
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should update an existing source from valid params" do
|
76
|
+
source = DataCatalog::Source.update(@source.id, {
|
77
|
+
:url => "http://fec.gov/newdata.csv"
|
78
|
+
})
|
79
|
+
source.should be_an_instance_of(DataCatalog::Source)
|
80
|
+
source.url.should == "http://fec.gov/newdata.csv"
|
81
|
+
end
|
82
|
+
end # describe ".all"
|
83
|
+
|
84
|
+
describe ".destroy" do
|
85
|
+
before do
|
86
|
+
@source = create_source
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should destroy an existing source" do
|
90
|
+
result = DataCatalog::Source.destroy(@source.id)
|
91
|
+
result.should be_true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should raise NotFound when attempting to destroy non-existing source" do
|
95
|
+
executing do
|
96
|
+
DataCatalog::Source.destroy(mangle(@source.id))
|
97
|
+
end.should raise_error(DataCatalog::NotFound)
|
98
|
+
end
|
99
|
+
end # describe ".destroy"
|
100
|
+
|
101
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/datacatalog'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
Spec::Runner.configure do |config|
|
5
|
+
config.mock_with :rr
|
6
|
+
end
|
7
|
+
|
8
|
+
alias :executing :lambda
|
9
|
+
|
10
|
+
def setup_api
|
11
|
+
config = YAML.load_file(File.dirname(__FILE__) + '/../sandbox_api.yml')
|
12
|
+
DataCatalog.api_key = config['api_key']
|
13
|
+
DataCatalog.base_uri = config['base_uri']
|
14
|
+
end
|
15
|
+
|
16
|
+
def clean_slate
|
17
|
+
DataCatalog::User.all.each do |u|
|
18
|
+
DataCatalog::User.destroy(u.id) unless u.name == "Primary Admin"
|
19
|
+
end
|
20
|
+
DataCatalog::Source.all.each do |s|
|
21
|
+
DataCatalog::Source.destroy(s.id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
if RUBY_VERSION >= "1.8.7"
|
26
|
+
# Converts a valid ID into a almost-but-not-quite valid one.
|
27
|
+
# Here is an example of what it does:
|
28
|
+
# From ... 4ac2520b25b7e7056600034e
|
29
|
+
# To ... a42c25b0527b7e50660030e4
|
30
|
+
def mangle(string)
|
31
|
+
array = string.chars.to_a
|
32
|
+
sliced = []
|
33
|
+
array.each_slice(2) { |s| sliced << s.reverse }
|
34
|
+
result = sliced.flatten.join
|
35
|
+
raise "mangle failed" if result == string
|
36
|
+
result
|
37
|
+
end
|
38
|
+
else
|
39
|
+
# Converts a valid ID into a almost-but-not-quite valid one.
|
40
|
+
# Here is an example of what it does:
|
41
|
+
# From ... 4ac2520b25b7e7056600034e
|
42
|
+
# To ... e4300066507e7b52b0252ca4
|
43
|
+
def mangle(string)
|
44
|
+
result = string.reverse
|
45
|
+
raise "mangle failed" if result == string
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
data/spec/user_spec.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe DataCatalog::User do
|
4
|
+
|
5
|
+
def create_user
|
6
|
+
DataCatalog::User.create({
|
7
|
+
:name => "Ted Smith",
|
8
|
+
:email => "ted@email.com"
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_user_with_2_keys
|
13
|
+
user = create_user
|
14
|
+
result = user.generate_api_key!(
|
15
|
+
:purpose => "Civic hacking with my awesome app",
|
16
|
+
:key_type => "application"
|
17
|
+
)
|
18
|
+
raise "generate_api_key! failed" unless result
|
19
|
+
raise "incorrect number of keys" unless user.api_keys.length == 2
|
20
|
+
user
|
21
|
+
end
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
setup_api
|
25
|
+
clean_slate
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".all" do
|
29
|
+
before(:each) do
|
30
|
+
3.times do |n|
|
31
|
+
DataCatalog::User.create(
|
32
|
+
:name => "User-#{n}",
|
33
|
+
:email => "user_#{n}@email.com"
|
34
|
+
)
|
35
|
+
end
|
36
|
+
@users = DataCatalog::User.all
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return an enumeration of users" do
|
40
|
+
@users.each do |u|
|
41
|
+
u.should be_an_instance_of(DataCatalog::User)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should include four users" do
|
46
|
+
names = @users.map(&:name)
|
47
|
+
names.should include("User-0")
|
48
|
+
names.should include("User-1")
|
49
|
+
names.should include("User-2")
|
50
|
+
end
|
51
|
+
end # describe ".all"
|
52
|
+
|
53
|
+
describe ".create" do
|
54
|
+
before do
|
55
|
+
@user = create_user
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should create a new user when valid params are passed in" do
|
59
|
+
@user.should be_an_instance_of(DataCatalog::User)
|
60
|
+
@user.name.should == "Ted Smith"
|
61
|
+
@user.email.should == "ted@email.com"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should raise BadRequest when invalid params are passed in" do
|
65
|
+
executing do
|
66
|
+
DataCatalog::User.create({ :garbage_field => "junk" })
|
67
|
+
end.should raise_error(DataCatalog::BadRequest)
|
68
|
+
end
|
69
|
+
end # describe ".create"
|
70
|
+
|
71
|
+
describe ".find" do
|
72
|
+
before do
|
73
|
+
@user = create_user
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return a user" do
|
77
|
+
user = DataCatalog::User.find(@user.id)
|
78
|
+
user.should be_an_instance_of(DataCatalog::User)
|
79
|
+
user.email.should == "ted@email.com"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should raise NotFound out if no user exists" do
|
83
|
+
executing do
|
84
|
+
DataCatalog::User.find(mangle(@user.id))
|
85
|
+
end.should raise_error(DataCatalog::NotFound)
|
86
|
+
end
|
87
|
+
end # describe ".find"
|
88
|
+
|
89
|
+
describe ".find_by_api_key" do
|
90
|
+
before do
|
91
|
+
@user = create_user
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return a user" do
|
95
|
+
user = DataCatalog::User.find_by_api_key(@user.primary_api_key)
|
96
|
+
user.should be_an_instance_of(DataCatalog::User)
|
97
|
+
user.email.should == "ted@email.com"
|
98
|
+
end
|
99
|
+
end # describe ".find_by_api_key"
|
100
|
+
|
101
|
+
describe ".update" do
|
102
|
+
before do
|
103
|
+
@user = create_user
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should update a user when valid params are passed in" do
|
107
|
+
user = DataCatalog::User.update(@user.id, { :name => "Jane Smith" })
|
108
|
+
user.name.should == "Jane Smith"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should raise BadRequest when invalid params are passed in" do
|
112
|
+
executing do
|
113
|
+
DataCatalog::User.update(@user.id, { :garbage => "junk" })
|
114
|
+
end.should raise_error(DataCatalog::BadRequest)
|
115
|
+
end
|
116
|
+
|
117
|
+
end # describe ".update"
|
118
|
+
|
119
|
+
describe ".destroy" do
|
120
|
+
before do
|
121
|
+
@user = create_user
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should destroy an existing user" do
|
125
|
+
result = DataCatalog::User.destroy(@user.id)
|
126
|
+
result.should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should raise NotFound when non-existing user" do
|
130
|
+
executing do
|
131
|
+
DataCatalog::User.destroy(mangle(@user.id))
|
132
|
+
end.should raise_error(DataCatalog::NotFound)
|
133
|
+
end
|
134
|
+
end # describe ".destroy"
|
135
|
+
|
136
|
+
describe "#generate_api_key!" do
|
137
|
+
before do
|
138
|
+
@user = create_user
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should generate a new key for the user" do
|
142
|
+
@user.api_keys.length.should == 1
|
143
|
+
@user.generate_api_key!({
|
144
|
+
:purpose => "Civic hacking with my awesome app",
|
145
|
+
:key_type => "application"
|
146
|
+
}).should be_true
|
147
|
+
@user.api_keys.length.should == 2
|
148
|
+
@user.api_keys.last[:purpose].should == "Civic hacking with my awesome app"
|
149
|
+
@user.application_api_keys.length.should == 1
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should raise BadRequest when attempting to create a primary key" do
|
153
|
+
executing do
|
154
|
+
@user.generate_api_key!({
|
155
|
+
:purpose => "Civic hacking with my awesome app",
|
156
|
+
:key_type => "primary"
|
157
|
+
})
|
158
|
+
end.should raise_error(DataCatalog::BadRequest)
|
159
|
+
end
|
160
|
+
end # describe "#generate_api_key!"
|
161
|
+
|
162
|
+
describe "#update_api_key!" do
|
163
|
+
before do
|
164
|
+
@user = create_user_with_2_keys
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should update a key for the user" do
|
168
|
+
@user.update_api_key!(@user.api_keys[1].id, {
|
169
|
+
:key_type => "valet",
|
170
|
+
:purpose => "To be more awesome"
|
171
|
+
}).should be_true
|
172
|
+
@user.api_keys[1].purpose.should == "To be more awesome"
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should raise NotFound if updating a key that doesn't exist" do
|
176
|
+
executing do
|
177
|
+
@user.update_api_key!(mangle(@user.api_keys[1].id), {})
|
178
|
+
end.should raise_error(DataCatalog::NotFound)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should raise BadRequest if primary key's type is changed" do
|
182
|
+
executing do
|
183
|
+
@user.update_api_key!(@user.api_keys[0].id, {
|
184
|
+
:key_type => "valet"
|
185
|
+
})
|
186
|
+
end.should raise_error(DataCatalog::BadRequest)
|
187
|
+
end
|
188
|
+
end # describe "#update_api_key!"
|
189
|
+
|
190
|
+
describe "#delete_api_key!" do
|
191
|
+
before do
|
192
|
+
@user = create_user_with_2_keys
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should delete a key for the user" do
|
196
|
+
@user.delete_api_key!(@user.api_keys[1].id).should be_true
|
197
|
+
@user.api_keys.length.should == 1
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should raise Conflict if deleting the primary key" do
|
201
|
+
executing do
|
202
|
+
@user.delete_api_key!(@user.api_keys[0].id)
|
203
|
+
end.should raise_error(DataCatalog::Conflict)
|
204
|
+
@user.api_keys.length.should == 2
|
205
|
+
end
|
206
|
+
end # describe "#delete_api_key!"
|
207
|
+
|
208
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: datacatalog
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Luigi Montanez
|
8
|
+
- David James
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-10-05 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
description: Ruby library that wraps the National Data Catalog API
|
27
|
+
email: luigi@sunlightfoundation.com
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- LICENSE.md
|
34
|
+
- README.md
|
35
|
+
files:
|
36
|
+
- .gitignore
|
37
|
+
- CHANGES.md
|
38
|
+
- LICENSE.md
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- VERSION
|
42
|
+
- datacatalog.gemspec
|
43
|
+
- doc/api_key_spec_for_rest_api.txt
|
44
|
+
- doc/api_key_spec_for_ruby_api.rb
|
45
|
+
- doc/mocking_options.md
|
46
|
+
- lib/datacatalog.rb
|
47
|
+
- lib/datacatalog/api_key.rb
|
48
|
+
- lib/datacatalog/base.rb
|
49
|
+
- lib/datacatalog/source.rb
|
50
|
+
- lib/datacatalog/user.rb
|
51
|
+
- sandbox_api.yml.example
|
52
|
+
- spec/api_key_spec.rb
|
53
|
+
- spec/base_spec.rb
|
54
|
+
- spec/source_spec.rb
|
55
|
+
- spec/spec.opts
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- spec/user_spec.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/sunlightlabs/datacatalog
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Wrapper for the National Data Catalog API
|
86
|
+
test_files:
|
87
|
+
- spec/api_key_spec.rb
|
88
|
+
- spec/base_spec.rb
|
89
|
+
- spec/source_spec.rb
|
90
|
+
- spec/spec_helper.rb
|
91
|
+
- spec/user_spec.rb
|