restapi 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/Gemfile CHANGED
@@ -1,15 +1,12 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem "rails", "3.0.11"
4
- gem "capybara", ">= 0.4.0"
5
4
  gem "sqlite3"
6
5
 
7
6
  group :development, :test do
8
7
  gem "rspec-rails"
9
- gem "ZenTest"
10
- gem "rcov"
8
+ #gem "rcov"
9
+ gem "redcarpet"
10
+ gem "RedCloth"
11
+ gem "rake"
11
12
  end
12
-
13
- # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
14
- #gem 'ruby-debug'
15
- # gem 'ruby-debug19'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- ZenTest (4.6.2)
4
+ RedCloth (4.2.9)
5
5
  abstract (1.0.0)
6
6
  actionmailer (3.0.11)
7
7
  actionpack (= 3.0.11)
@@ -31,19 +31,9 @@ GEM
31
31
  activesupport (3.0.11)
32
32
  arel (2.0.10)
33
33
  builder (2.1.2)
34
- capybara (1.1.2)
35
- mime-types (>= 1.16)
36
- nokogiri (>= 1.3.3)
37
- rack (>= 1.0.0)
38
- rack-test (>= 0.5.4)
39
- selenium-webdriver (~> 2.0)
40
- xpath (~> 0.1.4)
41
- childprocess (0.3.1)
42
- ffi (~> 1.0.6)
43
34
  diff-lcs (1.1.3)
44
35
  erubis (2.6.6)
45
36
  abstract (>= 1.0.0)
46
- ffi (1.0.11)
47
37
  i18n (0.5.0)
48
38
  json (1.6.5)
49
39
  mail (2.2.19)
@@ -52,8 +42,6 @@ GEM
52
42
  mime-types (~> 1.16)
53
43
  treetop (~> 1.4.8)
54
44
  mime-types (1.17.2)
55
- multi_json (1.0.4)
56
- nokogiri (1.5.0)
57
45
  polyglot (0.3.3)
58
46
  rack (1.2.5)
59
47
  rack-mount (0.6.14)
@@ -75,9 +63,9 @@ GEM
75
63
  rdoc (~> 3.4)
76
64
  thor (~> 0.14.4)
77
65
  rake (0.9.2.2)
78
- rcov (1.0.0)
79
66
  rdoc (3.12)
80
67
  json (~> 1.4)
68
+ redcarpet (2.1.1)
81
69
  rspec (2.8.0)
82
70
  rspec-core (~> 2.8.0)
83
71
  rspec-expectations (~> 2.8.0)
@@ -91,28 +79,20 @@ GEM
91
79
  activesupport (>= 3.0)
92
80
  railties (>= 3.0)
93
81
  rspec (~> 2.8.0)
94
- rubyzip (0.9.6.1)
95
- selenium-webdriver (2.19.0)
96
- childprocess (>= 0.2.5)
97
- ffi (~> 1.0.9)
98
- multi_json (~> 1.0.4)
99
- rubyzip
100
82
  sqlite3 (1.3.5)
101
83
  thor (0.14.6)
102
84
  treetop (1.4.10)
103
85
  polyglot
104
86
  polyglot (>= 0.3.1)
105
87
  tzinfo (0.3.31)
106
- xpath (0.1.4)
107
- nokogiri (~> 1.3)
108
88
 
109
89
  PLATFORMS
110
90
  ruby
111
91
 
112
92
  DEPENDENCIES
113
- ZenTest
114
- capybara (>= 0.4.0)
93
+ RedCloth
115
94
  rails (= 3.0.11)
116
- rcov
95
+ rake
96
+ redcarpet
117
97
  rspec-rails
118
98
  sqlite3
