hovercraft 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.
- data/.gitignore +17 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/hovercraft.gemspec +29 -0
- data/lib/hovercraft/actions.rb +47 -0
- data/lib/hovercraft/builder.rb +39 -0
- data/lib/hovercraft/caller.rb +29 -0
- data/lib/hovercraft/loader.rb +41 -0
- data/lib/hovercraft/server.rb +14 -0
- data/lib/hovercraft/version.rb +3 -0
- data/lib/hovercraft.rb +2 -0
- data/spec/hovercraft/actions_spec.rb +158 -0
- data/spec/hovercraft/builder_spec.rb +60 -0
- data/spec/hovercraft/caller_spec.rb +28 -0
- data/spec/hovercraft/loader_spec.rb +23 -0
- data/spec/hovercraft/server_spec.rb +7 -0
- metadata +173 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 vanstee
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Hovercraft
|
2
|
+
|
3
|
+
Generate a RESTful API from a directory of ActiveRecord models.
|
4
|
+
|
5
|
+
## Get Up and Running
|
6
|
+
|
7
|
+
1. Throw this in your Gemfile:
|
8
|
+
|
9
|
+
`gem 'hovercraft'`
|
10
|
+
|
11
|
+
2. Put your ActiveRecord models in `models/` (make sure the file names
|
12
|
+
are the same as the class names).
|
13
|
+
|
14
|
+
3. Create a rackup file that generates the application:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
run Hovercraft::Server.new
|
18
|
+
```
|
19
|
+
|
20
|
+
4. Run the application like normal:
|
21
|
+
|
22
|
+
`bundle exec rackup`
|
23
|
+
|
24
|
+
## Give Back
|
25
|
+
|
26
|
+
1. Fork it
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
28
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
30
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/hovercraft.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/hovercraft/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['vanstee']
|
6
|
+
gem.email = ['vanstee@highgroove.com']
|
7
|
+
gem.description = %q{Generate a RESTful API from a directory of ActiveRecord models}
|
8
|
+
gem.summary = %q{There's a lot of boiler plate code that goes into
|
9
|
+
creating an API so why not just generate all that code
|
10
|
+
from the models. Just throw your models in a models
|
11
|
+
directory and call the server from the rackup file and
|
12
|
+
you have yourself a perfect API.}
|
13
|
+
gem.homepage = ''
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
16
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = `git ls-files -- spec/*`.split("\n")
|
18
|
+
gem.name = 'hovercraft'
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
gem.version = Hovercraft::VERSION
|
21
|
+
|
22
|
+
gem.add_dependency 'sinatra-activerecord'
|
23
|
+
gem.add_dependency 'rack-contrib'
|
24
|
+
|
25
|
+
gem.add_development_dependency 'rspec'
|
26
|
+
gem.add_development_dependency 'pry'
|
27
|
+
gem.add_development_dependency 'rake'
|
28
|
+
gem.add_development_dependency 'rack-test'
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module Hovercraft
|
4
|
+
module Actions
|
5
|
+
def generate_index(model_class, model_name, plural_model_name)
|
6
|
+
get("/#{plural_model_name}.:format") do
|
7
|
+
model_instances = model_class.all
|
8
|
+
status 200
|
9
|
+
model_instances.to_json
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_create(model_class, model_name, plural_model_name)
|
14
|
+
post("/#{plural_model_name}.:format") do
|
15
|
+
model_instance = model_class.create(params[model_name.to_sym])
|
16
|
+
status model_instance.valid? ? 201 : 400
|
17
|
+
model_instance.to_json
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_show(model_class, model_name, plural_model_name)
|
22
|
+
get("/#{plural_model_name}/:id.:format") do
|
23
|
+
model_instance = model_class.find(params[:id])
|
24
|
+
status 200
|
25
|
+
model_instance.to_json
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_update(model_class, model_name, plural_model_name)
|
30
|
+
put("/#{plural_model_name}/:id.:format") do
|
31
|
+
model_instance = model_class.find(params[:id])
|
32
|
+
model_instance.update_attributes(params[model_name.to_sym])
|
33
|
+
status model_instance.valid? ? 204 : 400
|
34
|
+
model_instance.to_json
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_destroy(model_class, model_name, plural_model_name)
|
39
|
+
delete("/#{plural_model_name}/:id.:format") do
|
40
|
+
model_instance = model_class.find(params[:id])
|
41
|
+
model_instance.destroy
|
42
|
+
status 204
|
43
|
+
model_instance.to_json
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'hovercraft/loader'
|
2
|
+
require 'hovercraft/actions'
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'rack/contrib'
|
5
|
+
require 'forwardable'
|
6
|
+
|
7
|
+
module Hovercraft
|
8
|
+
class Builder
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def_delegator :@loader, :with_each_model
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@loader = Loader.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def application
|
18
|
+
application = Sinatra.new
|
19
|
+
application = configure(application)
|
20
|
+
application = generate_routes(application)
|
21
|
+
application
|
22
|
+
end
|
23
|
+
|
24
|
+
def configure(application)
|
25
|
+
application.register(Hovercraft::Actions)
|
26
|
+
application.use(Rack::PostBodyContentTypeParser)
|
27
|
+
application
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_routes(application)
|
31
|
+
with_each_model do |model_class, model_name, plural_model_name|
|
32
|
+
application.methods.grep(/generate/).each do |action|
|
33
|
+
application.send(action, model_class, model_name, plural_model_name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
application
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Hovercraft
|
2
|
+
class Caller
|
3
|
+
CALLERS_TO_IGNORE = [
|
4
|
+
/\/hovercraft(\/(caller|loader|builder|server))?\.rb$/, # hovercraft libary
|
5
|
+
/\/sinatra(\/(base|main|showexceptions))?\.rb$/, # sinatra library
|
6
|
+
/^\(.*\)$/, # generated code
|
7
|
+
/lib\/ruby/, # ruby core libraries
|
8
|
+
/rubygems\/custom_require\.rb$/, # rubygems require hacks
|
9
|
+
/active_support/, # active_support require hack
|
10
|
+
/bundler(\/runtime)?\.rb/, # bundler require hacks
|
11
|
+
/<internal:/, # internal in ruby >= 1.9.2
|
12
|
+
/src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
|
13
|
+
]
|
14
|
+
|
15
|
+
def directory
|
16
|
+
File.dirname(caller_file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def caller_file
|
20
|
+
cleaned_caller_files.first || $PROGRAM_NAME
|
21
|
+
end
|
22
|
+
|
23
|
+
def cleaned_caller_files
|
24
|
+
caller(1).map { |line| line.split(/:(?=\d|in )/, 3)[0, 1] }.
|
25
|
+
reject { |file, *_| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }.
|
26
|
+
flatten
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'hovercraft/caller'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
module Hovercraft
|
6
|
+
class Loader
|
7
|
+
def initialize
|
8
|
+
@caller = Caller.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def with_each_model
|
12
|
+
models.each do |model_class|
|
13
|
+
model_name = model_class.name.underscore
|
14
|
+
plural_model_name = model_name.pluralize
|
15
|
+
yield(model_class, model_name, plural_model_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def models
|
20
|
+
@models ||= require_models
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def require_models
|
26
|
+
Dir.glob(File.join(models_directory, '**/*.rb')).map do |file|
|
27
|
+
require file
|
28
|
+
class_from(file)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def models_directory
|
33
|
+
File.join(@caller.directory, 'models')
|
34
|
+
end
|
35
|
+
|
36
|
+
def class_from(file)
|
37
|
+
file.gsub!(/#{models_directory}|.rb/, '')
|
38
|
+
file.classify.safe_constantize
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/hovercraft.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'hovercraft/actions'
|
2
|
+
require 'rack/test'
|
3
|
+
|
4
|
+
describe Hovercraft::Actions do
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
let(:application) { Sinatra.new }
|
8
|
+
let(:model_name) { 'employee' }
|
9
|
+
let(:model_name_pluralize) { 'employees' }
|
10
|
+
let(:model_class) { Class.new }
|
11
|
+
|
12
|
+
let(:model) do
|
13
|
+
stub(
|
14
|
+
to_json:
|
15
|
+
'
|
16
|
+
{
|
17
|
+
"employee": {
|
18
|
+
"name": "Philip J. Fry",
|
19
|
+
"career": "Intergalactic Delivery Boy"
|
20
|
+
}
|
21
|
+
}
|
22
|
+
',
|
23
|
+
valid?: true,
|
24
|
+
update_attributes: self,
|
25
|
+
destroy: self
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:models) do
|
30
|
+
stub(
|
31
|
+
to_json:
|
32
|
+
'
|
33
|
+
[
|
34
|
+
{
|
35
|
+
"employee": {
|
36
|
+
"name": "Philip J. Fry",
|
37
|
+
"career": "Intergalactic Delivery Boy"
|
38
|
+
}
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"employee": {
|
42
|
+
"name": "John A. Zoidberg",
|
43
|
+
"career": "Physician"
|
44
|
+
}
|
45
|
+
]
|
46
|
+
'
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
alias :app :application
|
51
|
+
|
52
|
+
before do
|
53
|
+
application.register(Hovercraft::Actions)
|
54
|
+
|
55
|
+
model_class.stub(all: models, create: model, find: model)
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#generate_index' do
|
59
|
+
before do
|
60
|
+
application.generate_index(model_class, model_name, model_name_pluralize)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'generates a GET collection route' do
|
64
|
+
application.routes['GET'][0][0].should == %r{^/employees(?:\.|%2E)([^/?#]+)$}
|
65
|
+
application.routes['GET'][0][1].should == ['format']
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns a list of models' do
|
69
|
+
get '/employees.json'
|
70
|
+
|
71
|
+
last_response.status.should == 200
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#generate_create' do
|
76
|
+
before do
|
77
|
+
application.generate_create(model_class, model_name, model_name_pluralize)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'generates a POST collection route' do
|
81
|
+
application.routes['POST'][0][0].should == %r{^/employees(?:\.|%2E)([^/?#]+)$}
|
82
|
+
application.routes['POST'][0][1].should == ['format']
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'creates and returns a model' do
|
86
|
+
post '/employees.json', zoidberg: { occipation: 'doctor' }
|
87
|
+
|
88
|
+
last_response.status.should == 201
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'fails and returns an error' do
|
92
|
+
model.stub(valid?: false)
|
93
|
+
|
94
|
+
post '/employees.json', employee: { name: 'Bender Bending Rodriguez', career: 'Girder-bender' }
|
95
|
+
|
96
|
+
last_response.status.should == 400
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#generate_show' do
|
101
|
+
before do
|
102
|
+
application.generate_show(model_class, model_name, model_name_pluralize)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'generates a GET member route' do
|
106
|
+
application.routes['GET'][0][0].should == %r{^/employees/([^/?#]+)(?:\.|%2E)([^/?#]+)$}
|
107
|
+
application.routes['GET'][0][1].should == ['id', 'format']
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'returns a model' do
|
111
|
+
get '/employees/1.json'
|
112
|
+
|
113
|
+
last_response.status.should == 200
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#generate_update' do
|
118
|
+
before do
|
119
|
+
application.generate_update(model_class, model_name, model_name_pluralize)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'generates a PUT member route' do
|
123
|
+
application.routes['PUT'][0][0].should == %r{^/employees/([^/?#]+)(?:\.|%2E)([^/?#]+)$}
|
124
|
+
application.routes['PUT'][0][1].should == ['id', 'format']
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'updates and returns a model' do
|
128
|
+
put '/employees/1.json'
|
129
|
+
|
130
|
+
last_response.status.should == 204
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'fails and returns an error' do
|
134
|
+
model.stub(valid?: false)
|
135
|
+
|
136
|
+
put '/employees/1.json', employee: { career: 'Unemployed' }
|
137
|
+
|
138
|
+
last_response.status.should == 400
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#generate_destroy' do
|
143
|
+
before do
|
144
|
+
application.generate_destroy(model_class, model_name, model_name_pluralize)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'generates a DELETE member route' do
|
148
|
+
application.routes['DELETE'][0][0].should == %r{^/employees/([^/?#]+)(?:\.|%2E)([^/?#]+)$}
|
149
|
+
application.routes['DELETE'][0][1].should == ['id', 'format']
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'destroys and returns a model' do
|
153
|
+
delete '/employees/1.json'
|
154
|
+
|
155
|
+
last_response.status.should == 204
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'hovercraft/builder'
|
2
|
+
|
3
|
+
describe Hovercraft::Builder do
|
4
|
+
let(:model) { stub(name: 'Robot') }
|
5
|
+
let(:models) { Array.new(3) { model } }
|
6
|
+
let(:params) { models.map { |m| [m, 'robot', 'robots'] } }
|
7
|
+
|
8
|
+
before do
|
9
|
+
subject.stub(:with_each_model).
|
10
|
+
and_yield(*params[0]).
|
11
|
+
and_yield(*params[1]).
|
12
|
+
and_yield(*params[2])
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#application' do
|
16
|
+
it 'creates a sinatra application' do
|
17
|
+
subject.application.ancestors.should include(Sinatra::Base)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'configures the application' do
|
21
|
+
subject.should_receive(:configure)
|
22
|
+
|
23
|
+
subject.application
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'generates routes for the application' do
|
27
|
+
subject.should_receive(:generate_routes)
|
28
|
+
|
29
|
+
subject.application
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#configure' do
|
34
|
+
let(:application) { stub(register: nil, use: nil) }
|
35
|
+
|
36
|
+
it 'registers the methods to generate actions' do
|
37
|
+
application.should_receive(:register).with(Hovercraft::Actions)
|
38
|
+
|
39
|
+
subject.configure(application)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'uses a post body parsing middleware' do
|
43
|
+
application.should_receive(:use).with(Rack::PostBodyContentTypeParser)
|
44
|
+
|
45
|
+
subject.configure(application)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#generate_routes' do
|
50
|
+
let(:application) { stub }
|
51
|
+
|
52
|
+
it 'calls all generate methods for each model' do
|
53
|
+
[:index, :create, :show, :update, :destroy].each do |action|
|
54
|
+
application.should_receive("generate_#{action}").exactly(3).times
|
55
|
+
end
|
56
|
+
|
57
|
+
subject.generate_routes(application)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'hovercraft/caller'
|
2
|
+
|
3
|
+
describe Hovercraft::Caller do
|
4
|
+
describe '#directory' do
|
5
|
+
before { subject.stub(caller_file: '/gems/futurama/parallel_universe_box.rb:10 in `universe`') }
|
6
|
+
|
7
|
+
it 'returns the directory of the file at the top of the execution stack' do
|
8
|
+
subject.directory.should == '/gems/futurama'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#cleaned_caller_files' do
|
13
|
+
let(:files) do
|
14
|
+
[
|
15
|
+
'/gems/futurama/parallel_universe_box.rb:10 in `universe`',
|
16
|
+
'/gems/futurama/parallel_universe_box.rb:3 in `initialize`',
|
17
|
+
'<internal: (irb)'
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
before { subject.stub(caller: files) }
|
22
|
+
|
23
|
+
it 'returns a cleaned list of files on the execution stack' do
|
24
|
+
subject.cleaned_caller_files.should_not include('<internal: (irb)')
|
25
|
+
subject.cleaned_caller_files.should have(2).files
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'hovercraft/loader'
|
2
|
+
|
3
|
+
describe Hovercraft::Loader do
|
4
|
+
let(:model) { stub(name: 'Robot') }
|
5
|
+
let(:models) { Array.new(3) { model } }
|
6
|
+
let(:params) { models.map { |m| [m, 'robot', 'robots'] } }
|
7
|
+
|
8
|
+
describe '#with_each_model' do
|
9
|
+
before { subject.stub(models: models) }
|
10
|
+
|
11
|
+
it 'yields the class, name, and plural name of each model' do
|
12
|
+
expect { |b| subject.with_each_model(&b) }.to yield_successive_args(*params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#models' do
|
17
|
+
it 'is memoized' do
|
18
|
+
subject.should_receive(:require_models).once.and_return([])
|
19
|
+
|
20
|
+
2.times { subject.models }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hovercraft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- vanstee
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sinatra-activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rack-contrib
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rack-test
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Generate a RESTful API from a directory of ActiveRecord models
|
111
|
+
email:
|
112
|
+
- vanstee@highgroove.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- Gemfile
|
119
|
+
- LICENSE
|
120
|
+
- README.md
|
121
|
+
- Rakefile
|
122
|
+
- hovercraft.gemspec
|
123
|
+
- lib/hovercraft.rb
|
124
|
+
- lib/hovercraft/actions.rb
|
125
|
+
- lib/hovercraft/builder.rb
|
126
|
+
- lib/hovercraft/caller.rb
|
127
|
+
- lib/hovercraft/loader.rb
|
128
|
+
- lib/hovercraft/server.rb
|
129
|
+
- lib/hovercraft/version.rb
|
130
|
+
- spec/hovercraft/actions_spec.rb
|
131
|
+
- spec/hovercraft/builder_spec.rb
|
132
|
+
- spec/hovercraft/caller_spec.rb
|
133
|
+
- spec/hovercraft/loader_spec.rb
|
134
|
+
- spec/hovercraft/server_spec.rb
|
135
|
+
homepage: ''
|
136
|
+
licenses: []
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ! '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
segments:
|
148
|
+
- 0
|
149
|
+
hash: 2214615904925685358
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
152
|
+
requirements:
|
153
|
+
- - ! '>='
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
segments:
|
157
|
+
- 0
|
158
|
+
hash: 2214615904925685358
|
159
|
+
requirements: []
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 1.8.23
|
162
|
+
signing_key:
|
163
|
+
specification_version: 3
|
164
|
+
summary: There's a lot of boiler plate code that goes into creating an API so why
|
165
|
+
not just generate all that code from the models. Just throw your models in a models
|
166
|
+
directory and call the server from the rackup file and you have yourself a perfect
|
167
|
+
API.
|
168
|
+
test_files:
|
169
|
+
- spec/hovercraft/actions_spec.rb
|
170
|
+
- spec/hovercraft/builder_spec.rb
|
171
|
+
- spec/hovercraft/caller_spec.rb
|
172
|
+
- spec/hovercraft/loader_spec.rb
|
173
|
+
- spec/hovercraft/server_spec.rb
|