sinatra_resource 0.1.0
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/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.mdown +28 -0
- data/Rakefile +34 -0
- data/VERSION +1 -0
- data/examples/datacatalog/Rakefile +23 -0
- data/examples/datacatalog/app.rb +15 -0
- data/examples/datacatalog/config/config.rb +66 -0
- data/examples/datacatalog/config/config.yml +11 -0
- data/examples/datacatalog/config.ru +6 -0
- data/examples/datacatalog/lib/base.rb +9 -0
- data/examples/datacatalog/lib/resource.rb +73 -0
- data/examples/datacatalog/lib/roles.rb +15 -0
- data/examples/datacatalog/models/categorization.rb +31 -0
- data/examples/datacatalog/models/category.rb +28 -0
- data/examples/datacatalog/models/source.rb +33 -0
- data/examples/datacatalog/models/user.rb +51 -0
- data/examples/datacatalog/resources/categories.rb +32 -0
- data/examples/datacatalog/resources/sources.rb +35 -0
- data/examples/datacatalog/resources/users.rb +26 -0
- data/examples/datacatalog/tasks/db.rake +29 -0
- data/examples/datacatalog/tasks/test.rake +16 -0
- data/examples/datacatalog/test/helpers/assertions/assert_include.rb +17 -0
- data/examples/datacatalog/test/helpers/assertions/assert_not_include.rb +17 -0
- data/examples/datacatalog/test/helpers/lib/model_factories.rb +49 -0
- data/examples/datacatalog/test/helpers/lib/model_helpers.rb +30 -0
- data/examples/datacatalog/test/helpers/lib/request_helpers.rb +53 -0
- data/examples/datacatalog/test/helpers/model_test_helper.rb +5 -0
- data/examples/datacatalog/test/helpers/resource_test_helper.rb +5 -0
- data/examples/datacatalog/test/helpers/shared/api_keys.rb +48 -0
- data/examples/datacatalog/test/helpers/shared/common_body_responses.rb +15 -0
- data/examples/datacatalog/test/helpers/shared/status_codes.rb +61 -0
- data/examples/datacatalog/test/helpers/test_cases/model_test_case.rb +6 -0
- data/examples/datacatalog/test/helpers/test_cases/resource_test_case.rb +36 -0
- data/examples/datacatalog/test/helpers/test_helper.rb +36 -0
- data/examples/datacatalog/test/models/categorization_test.rb +40 -0
- data/examples/datacatalog/test/models/category_test.rb +35 -0
- data/examples/datacatalog/test/models/source_test.rb +37 -0
- data/examples/datacatalog/test/models/user_test.rb +77 -0
- data/examples/datacatalog/test/resources/categories/categories_delete_test.rb +112 -0
- data/examples/datacatalog/test/resources/categories/categories_get_many_test.rb +58 -0
- data/examples/datacatalog/test/resources/categories/categories_get_one_test.rb +75 -0
- data/examples/datacatalog/test/resources/categories/categories_post_test.rb +135 -0
- data/examples/datacatalog/test/resources/categories/categories_put_test.rb +140 -0
- data/examples/datacatalog/test/resources/sources/sources_delete_test.rb +112 -0
- data/examples/datacatalog/test/resources/sources/sources_get_many_test.rb +58 -0
- data/examples/datacatalog/test/resources/sources/sources_get_one_test.rb +74 -0
- data/examples/datacatalog/test/resources/sources/sources_post_test.rb +184 -0
- data/examples/datacatalog/test/resources/sources/sources_put_test.rb +227 -0
- data/examples/datacatalog/test/resources/users/users_delete_test.rb +134 -0
- data/examples/datacatalog/test/resources/users/users_get_many_test.rb +111 -0
- data/examples/datacatalog/test/resources/users/users_get_one_test.rb +75 -0
- data/examples/datacatalog/test/resources/users/users_post_test.rb +142 -0
- data/examples/datacatalog/test/resources/users/users_put_test.rb +171 -0
- data/lib/builder/helpers.rb +319 -0
- data/lib/builder/mongo_helpers.rb +70 -0
- data/lib/builder.rb +84 -0
- data/lib/exceptions.rb +10 -0
- data/lib/resource.rb +171 -0
- data/lib/roles.rb +163 -0
- data/lib/sinatra_resource.rb +6 -0
- data/notes/keywords.mdown +1 -0
- data/notes/permissions.mdown +181 -0
- data/notes/questions.mdown +18 -0
- data/notes/see_also.mdown +3 -0
- data/notes/synonyms.mdown +7 -0
- data/notes/to_do.mdown +7 -0
- data/notes/uniform_interface.mdown +22 -0
- data/sinatra_resource.gemspec +183 -0
- data/spec/sinatra_resource_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- data/tasks/spec.rake +13 -0
- data/tasks/yard.rake +13 -0
- metadata +253 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 David James
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.mdown
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
## About
|
2
|
+
|
3
|
+
Want to build Web services in the Resource Oriented Architecture style? With resource_sinatra, success is all but guaranteed, provided that you are using a [Sinatra](http://sinatrarb.com) + [MongoMapper](http://github.com/djsun/mongomapper) stack.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
It might not be a bad idea to make sure you are running the latest RubyGems:
|
8
|
+
|
9
|
+
sudo gem update --system
|
10
|
+
|
11
|
+
You will need gemcutter if you don't have it already:
|
12
|
+
|
13
|
+
gem install gemcutter
|
14
|
+
gem tumble
|
15
|
+
|
16
|
+
I recommend a user-level install:
|
17
|
+
|
18
|
+
gem install djsun-resource_sinatra
|
19
|
+
|
20
|
+
Note: in general, beware of `sudo gem install <project_name>` -- it gives elevated privileges. Do you trust `<project name>`? Better to be safe and use a local install to `~/.gem`.
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
For a basic example of what this looks like when integrated into a real-world Sinatra app, see `/examples/datacatalog`.
|
25
|
+
|
26
|
+
## History
|
27
|
+
|
28
|
+
This code was extracted from the [National Data Catalog](http://groups.google.com/group/datacatalog), a project of the [Sunlight Labs](http://sunlightlabs.com).
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sinatra_resource"
|
8
|
+
gem.summary = %Q{RESTful actions with Sinatra and MongoMapper}
|
9
|
+
gem.description = %Q{A DSL for creating RESTful actions with Sinatra and MongoMapper. It embraces the Resource Oriented Architecture as explained by Leonard Richardson and Sam Ruby.}
|
10
|
+
gem.email = "djames@sunlightfoundation.com"
|
11
|
+
gem.homepage = "http://github.com/djsun/sinatra_resource"
|
12
|
+
gem.authors = ["David James"]
|
13
|
+
|
14
|
+
gem.add_dependency 'djsun-mongo_mapper', '= 0.5.5.3'
|
15
|
+
gem.add_dependency 'mongo', '>= 0.15.1'
|
16
|
+
gem.add_dependency 'sinatra', '>= 0.9.4'
|
17
|
+
|
18
|
+
gem.add_development_dependency 'crack', '>= 0.1.4'
|
19
|
+
gem.add_development_dependency 'djsun-context', '>= 0.5.6'
|
20
|
+
gem.add_development_dependency 'jeremymcanally-pending', '>= 0.1'
|
21
|
+
gem.add_development_dependency 'rspec'
|
22
|
+
gem.add_development_dependency 'yard'
|
23
|
+
|
24
|
+
# gem is a Gem::Specification ...
|
25
|
+
# ... see http://www.rubygems.org/read/chapter/20 for additional settings
|
26
|
+
end
|
27
|
+
Jeweler::GemcutterTasks.new
|
28
|
+
rescue LoadError
|
29
|
+
puts "Jeweler (or a dependency) not available. Install with: gem install jeweler"
|
30
|
+
end
|
31
|
+
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
Dir.glob(File.dirname(__FILE__) + '/tasks/*.rake').each { |f| load f }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rcov/rcovtask'
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + '/config/config'
|
6
|
+
Dir.glob(File.dirname(__FILE__) + '/tasks/*.rake').each { |f| load f }
|
7
|
+
|
8
|
+
desc "Default: run all tests"
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
namespace :environment do
|
12
|
+
task :application do
|
13
|
+
puts "Loading application environment..."
|
14
|
+
require File.dirname(__FILE__) + '/app'
|
15
|
+
end
|
16
|
+
|
17
|
+
task :models do
|
18
|
+
puts "Loading models..."
|
19
|
+
Config.setup_mongomapper
|
20
|
+
base = File.dirname(__FILE__)
|
21
|
+
Dir.glob(base + '/models/*.rb' ).each { |f| require f }
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
gem 'sinatra', '>= 0.9.4'
|
4
|
+
require 'sinatra/base'
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/config/config'
|
7
|
+
|
8
|
+
Sinatra::Base.set(:config, Config.environment_config)
|
9
|
+
Config.setup
|
10
|
+
|
11
|
+
base = File.dirname(__FILE__)
|
12
|
+
Dir.glob(base + '/lib/*.rb' ).each { |f| require f }
|
13
|
+
Dir.glob(base + '/models/*.rb' ).each { |f| require f }
|
14
|
+
Dir.glob(base + '/resource_helpers/*.rb').each { |f| require f }
|
15
|
+
Dir.glob(base + '/resources/*.rb' ).each { |f| require f }
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module Config
|
4
|
+
|
5
|
+
def self.setup
|
6
|
+
setup_mongomapper
|
7
|
+
# More application setup can go here...
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.setup_mongomapper
|
11
|
+
gem 'djsun-mongo_mapper', '= 0.5.5.3'
|
12
|
+
require 'mongo_mapper'
|
13
|
+
MongoMapper.connection = new_mongo_connection
|
14
|
+
MongoMapper.database = environment_config['mongo_database']
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.new_mongo_connection
|
18
|
+
gem 'mongo', "= 0.15.1"
|
19
|
+
require 'mongo'
|
20
|
+
Mongo::Connection.new(environment_config["mongo_hostname"])
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.drop_database
|
24
|
+
database_name = environment_config["mongo_database"]
|
25
|
+
new_mongo_connection.drop_database(database_name)
|
26
|
+
database_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.environment_config
|
30
|
+
env_config = config[environment]
|
31
|
+
unless env_config
|
32
|
+
raise "Environment config not found for #{environment.inspect}"
|
33
|
+
end
|
34
|
+
env_config
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.environment
|
38
|
+
if @environment
|
39
|
+
@environment
|
40
|
+
else
|
41
|
+
@environment = if Object.const_defined?("Sinatra")
|
42
|
+
Sinatra::Base.environment.to_s
|
43
|
+
else
|
44
|
+
ENV['RACK_ENV'] || 'development'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.environment=(env)
|
50
|
+
@environment = env
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.environments
|
54
|
+
config.keys
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.config
|
58
|
+
if @config
|
59
|
+
@config
|
60
|
+
else
|
61
|
+
file = File.join(File.dirname(__FILE__), "config.yml")
|
62
|
+
@config = YAML.load_file(file)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
development:
|
2
|
+
base_uri: http://localhost:3000/
|
3
|
+
mongo_hostname: localhost
|
4
|
+
mongo_database: s_r_example_1_dev
|
5
|
+
api_key_salt: 51a920cc75eb105934df9be349be68cfdd6acf1c
|
6
|
+
|
7
|
+
test:
|
8
|
+
base_uri: http://localhost:4567/
|
9
|
+
mongo_hostname: localhost
|
10
|
+
mongo_database: s_r_example_1_test
|
11
|
+
api_key_salt: 51a920cc75eb105934df9be349be68cfdd6acf1c
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module DataCatalog
|
4
|
+
|
5
|
+
module Resource
|
6
|
+
|
7
|
+
def self.included(includee)
|
8
|
+
includee.instance_eval do
|
9
|
+
include SinatraResource::Resource
|
10
|
+
end
|
11
|
+
includee.helpers do
|
12
|
+
def before_authorization(action, role)
|
13
|
+
unless role
|
14
|
+
error 401, convert(body_for(:errors, ["invalid_api_key"]))
|
15
|
+
end
|
16
|
+
if role == :anonymous && minimum_role(action) != :anonymous
|
17
|
+
error 401, convert(body_for(:errors, ["missing_api_key"]))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def convert(object)
|
22
|
+
object == "" ? "" : object.to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
def full_uri(path)
|
26
|
+
base_uri = Config.environment_config["base_uri"]
|
27
|
+
URI.join(base_uri, path).to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def lookup_role(document=nil)
|
31
|
+
api_key = lookup_api_key
|
32
|
+
return :anonymous unless api_key
|
33
|
+
user = user_for(api_key)
|
34
|
+
return nil unless user
|
35
|
+
return :owner if document && owner?(user, document)
|
36
|
+
user.role.intern
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def lookup_api_key
|
42
|
+
@api_key ||= params.delete("api_key")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Is +user+ the owner of +document+?
|
46
|
+
#
|
47
|
+
# First, checks to see if +user+ and +document+ are the same. After
|
48
|
+
# that, try to follow the +document.user+ relationship, if present, to
|
49
|
+
# see if that points to +user+.
|
50
|
+
#
|
51
|
+
# @param [DataCatalog::User] user
|
52
|
+
#
|
53
|
+
# @param [MongoMapper::Document] user
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
def owner?(user, document)
|
57
|
+
return true if user == document
|
58
|
+
return false unless document.respond_to?(:user)
|
59
|
+
document.user == user
|
60
|
+
end
|
61
|
+
|
62
|
+
def user_for(api_key)
|
63
|
+
user = User.first(:conditions => { :_api_key => api_key })
|
64
|
+
return nil unless user
|
65
|
+
raise "API key found, but user has no role" unless user.role
|
66
|
+
user
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../lib/sinatra_resource'
|
2
|
+
|
3
|
+
module DataCatalog
|
4
|
+
|
5
|
+
module Roles
|
6
|
+
include SinatraResource::Roles
|
7
|
+
|
8
|
+
role :anonymous
|
9
|
+
role :basic => :anonymous
|
10
|
+
role :owner => :basic
|
11
|
+
role :curator => :basic
|
12
|
+
role :admin => [:owner, :curator]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Categorization
|
4
|
+
|
5
|
+
include MongoMapper::Document
|
6
|
+
|
7
|
+
# == Attributes
|
8
|
+
|
9
|
+
key :source_id, String
|
10
|
+
key :category_id, String
|
11
|
+
timestamps!
|
12
|
+
|
13
|
+
# == Indices
|
14
|
+
|
15
|
+
# == Associations
|
16
|
+
|
17
|
+
belongs_to :source
|
18
|
+
belongs_to :category
|
19
|
+
|
20
|
+
# == Validations
|
21
|
+
|
22
|
+
validate :validate_associations
|
23
|
+
|
24
|
+
def validate_associations
|
25
|
+
errors.add(:source_id, "must be valid") if source.nil?
|
26
|
+
errors.add(:category_id, "must be valid") if category.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Category
|
4
|
+
|
5
|
+
include MongoMapper::Document
|
6
|
+
|
7
|
+
# == Attributes
|
8
|
+
|
9
|
+
key :name, String
|
10
|
+
timestamps!
|
11
|
+
|
12
|
+
# == Indices
|
13
|
+
|
14
|
+
# == Associations
|
15
|
+
|
16
|
+
many :categorizations
|
17
|
+
|
18
|
+
def sources
|
19
|
+
categorizations.map(&:source)
|
20
|
+
end
|
21
|
+
|
22
|
+
# == Validations
|
23
|
+
|
24
|
+
validates_presence_of :name
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Source
|
4
|
+
|
5
|
+
include MongoMapper::Document
|
6
|
+
|
7
|
+
# == Attributes
|
8
|
+
|
9
|
+
key :title, String
|
10
|
+
key :url, String
|
11
|
+
key :raw, Hash
|
12
|
+
timestamps!
|
13
|
+
|
14
|
+
# == Indices
|
15
|
+
|
16
|
+
ensure_index :url
|
17
|
+
|
18
|
+
# == Associations
|
19
|
+
|
20
|
+
many :categorizations
|
21
|
+
|
22
|
+
def categories
|
23
|
+
categorizations.map(&:category)
|
24
|
+
end
|
25
|
+
|
26
|
+
# == Validations
|
27
|
+
|
28
|
+
validates_presence_of :title
|
29
|
+
validates_presence_of :url
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module DataCatalog
|
4
|
+
|
5
|
+
class User
|
6
|
+
|
7
|
+
include MongoMapper::Document
|
8
|
+
|
9
|
+
# == Attributes
|
10
|
+
|
11
|
+
key :name, String
|
12
|
+
key :email, String
|
13
|
+
key :role, String
|
14
|
+
key :_api_key, String
|
15
|
+
timestamps!
|
16
|
+
|
17
|
+
# == Indices
|
18
|
+
|
19
|
+
ensure_index :email
|
20
|
+
|
21
|
+
# == Validations
|
22
|
+
|
23
|
+
validates_presence_of :name
|
24
|
+
validates_presence_of :role
|
25
|
+
validate :validate_role
|
26
|
+
|
27
|
+
VALID_ROLES = %w(basic curator admin)
|
28
|
+
|
29
|
+
def validate_role
|
30
|
+
unless VALID_ROLES.include?(role)
|
31
|
+
errors.add(:role, "must be in #{VALID_ROLES.inspect}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# == Callbacks
|
36
|
+
|
37
|
+
def before_create
|
38
|
+
unless _api_key
|
39
|
+
self._api_key = generate_api_key
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_api_key
|
44
|
+
salt = Config.environment_config["api_key_salt"]
|
45
|
+
s = "#{Time.now.to_f}#{salt}#{rand(100_000_000)}#{name}#{email}"
|
46
|
+
Digest::SHA1.hexdigest(s)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Categories < Base
|
4
|
+
include Resource
|
5
|
+
|
6
|
+
model Category
|
7
|
+
|
8
|
+
# == Permissions
|
9
|
+
|
10
|
+
roles Roles
|
11
|
+
permission :read => :basic
|
12
|
+
permission :modify => :curator
|
13
|
+
|
14
|
+
# == Properties
|
15
|
+
|
16
|
+
property :name
|
17
|
+
|
18
|
+
property :sources do |category|
|
19
|
+
category.sources.map do |source|
|
20
|
+
{
|
21
|
+
"id" => source.id,
|
22
|
+
"href" => "/sources/#{source.id}",
|
23
|
+
"title" => source.title,
|
24
|
+
"url" => source.url,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Categories.build
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Sources < Base
|
4
|
+
include Resource
|
5
|
+
|
6
|
+
model Source
|
7
|
+
|
8
|
+
# == Permissions
|
9
|
+
|
10
|
+
roles Roles
|
11
|
+
permission :read => :basic
|
12
|
+
permission :modify => :curator
|
13
|
+
|
14
|
+
# == Properties
|
15
|
+
|
16
|
+
property :title
|
17
|
+
property :url
|
18
|
+
property :raw, :w => :admin
|
19
|
+
|
20
|
+
property :categories do |source|
|
21
|
+
source.categorizations.map do |categorization|
|
22
|
+
{
|
23
|
+
"id" => categorization.category.id,
|
24
|
+
"href" => "/categories/#{categorization.category.id}",
|
25
|
+
"name" => categorization.category.name,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# == Callbacks
|
31
|
+
end
|
32
|
+
|
33
|
+
Sources.build
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DataCatalog
|
2
|
+
|
3
|
+
class Users < Base
|
4
|
+
include Resource
|
5
|
+
|
6
|
+
model User
|
7
|
+
|
8
|
+
# == Permissions
|
9
|
+
|
10
|
+
roles Roles
|
11
|
+
permission :read => :basic
|
12
|
+
permission :modify => :owner
|
13
|
+
|
14
|
+
# == Properties
|
15
|
+
|
16
|
+
property :name, :r => :basic
|
17
|
+
property :email, :r => :owner
|
18
|
+
property :role, :r => :owner, :w => :admin
|
19
|
+
property :_api_key, :r => :owner, :w => :admin
|
20
|
+
|
21
|
+
# == Callbacks
|
22
|
+
end
|
23
|
+
|
24
|
+
Users.build
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace :db do
|
2
|
+
|
3
|
+
def verbosely_drop_database
|
4
|
+
db_name = Config.drop_database
|
5
|
+
puts "Dropped database: #{db_name}."
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Drop database for current environment (development unless RACK_ENV is set)'
|
9
|
+
task :reset do
|
10
|
+
verbosely_drop_database
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :reset do
|
14
|
+
desc 'Drop databases defined in config/config.yml'
|
15
|
+
task :all do
|
16
|
+
Config.environments.each do |env_name|
|
17
|
+
Config.environment = env_name
|
18
|
+
verbosely_drop_database
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Drop test database'
|
23
|
+
task :test do
|
24
|
+
Config.environment = 'test'
|
25
|
+
verbosely_drop_database
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
desc "Run tests"
|
2
|
+
task :test => %w(db:reset:test test:models test:resources)
|
3
|
+
|
4
|
+
namespace :test do
|
5
|
+
|
6
|
+
desc "Run model tests"
|
7
|
+
Rake::TestTask.new(:models) do |t|
|
8
|
+
t.test_files = FileList["test/models/*_test.rb"]
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Run other tests"
|
12
|
+
Rake::TestTask.new(:resources) do |t|
|
13
|
+
t.test_files = FileList["test/resources/**/*_test.rb"]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Test
|
2
|
+
module Unit
|
3
|
+
module Assertions
|
4
|
+
|
5
|
+
def assert_include(expected, actual, message = nil)
|
6
|
+
_wrap_assertion do
|
7
|
+
full_message = build_message(message,
|
8
|
+
"<?> expected to include\n<?>.\n", actual, expected)
|
9
|
+
assert_block(full_message) do
|
10
|
+
actual.include?(expected)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Test
|
2
|
+
module Unit
|
3
|
+
module Assertions
|
4
|
+
|
5
|
+
def assert_not_include(expected, actual, message = nil)
|
6
|
+
_wrap_assertion do
|
7
|
+
full_message = build_message(message,
|
8
|
+
"<?> expected to not include\n<?>.\n", actual, expected)
|
9
|
+
assert_block(full_message) do
|
10
|
+
not actual.include?(expected)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|