data/README.rdoc CHANGED
@@ -0,0 +1,3 @@
1
+ = Rails API documentation generator
2
+
3
+ {<img src="https://secure.travis-ci.org/Pajk/rails-restapi.png?branch=master" alt="Build Status" />}[http://travis-ci.org/Pajk/rails-restapi]
@@ -4,21 +4,12 @@ module Restapi
4
4
 
5
5
  def index
6
6
  respond_to do |format|
7
- format.json { render :json => Restapi.to_json(params[:resource], params[:method]) }
7
+ format.json do
8
+ render :json => Restapi.to_json(params[:resource], params[:method])
9
+ end
8
10
  format.html
9
11
  end
10
12
  end
11
13
 
12
- protected
13
-
14
- helper_method :restapi_javascript_src
15
- def restapi_javascript_src(file)
16
- "#{Restapi.configuration.doc_base_url}/javascripts/#{file}"
17
- end
18
-
19
- helper_method :restapi_stylesheet_src
20
- def restapi_stylesheet_src(file)
21
- "#{Restapi.configuration.doc_base_url}/stylesheets/#{file}"
22
- end
23
14
  end
24
15
  end
@@ -9,11 +9,13 @@ Restapi.Templates.Index = _.template(
9
9
  <thead><tr><th>Resource</th><th>Description</th></tr></thead> \
10
10
  <tbody> \
11
11
  <% _.each(api.methods, function(m) { %> \
12
- <tr> \
13
- <td><a href='<%= m.doc_url %>'><%= m.http_method %> <%= m.api_url %></a></td> \
14
- <td width='60%'><%= m['short_description'] %></td> \
15
- </tr> \
16
- <% }) %> \
12
+ <% _.each(m.apis, function(api) { %> \
13
+ <tr> \
14
+ <td><a href='<%= m.doc_url %>'><%= api.http_method %> <%= api.api_url %></a></td> \
15
+ <td width='60%'><%= api.short_description %></td> \
16
+ </tr> \
17
+ <% }) %>\
18
+ <% }) %> \
17
19
  </tbody> \
18
20
  </table> \
19
21
  <% }) %>");
@@ -29,30 +31,38 @@ Restapi.Templates.Resource = _.template(
29
31
  <div><%= resource.full_description %></div> \
30
32
  <% } %> \
31
33
  <div class='accordion' id='accordion'> \
