restivus 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/.DS_Store +0 -0
- data/.document +5 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +20 -0
- data/README.md +44 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/examples/banks/Gemfile +3 -0
- data/examples/banks/banklist.csv +451 -0
- data/examples/banks/config.ru +7 -0
- data/examples/banks/main.rb +8 -0
- data/lib/.DS_Store +0 -0
- data/lib/public/.DS_Store +0 -0
- data/lib/public/bootstrap.css +3352 -0
- data/lib/restivus.rb +131 -0
- data/lib/views/.DS_Store +0 -0
- data/lib/views/_sample_request.erb +6 -0
- data/lib/views/docs.erb +53 -0
- data/lib/views/layout.erb +58 -0
- data/test/helper.rb +18 -0
- data/test/test_restivus.rb +7 -0
- metadata +160 -0
data/lib/restivus.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'csv'
|
3
|
+
require 'uri'
|
4
|
+
require 'sinatra'
|
5
|
+
|
6
|
+
class Restivus < Sinatra::Base
|
7
|
+
|
8
|
+
# Doc helpers
|
9
|
+
# these methods generate text for the docs pages
|
10
|
+
# ------------
|
11
|
+
|
12
|
+
def curl_req(url)
|
13
|
+
`curl #{url}`
|
14
|
+
end
|
15
|
+
|
16
|
+
def format_curl_req(url, description="TODO", http="TODO", url_schema="TODO", div="TODO")
|
17
|
+
result = {
|
18
|
+
:cmd => "$ curl #{url}",
|
19
|
+
:raw_response => curl_req(url),
|
20
|
+
:pretty_response => JSON.pretty_generate(JSON.parse(curl_req(url))),
|
21
|
+
:description => description,
|
22
|
+
:http_verb => http,
|
23
|
+
:url_schema => url_schema,
|
24
|
+
:div_id => div
|
25
|
+
}
|
26
|
+
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def resource_name
|
31
|
+
self.class.name
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.fields
|
35
|
+
@@fields
|
36
|
+
end
|
37
|
+
|
38
|
+
# ----------
|
39
|
+
|
40
|
+
def self.csv(filename)
|
41
|
+
csv_data = CSV.read filename
|
42
|
+
headers = csv_data.shift.map {|i| i.to_s }
|
43
|
+
headers.map! {|h| h.gsub(" ", "_")}
|
44
|
+
@@fields = headers
|
45
|
+
string_data = csv_data.map {|row| row.map {|cell| cell.to_s } }
|
46
|
+
array_of_hashes = string_data.map {|row| Hash[*headers.zip(row).flatten] }
|
47
|
+
@@results = array_of_hashes
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.pk(key="id")
|
51
|
+
@@pk = key
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find(id)
|
55
|
+
where(@@pk => id.to_s).first
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.where(conditions={})
|
59
|
+
results = @@results.select do |result|
|
60
|
+
conditions.all? { |k,v| result[k] == v }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.all
|
65
|
+
@@results
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete_splat(params)
|
69
|
+
%w[splat captures resource].each {|w| params.delete(w)}
|
70
|
+
params
|
71
|
+
end
|
72
|
+
|
73
|
+
def base_uri
|
74
|
+
uri = "http://#{request.host}"
|
75
|
+
|
76
|
+
if request.port
|
77
|
+
uri << ":#{request.port}"
|
78
|
+
end
|
79
|
+
|
80
|
+
uri
|
81
|
+
end
|
82
|
+
|
83
|
+
get "/docs" do
|
84
|
+
@fields = self.class.fields
|
85
|
+
@base_uri = base_uri
|
86
|
+
@resource_name = resource_name
|
87
|
+
|
88
|
+
@sample_calls = []
|
89
|
+
#description="TODO", http="TODO", url_schema="TODO"
|
90
|
+
@sample_calls << get_index = format_curl_req("#{@base_uri}/#{@resource_name.downcase}", "Show all #{@resource_name} objects", "GET", "#{@base_uri}/#{@resource_name.downcase}", "index")
|
91
|
+
|
92
|
+
obj = self.class.all.first
|
93
|
+
pk_val = URI.encode(obj[@@pk])
|
94
|
+
|
95
|
+
@sample_calls << get_show = format_curl_req("#{@base_uri}/#{@resource_name.downcase}/#{pk_val}", "Show individual #{@resource_name} objects by #{@@pk}", "GET", "#{@base_uri}/#{@resource_name.downcase}/<#{@@pk}>", "show")
|
96
|
+
|
97
|
+
key = obj.keys.last
|
98
|
+
val = obj[key]
|
99
|
+
|
100
|
+
@sample_calls << get_find = format_curl_req("#{@base_uri}/#{@resource_name.downcase}?#{key}=#{val}", "Query #{@resource_name} objects based on parameters", "GET", "#{@base_uri}/#{@resource_name.downcase}?<param>=<value>", "find")
|
101
|
+
erb :docs
|
102
|
+
end
|
103
|
+
|
104
|
+
get "/:resource" do
|
105
|
+
content_type :json
|
106
|
+
case params.keys.length
|
107
|
+
when 0 # /:resource
|
108
|
+
{"results" => self.class.all}.to_json
|
109
|
+
else # /:resource?key=value&...
|
110
|
+
constraints = delete_splat(params)
|
111
|
+
{"results" => self.class.where(constraints)}.to_json
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
get "/:resource/:id" do
|
116
|
+
content_type :json
|
117
|
+
self.class.find(params[:id].to_s).to_json
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
# Usage:
|
123
|
+
|
124
|
+
#class Person < Restivus
|
125
|
+
# csv "example.csv"
|
126
|
+
#end
|
127
|
+
|
128
|
+
#class Bank < Restivus
|
129
|
+
# csv "banks.csv"
|
130
|
+
# pk "Bank_Name"
|
131
|
+
#end
|
data/lib/views/.DS_Store
ADDED
Binary file
|
data/lib/views/docs.erb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
<br /><br /><br />
|
2
|
+
<h2>REST API</h2>
|
3
|
+
|
4
|
+
<p>The REST API lets you interact with <%= @resource_name %> objects using HTTP calls.</p>
|
5
|
+
|
6
|
+
<h3>Quick Reference</h3>
|
7
|
+
|
8
|
+
<table class="table">
|
9
|
+
<thead>
|
10
|
+
<tr>
|
11
|
+
<th>URL</th>
|
12
|
+
<th>HTTP Verb</th>
|
13
|
+
<th>Functionality</th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
<tbody>
|
17
|
+
<% @sample_calls.each do |call| %>
|
18
|
+
<tr>
|
19
|
+
<td><%= call[:url_schema] %></td>
|
20
|
+
<td><%= call[:http_verb] %>
|
21
|
+
<td>
|
22
|
+
<a href="#<%= call[:div_id] %>">
|
23
|
+
<%= call[:description] %>
|
24
|
+
</a>
|
25
|
+
</td>
|
26
|
+
</tr>
|
27
|
+
<% end %>
|
28
|
+
</tbody>
|
29
|
+
</table>
|
30
|
+
|
31
|
+
<div id="fields" class="span7">
|
32
|
+
<h3>Fields</h3>
|
33
|
+
|
34
|
+
<p>The following are the valid fields of <%= @resource_name %> objects:</p>
|
35
|
+
<ul>
|
36
|
+
<% @fields.each do |field| %>
|
37
|
+
<li><%= field %></li>
|
38
|
+
<% end %>
|
39
|
+
</ul>
|
40
|
+
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<% @sample_calls.each do |call| %>
|
44
|
+
<%= erb :_sample_request, :locals => {:sample => call} %>
|
45
|
+
<% end %>
|
46
|
+
|
47
|
+
|
48
|
+
<div class="span6">
|
49
|
+
<footer class="footer">
|
50
|
+
<p class="pull-right"><a href="#">Back to top</a></p>
|
51
|
+
|
52
|
+
</footer>
|
53
|
+
</div>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title><%= @resource_name %> REST API Documentation</title>
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
7
|
+
|
8
|
+
<meta name="viewport"
|
9
|
+
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
10
|
+
<meta name="description" content="">
|
11
|
+
<meta name="author" content="">
|
12
|
+
<!--<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css">-->
|
13
|
+
<link href="/bootstrap.css" rel="stylesheet">
|
14
|
+
<link href="/bootstrap-responsive.css" rel="stylesheet">
|
15
|
+
|
16
|
+
<script type="text/javascript">
|
17
|
+
window.addEventListener("load",function() {
|
18
|
+
// Set a timeout...
|
19
|
+
setTimeout(function(){
|
20
|
+
// Hide the address bar!
|
21
|
+
window.scrollTo(0, 1);
|
22
|
+
}, 0);
|
23
|
+
});
|
24
|
+
|
25
|
+
</script
|
26
|
+
|
27
|
+
</head>
|
28
|
+
|
29
|
+
<body data-spy="scroll" data-target=".subnav" data-offset="100">
|
30
|
+
<div class="navbar navbar-fixed-top">
|
31
|
+
<div class="navbar-inner">
|
32
|
+
<div class="container">
|
33
|
+
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
34
|
+
<span class="i-bar"></span>
|
35
|
+
<span class="i-bar"></span>
|
36
|
+
<span class="i-bar"></span>
|
37
|
+
</a>
|
38
|
+
<a class="brand" href="/"><%= @resource_name %> Docs</a>
|
39
|
+
<div class="nav-collapse">
|
40
|
+
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div class="container">
|
47
|
+
|
48
|
+
<!-- Main hero unit for a primary marketing message or call to action -->
|
49
|
+
|
50
|
+
<%= yield %>
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
</div> <!-- /container -->
|
55
|
+
|
56
|
+
</body>
|
57
|
+
</html>
|
58
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'restivus'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: restivus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alan deLevie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-25 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sinatra
|
16
|
+
requirement: &70359564562260 !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: *70359564562260
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sinatra-respond_to
|
27
|
+
requirement: &70359564561380 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70359564561380
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: json
|
38
|
+
requirement: &70359564528980 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70359564528980
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: active_support
|
49
|
+
requirement: &70359564526800 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70359564526800
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: shoulda
|
60
|
+
requirement: &70359564525340 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70359564525340
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: &70359564522980 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.0.0
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70359564522980
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: jeweler
|
82
|
+
requirement: &70359564521340 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 1.6.4
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70359564521340
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rcov
|
93
|
+
requirement: &70359564519680 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70359564519680
|
102
|
+
description: Restivus eats CSV files and spits out fully-documented RESTful endpoints.
|
103
|
+
email: adelevie@gmail.com
|
104
|
+
executables: []
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files:
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.md
|
109
|
+
files:
|
110
|
+
- .DS_Store
|
111
|
+
- .document
|
112
|
+
- Gemfile
|
113
|
+
- Gemfile.lock
|
114
|
+
- LICENSE.txt
|
115
|
+
- README.md
|
116
|
+
- Rakefile
|
117
|
+
- VERSION
|
118
|
+
- examples/banks/Gemfile
|
119
|
+
- examples/banks/banklist.csv
|
120
|
+
- examples/banks/config.ru
|
121
|
+
- examples/banks/main.rb
|
122
|
+
- lib/.DS_Store
|
123
|
+
- lib/public/.DS_Store
|
124
|
+
- lib/public/bootstrap.css
|
125
|
+
- lib/restivus.rb
|
126
|
+
- lib/views/.DS_Store
|
127
|
+
- lib/views/_sample_request.erb
|
128
|
+
- lib/views/docs.erb
|
129
|
+
- lib/views/layout.erb
|
130
|
+
- test/helper.rb
|
131
|
+
- test/test_restivus.rb
|
132
|
+
homepage: http://github.com/adelevie/restivus
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
hash: 1920547086008092273
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 1.8.10
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: REST APIs for the rest of us.
|
160
|
+
test_files: []
|