json-crud-api 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d29a60e6d78b872ce5373491643e567e2c6131d8
4
+ data.tar.gz: ec36f07906e2cb7c7fa18811b586c33331879ddf
5
+ SHA512:
6
+ metadata.gz: 58cb2c22a099f4898bf5ccea53481e7ee8e1ae625991f319603cc58e824058e17c232242f7b0715e02283004225b6b51ad09d64a061411b8ed03b02f09a5d7c7
7
+ data.tar.gz: 7e4112a6b627e591b1017a9ceed570f880dddf526e8589368e6eb1c544f7c92f824877a9e04df0634f40602f6e6a6254a5ed585dc1a0ba8d3a1d153dfc1e3164
@@ -0,0 +1,4 @@
1
+ require "json-crud-api/service"
2
+ require "json-crud-api/crud"
3
+ require "json-crud-api/api"
4
+ require "json-crud-api/auth_client"
@@ -0,0 +1,102 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+
4
+ module JsonCrudApi
5
+ class API < Sinatra::Base
6
+
7
+ register JsonCrudApi::Crud
8
+
9
+ before do
10
+ # HTTPS Only (if configured)
11
+ if settings.respond_to? :https_only and settings.https_only and env['HTTPS'] != 'on' and env['HTTP_X_FORWARDED_PROTO'] != 'https'
12
+ fail_with_error 403, 'SSL_ONLY', 'The API can only be accessed over SSL (HTTPS)'
13
+ end
14
+
15
+ # JSON Errors
16
+ @errors = []
17
+
18
+ # No-Cache by default
19
+ cache_control :no_cache, :max_age => 0
20
+
21
+ # Session
22
+ @user = nil
23
+ @logged_in = false
24
+ if settings.respond_to? :auth_client
25
+ @session_id = env['HTTP_X_SESSION_ID']
26
+ unless @session_id.nil?
27
+ @user = settings.auth_client.get(@session_id)
28
+ @logged_in = !@user.nil?
29
+ end
30
+ end
31
+ settings.services.each do |k,service|
32
+ service.set_user @user if service.respond_to? :set_user
33
+ end
34
+
35
+ # JSON Payload
36
+ request.body.rewind
37
+ body = request.body.read
38
+ if body.length > 2
39
+ begin
40
+ @payload = JSON.parse body, :symbolize_names => true
41
+ rescue JSON::ParserError
42
+ fail_with_error 422, 'JSON_PARSE_ERROR', 'The JSON payload cannot be parsed'
43
+ end
44
+ else
45
+ @payload = nil
46
+ end
47
+
48
+ # CORS
49
+ content_type 'application/json; charset=utf-8'
50
+ response.headers['Access-Control-Allow-Origin'] = '*'
51
+ response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
52
+ end
53
+
54
+ def logged_in?
55
+ @logged_in
56
+ end
57
+
58
+ def add_error(code, message, reference = nil)
59
+ @errors = [] if @errors.nil?
60
+
61
+ error = {
62
+ :code => code,
63
+ :message => message,
64
+ }
65
+ error[:reference] = reference unless reference.nil?
66
+ @errors.push error
67
+ end
68
+
69
+ def fail_with_error(status, code, message, reference = nil)
70
+ add_error code,message,reference
71
+ fail_with_errors status
72
+ end
73
+
74
+ def fail_with_errors(status = 422)
75
+ halt status, JSON.fast_generate({
76
+ :success => false,
77
+ :errors => @errors
78
+ })
79
+ end
80
+
81
+ def fail_not_found
82
+ fail_with_error 404, 'NOT_FOUND','The resource cannot be found.'
83
+ end
84
+
85
+ def fail_unauthorized
86
+ fail_with_error 401, 'UNAUTHORIZED','Authorization is required to perform this operation on the resource.'
87
+ end
88
+
89
+ def fail_forbidden
90
+ fail_with_error 403, 'FORBIDDEN','The user is not allowed to perform this operation on the resource.'
91
+ end
92
+
93
+ not_found do
94
+ fail_not_found
95
+ end
96
+
97
+ error do
98
+ fail_with_error 500, 'INTERNAL_ERROR','The server has encountered an unknown error.'
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+
3
+ module JsonCrudApi
4
+ class AuthClient
5
+
6
+ attr_accessor :redis, :session_ttl, :prefix
7
+
8
+ def initialize(options)
9
+ @redis = options[:redis_client]
10
+ @session_ttl = options[:session_ttl]
11
+ @prefix = options[:key_prefix]
12
+ end
13
+
14
+ def get(key)
15
+ key = get_redis_key(key)
16
+ data = @redis.get(key)
17
+ return nil if data.nil?
18
+ touch(key)
19
+ JSON.parse(data, :symbolize_names => true)
20
+ end
21
+
22
+ def delete(key)
23
+ key = get_redis_key(key)
24
+ return false unless @redis.exists(key)
25
+ @redis.del(key)
26
+ true
27
+ end
28
+
29
+ def touch(key)
30
+ key = get_redis_key(key)
31
+ return false unless @redis.exists(key)
32
+ @redis.expire(key, @session_ttl)
33
+ true
34
+ end
35
+
36
+ def get_redis_key(key)
37
+ return key.to_s if @prefix.nil?
38
+ @prefix.to_s+key.to_s
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,71 @@
1
+ module JsonCrudApi
2
+ module Crud
3
+
4
+ def crud_api(url, key, options = [])
5
+
6
+ unless options.include? :disable_read
7
+
8
+ unless options.include? :disable_get_all
9
+ get url do
10
+ service = settings.services[key]
11
+ presenter = settings.presenters[key]
12
+ fail_unauthorized unless service.user_authorized_for? :get_all
13
+ entities = service.get_all
14
+ fail_not_found if entities.nil?
15
+
16
+ JSON.fast_generate settings.presenters[key].render(entities)
17
+ end
18
+ end
19
+
20
+ unless options.include? :disable_get
21
+ get url+"/:id" do
22
+ service = settings.services[key]
23
+ presenter = settings.presenters[key]
24
+ fail_unauthorized unless service.user_authorized_for? :get
25
+ entity = service.get(params["id"])
26
+ fail_not_found if entity.nil?
27
+
28
+ JSON.fast_generate settings.presenters[key].render(entity)
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ unless options.include? :disable_write
35
+
36
+ unless options.include? :disable_post
37
+ post url do
38
+ service = settings.services[key]
39
+ presenter = settings.presenters[key]
40
+ fail_unauthorized 'create' unless service.user_authorized_for? :create
41
+ entity = service.create(presenter.parse(@payload))
42
+
43
+ JSON.fast_generate settings.presenters[key].render(entity)
44
+ end
45
+ end
46
+
47
+ unless options.include? :disable_put
48
+ put url+"/:id" do
49
+ service = settings.services[key]
50
+ presenter = settings.presenters[key]
51
+ fail_unauthorized 'update' unless service.user_authorized_for? :update
52
+ fail_not_found unless service.update(params["id"], presenter.parse(@payload))
53
+ entity = service.get(params["id"])
54
+ JSON.fast_generate settings.presenters[key].render(entity)
55
+ end
56
+ end
57
+
58
+ unless options.include? :disable_delete
59
+ delete url+"/:id" do
60
+ service = settings.services[key]
61
+ presenter = settings.presenters[key]
62
+ fail_unauthorized 'delete' unless service.user_authorized_for? :delete
63
+ fail_not_found unless service.delete(params["id"])
64
+ 204
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,85 @@
1
+ require 'rubygems'
2
+
3
+ module JsonCrudApi
4
+ class Service
5
+
6
+ attr_accessor :log_service, :repo, :user, :scope_map, :user_scopes
7
+
8
+ def initialize(options)
9
+ @log_service = options[:log_service]
10
+ @repo = options[:repository]
11
+ @scope_map = options[:scope_map]
12
+ @user = nil
13
+ @user_scopes = nil
14
+ end
15
+
16
+ # Create a record with the given attributes
17
+ def create(params)
18
+ @repo.create(params)
19
+ end
20
+
21
+ # Determine if a record with the given id exists
22
+ def exists?(id)
23
+ @repo.all(:id => id).count > 0
24
+ end
25
+
26
+ # Get all records
27
+ def get_all
28
+ @repo.all
29
+ end
30
+
31
+ # Get the first record with the given id
32
+ def get(id)
33
+ @repo.first(:id => id)
34
+ end
35
+
36
+ # Update a record with the given id with the given attributes
37
+ # Returns false if the record does not exist.
38
+ def update(id, params)
39
+ record = get(id)
40
+ return false if record.nil?
41
+
42
+ record.update(params)
43
+ end
44
+
45
+ # Delete a record with the given id
46
+ # Returns false if the record does not exist.
47
+ def delete(id)
48
+ record = get(id)
49
+ return false if record.nil?
50
+
51
+ record.destroy
52
+ end
53
+
54
+ # Set the current user
55
+ def set_user(user)
56
+ @user = user
57
+ set_user_scopes(user[:scopes]) unless @user.nil?
58
+ end
59
+
60
+ # Set the current user scopes
61
+ def set_user_scopes(user_scopes)
62
+ @user_scopes = user_scopes
63
+ end
64
+
65
+ # Determine if the current user is authorized for the given operation
66
+ def user_authorized_for?(operation)
67
+ # Auth is disabled if scope map is nil
68
+ return true if @scope_map.nil?
69
+ # Auth succeeds if there is no map for this operation
70
+ return true if @scope_map[operation].nil?
71
+ # Auth fails if user is not logged in
72
+ return false if @user.nil?
73
+ # Auth fails if user has no scopes
74
+ return false if @user_scopes.nil? or @user_scopes.empty?
75
+
76
+ if @scope_map[operation].is_a?(Array)
77
+ # Auth succeeds if the intersection of allowed scopes and mapped scopes is non-empty.
78
+ return !((@scope_map[operation] & @user_scopes).empty?)
79
+ end
80
+
81
+ # Auth succeeds if the mapped scope is singular and the user posesses it
82
+ @user_scopes.include?(@scope_map[operation])
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,12 @@
1
+ require "coveralls"
2
+ Coveralls.wear!
3
+ SimpleCov.coverage_dir('spec/coverage')
4
+
5
+ require "dotenv"
6
+ Dotenv.load
7
+
8
+ require "json-crud-api"
9
+
10
+ RSpec.configure do |c|
11
+ c.include Helpers
12
+ end
@@ -0,0 +1,3 @@
1
+ module Helpers
2
+ # Spec helpers here
3
+ end
@@ -0,0 +1,101 @@
1
+ require "helper"
2
+
3
+ describe JsonCrudApi::AuthClient do
4
+ before(:each) do
5
+ @mock_redis = double('redis')
6
+
7
+ @client = JsonCrudApi::AuthClient.new({
8
+ :redis_client => @mock_redis,
9
+ :session_ttl => 200,
10
+ :key_prefix => 789
11
+ })
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'should inject dependencies correctly' do
16
+ @client.redis.should be @mock_redis
17
+ @client.session_ttl.should be 200
18
+ @client.prefix.should be 789
19
+ end
20
+ end
21
+
22
+ describe '#get' do
23
+ it 'should call get_redis_key and redis get' do
24
+ @client.should_receive(:get_redis_key).with('one')
25
+ @mock_redis.should_receive(:get).and_return nil
26
+ @client.get('one')
27
+ end
28
+
29
+ it 'should return nil if redis get return nil' do
30
+ @mock_redis.should_receive(:get).and_return nil
31
+ @client.get('one').should be nil
32
+ end
33
+
34
+ it 'should call touch if redis get is non nil' do
35
+ @mock_redis.should_receive(:get).and_return '{}'
36
+ @client.should_receive(:touch).with('789one')
37
+ @client.get('one')
38
+ end
39
+
40
+ it 'should parse JSON from redis get' do
41
+ @mock_redis.should_receive(:get).and_return '{"five":5}'
42
+ @client.should_receive(:touch).with('789one')
43
+ @client.get('one').should eq({ :five => 5 })
44
+ end
45
+ end
46
+
47
+ describe '#delete' do
48
+ it 'should call get_redis_key and redis exists and return false if exists is false' do
49
+ @client.should_receive(:get_redis_key).with('one')
50
+ @mock_redis.should_receive(:exists).and_return false
51
+ @client.delete('one').should be false
52
+ end
53
+
54
+ it 'should call redis del and return true if redis exists is true' do
55
+ @mock_redis.should_receive(:exists).and_return true
56
+ @mock_redis.should_receive(:del).with('789one')
57
+ @client.delete('one').should be true
58
+ end
59
+ end
60
+
61
+ describe '#touch' do
62
+ it 'should call get_redis_key and redis exists and return false if exists is false' do
63
+ @client.should_receive(:get_redis_key).with('one')
64
+ @mock_redis.should_receive(:exists).and_return false
65
+ @client.touch('one').should be false
66
+ end
67
+
68
+ it 'should call redis expire and return true if redis exists is true' do
69
+ @mock_redis.should_receive(:exists).and_return true
70
+ @mock_redis.should_receive(:expire).with('789one', 200)
71
+ @client.touch('one').should be true
72
+ end
73
+ end
74
+
75
+ describe '#get_redis_key' do
76
+ it 'should return key if prefix is nil' do
77
+ @client.prefix = nil
78
+ @client.get_redis_key('one').should eq 'one'
79
+ end
80
+
81
+ it 'should return key.to_s if prefix is nil' do
82
+ @client.prefix = nil
83
+ @client.get_redis_key(1).should eq '1'
84
+ end
85
+
86
+ it 'should return prefix plus key if prefix is not nil' do
87
+ @client.prefix = 'pre-'
88
+ @client.get_redis_key('one').should eq 'pre-one'
89
+ end
90
+
91
+ it 'should return prefix plus key.to_s if prefix is not nil' do
92
+ @client.prefix = 'post-'
93
+ @client.get_redis_key(1).should eq 'post-1'
94
+ end
95
+
96
+ it 'should return prefix.to_s plus key.to_s if prefix is not nil' do
97
+ @client.prefix = 5
98
+ @client.get_redis_key(1).should eq '51'
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,219 @@
1
+ require "helper"
2
+
3
+ describe JsonCrudApi::Service do
4
+ before(:each) do
5
+ @mock_repo = double('repo')
6
+ @mock_log = double('Log')
7
+ @mock_map = double('Map')
8
+
9
+ @service = JsonCrudApi::Service.new({
10
+ :log_service => @mock_log,
11
+ :repository => @mock_repo,
12
+ :scope_map => @mock_map
13
+ })
14
+ end
15
+
16
+ describe '#initialize' do
17
+ it 'should inject dependencies correctly' do
18
+ @service.log_service.should be @mock_log
19
+ @service.repo.should be @mock_repo
20
+ @service.scope_map.should be @mock_map
21
+ end
22
+
23
+ it 'should initialize user and scopes to nil' do
24
+ @service.user.should be nil
25
+ @service.user_scopes.should be nil
26
+ end
27
+ end
28
+
29
+ describe '#create' do
30
+ it 'should call create on repo with params' do
31
+ params = { :one => 'one', :two => 'two' }
32
+ @mock_repo.should_receive(:create).with(params).and_return(2)
33
+ @service.create(params).should eq 2
34
+ end
35
+ end
36
+
37
+ describe '#exists?' do
38
+ it 'should call all on repo with correct id' do
39
+ query_object = OpenStruct.new :count => 1
40
+ @mock_repo.should_receive(:all).with(:id => 3)
41
+ .and_return(query_object)
42
+ @service.exists?(3).should eq true
43
+ end
44
+
45
+ it 'should return false when count is zero' do
46
+ query_object = OpenStruct.new :count => 0
47
+ @mock_repo.should_receive(:all).with(:id => 3)
48
+ .and_return(query_object)
49
+ @service.exists?(3).should eq false
50
+ end
51
+
52
+ it 'should return true when count is one' do
53
+ query_object = OpenStruct.new :count => 1
54
+ @mock_repo.should_receive(:all).with(:id => 3)
55
+ .and_return(query_object)
56
+ @service.exists?(3).should eq true
57
+ end
58
+
59
+ it 'should return true when count is more than one' do
60
+ query_object = OpenStruct.new :count => 2
61
+ @mock_repo.should_receive(:all).with(:id => 3)
62
+ .and_return(query_object)
63
+ @service.exists?(3).should eq true
64
+ end
65
+ end
66
+
67
+ describe '#get_all' do
68
+ it 'should call all on repo and return output' do
69
+ @mock_repo.should_receive(:all).with().and_return(67)
70
+ @service.get_all.should eq 67
71
+ end
72
+ end
73
+
74
+ describe '#get' do
75
+ it 'should call first on repo with correct id and return result' do
76
+ @mock_repo.should_receive(:first).with({:id=>8}).and_return(123)
77
+ @service.get(8).should eq 123
78
+ end
79
+ end
80
+
81
+ describe '#update' do
82
+ it 'should call get on service with correct id' do
83
+ @service.should_receive(:get).with(5).and_return(nil)
84
+ @service.update(5,nil)
85
+ end
86
+
87
+ it 'should return false if get returns nil' do
88
+ @service.should_receive(:get).with(5).and_return(nil)
89
+ @service.update(5,nil).should eq false
90
+ end
91
+
92
+ it 'should call update on record with correct params' do
93
+ params = { :one => 'one', :two => 'two' }
94
+ record = double('entity')
95
+ @service.should_receive(:get).with(5)
96
+ .and_return(record)
97
+ record.should_receive(:update).with(params)
98
+ .and_return(789)
99
+ @service.update(5,params).should eq 789
100
+ end
101
+ end
102
+
103
+ describe '#delete' do
104
+ it 'should call get on service with correct id' do
105
+ @service.should_receive(:get).with(5).and_return(nil)
106
+ @service.delete(5)
107
+ end
108
+
109
+ it 'should return false if get returns nil' do
110
+ @service.should_receive(:get).with(5).and_return(nil)
111
+ @service.delete(5).should eq false
112
+ end
113
+
114
+ it 'should call delete on record' do
115
+ record = double('entity')
116
+ @service.should_receive(:get).with(5)
117
+ .and_return(record)
118
+ record.should_receive(:destroy).and_return(109)
119
+ @service.delete(5).should eq 109
120
+ end
121
+ end
122
+
123
+ describe '#set_user' do
124
+ it 'should set user in service to param' do
125
+ @service.set_user(nil)
126
+ @service.user.should eq nil
127
+ end
128
+
129
+ it 'should not call set_user_scopes if user is nil' do
130
+ @service.should_not_receive(:set_user_scopes)
131
+ @service.set_user(nil)
132
+ @service.user.should eq nil
133
+ end
134
+
135
+ it 'should call set_user_scopes if user is not' do
136
+ user = { :scopes => [1,2] }
137
+ @service.should_receive(:set_user_scopes).with([1,2])
138
+ @service.set_user(user)
139
+ @service.user.should eq user
140
+ end
141
+ end
142
+
143
+ describe '#set_user_scopes' do
144
+ it 'should set user_scopes in service to param' do
145
+ @service.set_user_scopes(nil)
146
+ @service.user_scopes.should eq nil
147
+
148
+ @service.set_user_scopes(234234)
149
+ @service.user_scopes.should eq 234234
150
+ end
151
+ end
152
+
153
+ describe '#user_authorized_for?' do
154
+ it 'should return true if scope_map is nil' do
155
+ @service.scope_map = nil
156
+ @service.user_authorized_for?(:one).should be true
157
+ end
158
+
159
+ it 'should return true if scope_map is not nil but no map for operation' do
160
+ @service.scope_map = { :two => 'TWO' }
161
+ @service.user_authorized_for?(:one).should be true
162
+ end
163
+
164
+ it 'should return false if user is nil' do
165
+ @service.scope_map = { :two => 'TWO' }
166
+ @service.user = nil
167
+ @service.user_authorized_for?(:two).should be false
168
+ end
169
+
170
+ it 'should return false if user has nil scopes' do
171
+ @service.scope_map = { :two => 'TWO' }
172
+ @service.user = { :name => "Tom" }
173
+ @service.user_scopes = nil
174
+ @service.user_authorized_for?(:two).should be false
175
+ end
176
+
177
+ it 'should return false if user has empty scopes' do
178
+ @service.scope_map = { :two => 'TWO' }
179
+ @service.user = { :name => "Tom" }
180
+ @service.user_scopes = []
181
+ @service.user_authorized_for?(:two).should be false
182
+ end
183
+
184
+ it 'should return true if scope map exists in user scopes' do
185
+ @service.scope_map = { :two => 'FIVE'}
186
+ @service.user = { :name => "Tom" }
187
+ @service.user_scopes = [ 'ONE', 'TWO', 'FIVE']
188
+ @service.user_authorized_for?(:two).should be true
189
+ end
190
+
191
+ it 'should return false if scope map does not exist in user scopes' do
192
+ @service.scope_map = { :two => 'SEVEN'}
193
+ @service.user = { :name => "Tom" }
194
+ @service.user_scopes = [ 'ONE', 'TWO', 'FIVE']
195
+ @service.user_authorized_for?(:two).should be false
196
+ end
197
+
198
+ it 'should return true if scope map is array and shares one scope with user' do
199
+ @service.scope_map = { :two => ['TWO'] }
200
+ @service.user = { :name => "Tom" }
201
+ @service.user_scopes = [ 'ONE', 'TWO', 'THREE']
202
+ @service.user_authorized_for?(:two).should be true
203
+ end
204
+
205
+ it 'should return true if scope map is array and shares more than one scope with user' do
206
+ @service.scope_map = { :two => ['TWO','THREE'] }
207
+ @service.user = { :name => "Tom" }
208
+ @service.user_scopes = [ 'ONE', 'TWO', 'THREE']
209
+ @service.user_authorized_for?(:two).should be true
210
+ end
211
+
212
+ it 'should return false if scope map is array and does not share scopes with user' do
213
+ @service.scope_map = { :two => ['FOUR'] }
214
+ @service.user = { :name => "Tom" }
215
+ @service.user_scopes = [ 'ONE', 'TWO', 'THREE']
216
+ @service.user_authorized_for?(:two).should be false
217
+ end
218
+ end
219
+ end
metadata ADDED
@@ -0,0 +1,240 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json-crud-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tom Cully
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: coveralls
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-mocks
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dalli
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 2.6.4
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: 2.6.4
107
+ type: :runtime
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ~>
112
+ - !ruby/object:Gem::Version
113
+ version: 2.6.4
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: 2.6.4
117
+ - !ruby/object:Gem::Dependency
118
+ name: json
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ~>
122
+ - !ruby/object:Gem::Version
123
+ version: 1.8.0
124
+ - - '>='
125
+ - !ruby/object:Gem::Version
126
+ version: 1.8.0
127
+ type: :runtime
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 1.8.0
134
+ - - '>='
135
+ - !ruby/object:Gem::Version
136
+ version: 1.8.0
137
+ - !ruby/object:Gem::Dependency
138
+ name: mysql2
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ~>
142
+ - !ruby/object:Gem::Version
143
+ version: 0.3.13
144
+ - - '>='
145
+ - !ruby/object:Gem::Version
146
+ version: 0.3.13
147
+ type: :runtime
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ~>
152
+ - !ruby/object:Gem::Version
153
+ version: 0.3.13
154
+ - - '>='
155
+ - !ruby/object:Gem::Version
156
+ version: 0.3.13
157
+ - !ruby/object:Gem::Dependency
158
+ name: sinatra
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ~>
162
+ - !ruby/object:Gem::Version
163
+ version: 1.4.3
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: 1.4.3
167
+ type: :runtime
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: 1.4.3
174
+ - - '>='
175
+ - !ruby/object:Gem::Version
176
+ version: 1.4.3
177
+ - !ruby/object:Gem::Dependency
178
+ name: datamapper
179
+ requirement: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ~>
182
+ - !ruby/object:Gem::Version
183
+ version: 1.2.0
184
+ - - '>='
185
+ - !ruby/object:Gem::Version
186
+ version: 1.2.0
187
+ type: :runtime
188
+ prerelease: false
189
+ version_requirements: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ~>
192
+ - !ruby/object:Gem::Version
193
+ version: 1.2.0
194
+ - - '>='
195
+ - !ruby/object:Gem::Version
196
+ version: 1.2.0
197
+ description: A set of classes to simplify JSON APIs
198
+ email: tomhughcully@gmail.com
199
+ executables: []
200
+ extensions: []
201
+ extra_rdoc_files: []
202
+ files:
203
+ - lib/json-crud-api/api.rb
204
+ - lib/json-crud-api/auth_client.rb
205
+ - lib/json-crud-api/crud.rb
206
+ - lib/json-crud-api/service.rb
207
+ - lib/json-crud-api.rb
208
+ - spec/helper.rb
209
+ - spec/helpers_spec.rb
210
+ - spec/unit/auth_client_spec.rb
211
+ - spec/unit/service_spec.rb
212
+ homepage: http://rubygems.org/gems/json-crud-api
213
+ licenses:
214
+ - MIT
215
+ metadata: {}
216
+ post_install_message:
217
+ rdoc_options: []
218
+ require_paths:
219
+ - lib
220
+ required_ruby_version: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - '>='
223
+ - !ruby/object:Gem::Version
224
+ version: 2.0.0
225
+ required_rubygems_version: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ requirements: []
231
+ rubyforge_project:
232
+ rubygems_version: 2.1.11
233
+ signing_key:
234
+ specification_version: 4
235
+ summary: Sinatra JSON API Framework Classes
236
+ test_files:
237
+ - spec/helper.rb
238
+ - spec/helpers_spec.rb
239
+ - spec/unit/auth_client_spec.rb
240
+ - spec/unit/service_spec.rb