32
- <% _.each(resource.methods, function(api) { %> \
34
+ <% _.each(resource.methods, function(m) { %> \
33
35
  <hr><div class=''> \
34
- <div class='pull-right small'><a href='<%= api.doc_url %>'> >>> </a></div> \
36
+ <div class='pull-right small'><a href='<%= m.doc_url %>'> >>> </a></div> \
35
37
  <div> \
36
- <a href='#description-<%= api.name %>' class='accordion-toggle' data-toggle='collapse' data-parent='#accordion'> \
37
- <h3><%= api.http_method %> <%= api.api_url %></a><br> \
38
- <small><%= api.short_description %></small></h3>\
38
+ <% _.each(m.apis, function(api) { %> \
39
+ <h3> \
40
+ <a href='#description-<%= m.name %>' \
41
+ class='accordion-toggle' \
42
+ data-toggle='collapse' \
43
+ data-parent='#accordion'> \
44
+ <%= api.http_method %> <%= api.api_url %> \
45
+ </a> <br> \
46
+ <small><%= api.short_description %></small> \
47
+ </h3> \
48
+ <% }) %> \
39
49
  </div> \
40
- <div id='description-<%= api.name %>' class='collapse accordion-body'> \
41
- <%= api.full_description %> \
42
- <% if(api.errors != '') { %> \
50
+ <div id='description-<%= m.name %>' class='collapse accordion-body'> \
51
+ <%= m.full_description %> \
52
+ <% if(m.errors != '') { %> \
43
53
  <h2>Errors</h2> \
44
- <% _.each(api.errors, function(err) { %> \
54
+ <% _.each(m.errors, function(err) { %> \
45
55
  <%= err.code %> \
46
56
  <%= err.description %> \
47
57
  <br> \
48
58
  <% }) %> \
49
59
  <% } %> \
50
- <% if(api.params != ''){ %> \
60
+ <% if(m.params != ''){ %> \
51
61
  <h2>Params</h2> \
52
62
  <table class='table'> \
53
63
  <thead><tr><th>Param name</th><th>Description</th></tr></thead> \
54
64
  <tbody> \
55
- <% _.each(api.params, function(val) { %> \
65
+ <% _.each(m.params, function(val) { %> \
56
66
  <tr><td><strong><%= val.name %></strong><br>\
57
67
  <small><%= val.required ? 'required' : 'optional' %></small></td> \
58
68
  <td><%= val.description %><br>\
@@ -68,13 +78,22 @@ Restapi.Templates.Resource = _.template(
68
78
 
69
79
  Restapi.Templates.Method = _.template(
70
80
  "<ul class='breadcrumb'> \
71
- <li><a href='<%= docs.doc_url %>'><%= docs.name %></a><span class='divider'>/</span></li> \
72
- <li><a href='<%= resource.doc_url %>'><%= resource.name %></a><span class='divider'>/</span></li> \
81
+ <li> \
82
+ <a href='<%= docs.doc_url %>'><%= docs.name %></a> \
83
+ <span class='divider'>/</span> \
84
+ </li> \
85
+ <li> \
86
+ <a href='<%= resource.doc_url %>'><%= resource.name %></a> \
87
+ <span class='divider'>/</span> \
88
+ </li> \
73
89
  <li class='active'><%= method.name %></li> \
74
90
  </ul> \
75
- <div class='page-header'><h1><%= method.http_method %> <%= method.api_url %><br> \
76
- <small><%= method.short_description %></small></h1> \
77
- </div> \
91
+ <% _.each(method.apis, function(api) { %> \
92
+ <div class='page-header'> \
93
+ <h1><%= api.http_method %> <%= api.api_url %><br> \
94
+ <small><%= api.short_description %></small></h1> \
95
+ </div> \
96
+ <% }) %> \
78
97
  <div> \
79
98
  <%= method.full_description %> \
80
99
  <% if(method.errors != '') { %> \
@@ -105,4 +124,4 @@ Restapi.Templates.Method = _.template(
105
124
  </tbody> \
106
125
  </table> \
107
126
  <% } %> \
108
- </div>");
127
+ </div>");
@@ -1,14 +1,13 @@
1
1
  var Restapi = {
2
2
  Routers: {},
3
3
  Templates: {},
4
+ Rendered: false,
4
5
 
5
6
  init: function() {
6
7
  new Restapi.Routers.Documentation();
7
- var base = '/' + window.location.pathname.split('/')[1];
8
- Backbone.history.start({pushState: true, root: base});
9
- },
10
-
11
- baseurl: function() { return document.location.toString().replace(/#.*/,""); }
8
+ var base = window.location.pathname;
9
+ Backbone.history.start({root: base});
10
+ }
12
11
  };
13
12
 
14
13
  $(document).ready(function() {
@@ -11,21 +11,25 @@ Restapi.Routers.Documentation = Backbone.Router.extend({
11
11
  },
12
12
 
13
13
  index: function() {
14
- this.render('index');
14
+ var url = window.location.pathname + '.json';
15
+ this.render('index', url);
15
16
  },
16
17
 
17
18
  resource: function(resource) {
18
- this.render('resource');
19
+ var url = [window.location.pathname, resource + '.json'].join('/');
20
+ this.render('resource', url);
19
21
  },
20
22
 
21
23
  method: function(resource, method) {
22
- this.render('method');
24
+ var url = [window.location.pathname, resource, method +'.json'].join('/');
25
+ this.render('method', url);
23
26
  },
24
27
 
25
- render: function(type) {
26
- this.data = $.getJSON(window.location.pathname + '.json', function(data) {
27
- $('#api-title').html(data.docs.name).attr('href', data.docs.doc_url);
28
- $('footer').html(data.docs.copyright);
28
+ render: function(type, url) {
29
+ this.data = $.getJSON(url, function(data) {
30
+ if(!Restapi.rendered) {
31
+ $('footer').html(data.docs.copyright);
32
+ }
29
33
 
30
34
  var html = '';
31
35
  if (type == 'index') {
@@ -40,7 +44,8 @@ Restapi.Routers.Documentation = Backbone.Router.extend({
40
44
  });
41
45
  }
42
46
 
43
- $("#container").append(html);
47
+ $("#container").html(html);
48
+ Restapi.rendered = true;
44
49
  });
45
50
  }
46
51
 
data/lib/restapi.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  require 'active_support/dependencies'
2
- require 'rdoc'
3
- require 'rdoc/markup/to_html'
4
2
 
5
3
  # add path to restapi controller to ActiveSupport paths
6
4
  %w{ controllers views }.each do |dir|
@@ -11,6 +9,7 @@ require 'rdoc/markup/to_html'
11
9
  end
12
10
 
13
11
  require "restapi/routing"
12
+ require "restapi/markup"
14
13
  require "restapi/restapi_module"
15
14
  require "restapi/method_description"
16
15
  require "restapi/resource_description"
@@ -1,4 +1,3 @@
1
- require 'ostruct'
2
1
  require 'restapi/static_dispatcher'
3
2
 
4
3
  module Restapi
@@ -23,37 +22,38 @@ module Restapi
23
22
  end
24
23
 
25
24
  # create new method api description
26
- def define_method_description(resource_name, method_name)
27
- resource_name = get_resource_name(resource_name)
28
-
29
- puts "defining api for #{resource_name}:#{method_name}"
30
-
25
+ def define_method_description(controller, method_name)
31
26
  # create new or get existing api
27
+ resource_name = get_resource_name(controller)
32
28
  key = [resource_name, method_name].join('#')
33
- @method_descriptions[key] ||= Restapi::MethodDescription.new(method_name, resource_name, self)
29
+ # add method description key to resource description
30
+ resource = define_resource_description(controller)
34
31
 
35
- # add mapi key to resource api
36
- define_resource_description(resource_name).add_method(key)
32
+ method_description = Restapi::MethodDescription.new(method_name, resource, self)
33
+
34
+ @method_descriptions[key] ||= method_description
37
35
 
38
36
  @method_descriptions[key]
39
37
  end
40
38
 
41
39
  # create new resource api description
42
- def define_resource_description(resource_name, &block)
43
- resource_name = get_resource_name(resource_name)
40
+ def define_resource_description(controller, &block)
41
+ resource_name = get_resource_name(controller)
44
42
 
45
- @resource_descriptions[resource_name] ||= Restapi::ResourceDescription.new(resource_name, &block)
43
+ # puts "defining api for #{resource_name}"
44
+
45
+ @resource_descriptions[resource_name] ||=
46
+ Restapi::ResourceDescription.new(controller, resource_name, &block)
47
+ end
48
+
49
+ def add_method_description_args(args)
50
+ @last_api_args << MethodDescription::Api.new(args)
46
51
  end
47
52
 
48
53
  # check if there is some saved description
49
54
  def restapi_provided?
50
55
  true unless last_api_args.blank?
51
56
  end
52
-
53
- # List of all the apis defined in the given scope (and its sub-scopes).
54
- # def mapis_for_resource(resource_name)
55
- # @method_descriptions.select { |key,val| key.first == controller_name }
56
- # end
57
57
 
58
58
  # get api for given method
59
59
  def get_method_description(resource_name, method_name)
@@ -90,9 +90,9 @@ module Restapi
90
90
 
91
91
  # clear all saved data
92
92
  def clear_last
93
- @last_api_args = nil
94
- @last_errors = Array.new
95
- @last_params = Hash.new
93
+ @last_api_args = []
94
+ @last_errors = []
95
+ @last_params = []
96
96
  @last_description = nil
97
97
  end
98
98
 
@@ -124,7 +124,12 @@ module Restapi
124
124
  def to_json(resource_name, method_name)
125
125
 
126
126
  _resources = if resource_name.blank?
127
- resource_descriptions.collect { |_,v| v.to_json }
127
+ # take just resources which have some methods because
128
+ # we dont want to show eg ApplicationController as resource
129
+ resource_descriptions.inject({}) do |result, (k,v)|
130
+ result[k] = v.to_json unless v._methods.blank?
131
+ result
132
+ end
128
133
  else
129
134
  [@resource_descriptions[resource_name].to_json(method_name)]
130
135
  end
@@ -134,7 +139,7 @@ module Restapi
134
139
  'name' => Restapi.configuration.app_name,
135
140
  'info' => Restapi.configuration.app_info,
136
141
  'copyright' => Restapi.configuration.copyright,
137
- 'doc_url' => Restapi.configuration.doc_base_url,
142
+ 'doc_url' => "#{ENV["RAILS_RELATIVE_URL_ROOT"]}#{Restapi.configuration.doc_base_url}",
138
143
  'api_url' => Restapi.configuration.api_base_url,
139
144
  'resources' => _resources
140
145
  }
@@ -146,7 +151,7 @@ module Restapi
146
151
  def get_resource_name(klass)
147
152
  if klass.class == String
148
153
  klass
149
- elsif klass.class == Class && klass.ancestors.include?(ActionController::Base)
154
+ elsif klass.class == Class && ActionController::Base.descendants.include?(klass)
150
155
  klass.controller_name
151
156
  end
152
157
  end
@@ -2,8 +2,7 @@
2
2
 
3
3
  module Restapi
4
4
 
5
- # DSL is a module that provides #api, #error, #param, #error. Use this
6
- # when you'd like to use restapi outside the top level scope.
5
+ # DSL is a module that provides #api, #error, #param, #error.
7
6
 
8
7
  module DSL
9
8
 
@@ -29,7 +28,7 @@ module Restapi
29
28
  # :method => "GET"
30
29
  #
31
30
  def api(args)
32
- Restapi.last_api_args = args
31
+ Restapi.add_method_description_args(args)
33
32
  end
34
33
 
35
34
  # Describe the next method.
@@ -70,7 +69,7 @@ module Restapi
70
69
  # end
71
70
  #
72
71
  def param(param_name, *args, &block)
73
- Restapi.last_params[param_name.to_sym] = Restapi::ParamDescription.new(param_name, *args, &block)
72
+ Restapi.last_params << Restapi::ParamDescription.new(param_name, *args, &block)
74
73
  end
75
74
 
76
75
  # create method api and redefine newly added method
@@ -80,12 +79,9 @@ module Restapi
80
79
 
81
80
  return unless Restapi.restapi_provided?
82
81
 
83
- method_name = method_name.to_sym
84
- resource_name = self.controller_name
85
-
86
- # remove mapi if exists and create new one
87
- Restapi.remove_method_description(resource_name, method_name)
88
- mapi = Restapi.define_method_description(resource_name, method_name)
82
+ # remove method description if exists and create new one
83
+ Restapi.remove_method_description(self, method_name)
84
+ description = Restapi.define_method_description(self, method_name)
89
85
 
90
86
  # redefine method only if validation is turned on
91
87
  if Restapi.configuration.validate == true
@@ -94,7 +90,7 @@ module Restapi
94
90
 
95
91
  define_method(method_name) do |*args|
96
92
 
97
- mapi.params.each do |_, param|
93
+ description.params.each do |_, param|
98
94
 
99
95
  # check if required parameters are present
100
96
  if param.required && !params.has_key?(param.name)
@@ -116,4 +112,4 @@ module Restapi
116
112
 
117
113
  end # def method_added
118
114
  end # module DSL
119
- end # module Restapi
115
+ end # module Restapi