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/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}/&lt;#{@@pk}&gt;", "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}?&lt;param&gt;=&lt;value&gt;", "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
Binary file
@@ -0,0 +1,6 @@
1
+ <div id="<%= sample[:div_id] %>" class="span7">
2
+ <h3><%= sample[:description] %></h3>
3
+ <pre><%= sample[:cmd]%></pre>
4
+ <p>Response (prettified):</p>
5
+ <pre><%= sample[:pretty_response] %></pre>
6
+ </div>
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestRestivus < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ 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: []