restapi 0.0.3 → 0.0.4
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/Gemfile +2 -1
- data/Gemfile.lock +83 -64
- data/README.rdoc +375 -2
- data/app/controllers/restapi/restapis_controller.rb +21 -3
- data/app/helpers/restapi/restapis_helper.rb +31 -0
- data/app/public/restapi/javascripts/bundled/prettify.js +28 -0
- data/app/public/restapi/javascripts/restapi.js +4 -13
- data/app/public/restapi/stylesheets/bundled/prettify.css +30 -0
- data/app/views/layouts/restapi/restapi.html.erb +36 -0
- data/app/views/restapi/restapis/index.html.erb +35 -33
- data/app/views/restapi/restapis/method.html.erb +59 -0
- data/app/views/restapi/restapis/resource.html.erb +71 -0
- data/app/views/restapi/restapis/static.html.erb +103 -0
- data/lib/restapi.rb +0 -10
- data/lib/restapi/application.rb +25 -10
- data/lib/restapi/dsl_definition.rb +38 -32
- data/lib/restapi/markup.rb +12 -12
- data/lib/restapi/method_description.rb +10 -8
- data/lib/restapi/param_description.rb +23 -10
- data/lib/restapi/resource_description.rb +1 -1
- data/lib/restapi/restapi_module.rb +15 -0
- data/lib/restapi/validator.rb +37 -14
- data/lib/restapi/version.rb +1 -1
- data/lib/tasks/restapi.rake +157 -0
- data/restapi.gemspec +1 -1
- data/spec/controllers/restapis_controller_spec.rb +84 -0
- data/spec/controllers/users_controller_spec.rb +273 -221
- data/spec/dummy/app/controllers/twitter_example_controller.rb +209 -208
- data/spec/dummy/app/controllers/users_controller.rb +23 -33
- data/spec/dummy/config/initializers/restapi.rb +45 -23
- data/spec/dummy/config/routes.rb +12 -7
- metadata +26 -15
- data/app/public/restapi/javascripts/bundled/backbone.js +0 -1431
- data/app/public/restapi/javascripts/bundled/json2.js +0 -487
- data/app/public/restapi/javascripts/bundled/underscore.js +0 -999
- data/app/public/restapi/javascripts/jst.js +0 -127
- data/app/public/restapi/javascripts/routers/documentation_router.js +0 -52
- data/app/public/restapi/stylesheets/bundled/bootstrap-responsive.css +0 -686
- data/app/public/restapi/stylesheets/bundled/bootstrap.css +0 -3990
- data/spec/dummy/app/controllers/dogs_controller.rb +0 -20
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
data/lib/restapi.rb
CHANGED
@@ -1,13 +1,3 @@
|
|
1
|
-
require 'active_support/dependencies'
|
2
|
-
|
3
|
-
# add path to restapi controller to ActiveSupport paths
|
4
|
-
%w{ controllers views }.each do |dir|
|
5
|
-
path = File.join(File.dirname(__FILE__), 'app', dir)
|
6
|
-
$LOAD_PATH << path
|
7
|
-
ActiveSupport::Dependencies.autoload_paths << path
|
8
|
-
ActiveSupport::Dependencies.autoload_once_paths.delete(path)
|
9
|
-
end
|
10
|
-
|
11
1
|
require "restapi/routing"
|
12
2
|
require "restapi/markup"
|
13
3
|
require "restapi/restapi_module"
|
data/lib/restapi/application.rb
CHANGED
@@ -11,7 +11,7 @@ module Restapi
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
attr_accessor :last_api_args, :last_errors, :last_params, :last_description
|
14
|
+
attr_accessor :last_api_args, :last_errors, :last_params, :last_description, :last_examples
|
15
15
|
attr_reader :method_descriptions, :resource_descriptions
|
16
16
|
|
17
17
|
def initialize
|
@@ -46,8 +46,12 @@ module Restapi
|
|
46
46
|
Restapi::ResourceDescription.new(controller, resource_name, &block)
|
47
47
|
end
|
48
48
|
|
49
|
-
def add_method_description_args(
|
50
|
-
@last_api_args << MethodDescription::Api.new(
|
49
|
+
def add_method_description_args(method, path, desc)
|
50
|
+
@last_api_args << MethodDescription::Api.new(method, path, desc)
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_example(example)
|
54
|
+
@last_examples << example.strip_heredoc
|
51
55
|
end
|
52
56
|
|
53
57
|
# check if there is some saved description
|
@@ -94,6 +98,7 @@ module Restapi
|
|
94
98
|
@last_errors = []
|
95
99
|
@last_params = []
|
96
100
|
@last_description = nil
|
101
|
+
@last_examples = []
|
97
102
|
end
|
98
103
|
|
99
104
|
# Return the current description, clearing it in the process.
|
@@ -120,6 +125,12 @@ module Restapi
|
|
120
125
|
@last_params.clear
|
121
126
|
params
|
122
127
|
end
|
128
|
+
|
129
|
+
def get_examples
|
130
|
+
examples = @last_examples.clone
|
131
|
+
@last_examples.clear
|
132
|
+
examples
|
133
|
+
end
|
123
134
|
|
124
135
|
def to_json(resource_name, method_name)
|
125
136
|
|
@@ -135,17 +146,21 @@ module Restapi
|
|
135
146
|
end
|
136
147
|
|
137
148
|
{
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
149
|
+
:docs => {
|
150
|
+
:name => Restapi.configuration.app_name,
|
151
|
+
:info => Restapi.configuration.app_info,
|
152
|
+
:copyright => Restapi.configuration.copyright,
|
153
|
+
:doc_url => "#{ENV["RAILS_RELATIVE_URL_ROOT"]}#{Restapi.configuration.doc_base_url}",
|
154
|
+
:api_url => Restapi.configuration.api_base_url,
|
155
|
+
:resources => _resources
|
145
156
|
}
|
146
157
|
}
|
147
158
|
end
|
148
159
|
|
160
|
+
def reload_documentation
|
161
|
+
Dir[Restapi.configuration.api_controllers_matcher].each {|f| load f}
|
162
|
+
end
|
163
|
+
|
149
164
|
private
|
150
165
|
|
151
166
|
def get_resource_name(klass)
|
@@ -3,32 +3,30 @@
|
|
3
3
|
module Restapi
|
4
4
|
|
5
5
|
# DSL is a module that provides #api, #error, #param, #error.
|
6
|
-
|
7
6
|
module DSL
|
8
7
|
|
9
8
|
private
|
10
|
-
|
9
|
+
|
11
10
|
# Describe whole resource
|
12
|
-
#
|
11
|
+
#
|
13
12
|
# Example:
|
14
13
|
# api :desc => "Show user profile", :path => "/users/", :version => '1.0 - 3.4.2012'
|
15
14
|
# param :id, Fixnum, :desc => "User ID", :required => true
|
16
15
|
# desc <<-EOS
|
17
16
|
# Long description...
|
18
17
|
# EOS
|
19
|
-
def resource_description(options = {}, &block)
|
18
|
+
def resource_description(options = {}, &block) #:doc:
|
19
|
+
Restapi.remove_resource_description(self)
|
20
20
|
Restapi.define_resource_description(self, &block) if block_given?
|
21
21
|
end
|
22
22
|
|
23
23
|
# Declare an api.
|
24
24
|
#
|
25
25
|
# Example:
|
26
|
-
# api :
|
27
|
-
# :path => "/resource_route",
|
28
|
-
# :method => "GET"
|
26
|
+
# api :GET, "/resource_route", "short description",
|
29
27
|
#
|
30
|
-
def api(
|
31
|
-
Restapi.add_method_description_args(
|
28
|
+
def api(method, path, desc = nil) #:doc:
|
29
|
+
Restapi.add_method_description_args(method, path, desc)
|
32
30
|
end
|
33
31
|
|
34
32
|
# Describe the next method.
|
@@ -39,7 +37,7 @@ module Restapi
|
|
39
37
|
# puts "hello world"
|
40
38
|
# end
|
41
39
|
#
|
42
|
-
def desc(description)
|
40
|
+
def desc(description) #:doc:
|
43
41
|
if Restapi.last_description
|
44
42
|
raise "Double method description."
|
45
43
|
end
|
@@ -47,6 +45,12 @@ module Restapi
|
|
47
45
|
end
|
48
46
|
alias :description :desc
|
49
47
|
|
48
|
+
# Show some example of what does the described
|
49
|
+
# method return.
|
50
|
+
def example(example) #:doc:
|
51
|
+
Restapi.add_example(example)
|
52
|
+
end
|
53
|
+
|
50
54
|
# Describe possible errors
|
51
55
|
#
|
52
56
|
# Example:
|
@@ -56,10 +60,10 @@ module Restapi
|
|
56
60
|
# puts "hello world"
|
57
61
|
# end
|
58
62
|
#
|
59
|
-
def error(args)
|
63
|
+
def error(args) #:doc:
|
60
64
|
Restapi.last_errors << Restapi::ErrorDescription.new(args)
|
61
65
|
end
|
62
|
-
|
66
|
+
|
63
67
|
# Describe method's parameter
|
64
68
|
#
|
65
69
|
# Example:
|
@@ -68,17 +72,17 @@ module Restapi
|
|
68
72
|
# puts greeting
|
69
73
|
# end
|
70
74
|
#
|
71
|
-
def param(param_name, *args, &block)
|
75
|
+
def param(param_name, *args, &block) #:doc:
|
72
76
|
Restapi.last_params << Restapi::ParamDescription.new(param_name, *args, &block)
|
73
77
|
end
|
74
|
-
|
78
|
+
|
75
79
|
# create method api and redefine newly added method
|
76
|
-
def method_added(method_name)
|
80
|
+
def method_added(method_name) #:doc:
|
77
81
|
|
78
82
|
super
|
79
|
-
|
83
|
+
|
80
84
|
return unless Restapi.restapi_provided?
|
81
|
-
|
85
|
+
|
82
86
|
# remove method description if exists and create new one
|
83
87
|
Restapi.remove_method_description(self, method_name)
|
84
88
|
description = Restapi.define_method_description(self, method_name)
|
@@ -86,30 +90,32 @@ module Restapi
|
|
86
90
|
# redefine method only if validation is turned on
|
87
91
|
if Restapi.configuration.validate == true
|
88
92
|
|
89
|
-
old_method = instance_method(method_name)
|
90
|
-
|
93
|
+
old_method = instance_method(method_name)
|
94
|
+
|
91
95
|
define_method(method_name) do |*args|
|
92
|
-
|
93
|
-
description.params.each do |_, param|
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
-
raise ArgumentError.new("Expecting #{param.name} parameter.")
|
98
|
-
end
|
99
|
-
|
100
|
-
# params validations
|
101
|
-
if params.has_key?(param.name)
|
102
|
-
param.validate(params[:"#{param.name}"])
|
103
|
-
end
|
97
|
+
if Restapi.configuration.validate == true
|
98
|
+
description.params.each do |_, param|
|
104
99
|
|
105
|
-
|
100
|
+
# check if required parameters are present
|
101
|
+
if param.required && !params.has_key?(param.name)
|
102
|
+
raise ArgumentError.new("Expecting #{param.name} parameter.")
|
103
|
+
end
|
104
|
+
|
105
|
+
# params validations
|
106
|
+
if params.has_key?(param.name)
|
107
|
+
param.validate(params[:"#{param.name}"])
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
106
112
|
|
107
113
|
# run the original method code
|
108
114
|
old_method.bind(self).call(*args)
|
109
115
|
end
|
110
116
|
|
111
117
|
end
|
112
|
-
|
118
|
+
|
113
119
|
end # def method_added
|
114
120
|
end # module DSL
|
115
121
|
end # module Restapi
|
data/lib/restapi/markup.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
1
|
module Restapi
|
2
|
-
|
2
|
+
|
3
3
|
module Markup
|
4
|
-
|
4
|
+
|
5
5
|
class RDoc
|
6
|
-
|
6
|
+
|
7
7
|
def initialize
|
8
8
|
require 'rdoc'
|
9
9
|
require 'rdoc/markup/to_html'
|
10
10
|
@rdoc ||= ::RDoc::Markup::ToHtml.new
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def to_html(text)
|
14
14
|
@rdoc.convert(text)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
class Markdown
|
20
|
-
|
20
|
+
|
21
21
|
def initialize
|
22
22
|
require 'redcarpet'
|
23
23
|
@redcarpet ||= ::Redcarpet::Markdown.new(::Redcarpet::Render::HTML.new)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def to_html(text)
|
27
27
|
@redcarpet.render(text)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
class Textile
|
33
|
-
|
33
|
+
|
34
34
|
def initialize
|
35
35
|
require 'RedCloth'
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def to_html(text)
|
39
39
|
RedCloth.new(text).to_html
|
40
40
|
end
|
@@ -7,10 +7,10 @@ module Restapi
|
|
7
7
|
|
8
8
|
attr_accessor :short_description, :api_url, :http_method
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@http_method =
|
12
|
-
@
|
13
|
-
@
|
10
|
+
def initialize(method, path, desc)
|
11
|
+
@http_method = method.to_s
|
12
|
+
@api_url = create_api_url(path)
|
13
|
+
@short_description = desc
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -21,7 +21,7 @@ module Restapi
|
|
21
21
|
|
22
22
|
end
|
23
23
|
|
24
|
-
attr_reader :errors, :full_description, :method, :resource, :apis
|
24
|
+
attr_reader :errors, :full_description, :method, :resource, :apis, :examples
|
25
25
|
|
26
26
|
def initialize(method, resource, app)
|
27
27
|
@method = method
|
@@ -33,6 +33,7 @@ module Restapi
|
|
33
33
|
@full_description = Restapi.markup_to_html(desc)
|
34
34
|
@errors = app.get_errors
|
35
35
|
@params_ordered = app.get_params
|
36
|
+
@examples = app.get_examples
|
36
37
|
|
37
38
|
parent = @resource.controller.superclass
|
38
39
|
if parent != ActionController::Base
|
@@ -66,7 +67,7 @@ module Restapi
|
|
66
67
|
[
|
67
68
|
ENV["RAILS_RELATIVE_URL_ROOT"],
|
68
69
|
Restapi.configuration.doc_base_url,
|
69
|
-
"
|
70
|
+
"/#{@resource._id}/#{@method}"
|
70
71
|
].join
|
71
72
|
end
|
72
73
|
|
@@ -74,7 +75,7 @@ module Restapi
|
|
74
75
|
@apis.each.collect do |api|
|
75
76
|
{
|
76
77
|
:api_url => api.api_url,
|
77
|
-
:http_method => api.http_method,
|
78
|
+
:http_method => api.http_method.to_s,
|
78
79
|
:short_description => api.short_description
|
79
80
|
}
|
80
81
|
end
|
@@ -87,7 +88,8 @@ module Restapi
|
|
87
88
|
:apis => method_apis_to_json,
|
88
89
|
:full_description => @full_description,
|
89
90
|
:errors => @errors,
|
90
|
-
:params => params_ordered.map(&:to_json).flatten
|
91
|
+
:params => params_ordered.map(&:to_json).flatten,
|
92
|
+
:examples => @examples
|
91
93
|
}
|
92
94
|
end
|
93
95
|
|
@@ -1,17 +1,17 @@
|
|
1
1
|
module Restapi
|
2
2
|
|
3
3
|
# method parameter description
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# name - method name (show)
|
6
6
|
# desc - description
|
7
7
|
# required - boolean if required
|
8
8
|
# validator - Validator::BaseValidator subclass
|
9
9
|
class ParamDescription
|
10
10
|
|
11
|
-
attr_reader :name, :desc, :required, :validator
|
11
|
+
attr_reader :name, :desc, :required, :allow_nil, :validator
|
12
12
|
|
13
13
|
attr_accessor :parent
|
14
|
-
|
14
|
+
|
15
15
|
def initialize(name, *args, &block)
|
16
16
|
|
17
17
|
if args.size > 1 || !args.first.is_a?(Hash)
|
@@ -20,20 +20,21 @@ module Restapi
|
|
20
20
|
validator_type = nil
|
21
21
|
end
|
22
22
|
options = args.pop || {}
|
23
|
-
|
23
|
+
|
24
24
|
@name = name
|
25
25
|
@desc = Restapi.markup_to_html(options[:desc] || '')
|
26
26
|
@required = options[:required] || false
|
27
|
-
|
27
|
+
@allow_nil = options[:allow_nil] || false
|
28
|
+
|
28
29
|
@validator = nil
|
29
30
|
unless validator_type.nil?
|
30
|
-
@validator =
|
31
|
-
Validator::BaseValidator.find(self, validator_type, options, block)
|
31
|
+
@validator = Validator::BaseValidator.find(self, validator_type, options, block)
|
32
32
|
raise "Validator not found." unless validator
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def validate(value)
|
37
|
+
return true if @allow_nil && value.nil?
|
37
38
|
unless @validator.valid?(value)
|
38
39
|
raise ArgumentError.new(@validator.error)
|
39
40
|
end
|
@@ -57,13 +58,25 @@ module Restapi
|
|
57
58
|
|
58
59
|
def to_json
|
59
60
|
if validator.is_a? Restapi::Validator::HashValidator
|
60
|
-
|
61
|
+
{
|
62
|
+
:name => name.to_s,
|
63
|
+
:full_name => full_name,
|
64
|
+
:description => desc,
|
65
|
+
:required => required,
|
66
|
+
:allow_nil => allow_nil,
|
67
|
+
:validator => validator.to_s,
|
68
|
+
:expected_type => validator.expected_type,
|
69
|
+
:params => validator.hash_params_ordered.map(&:to_json)
|
70
|
+
}
|
61
71
|
else
|
62
72
|
{
|
63
|
-
:name =>
|
73
|
+
:name => name.to_s,
|
74
|
+
:full_name => full_name,
|
64
75
|
:description => desc,
|
65
76
|
:required => required,
|
66
|
-
:
|
77
|
+
:allow_nil => allow_nil,
|
78
|
+
:validator => validator.to_s,
|
79
|
+
:expected_type => validator.expected_type
|
67
80
|
}
|
68
81
|
end
|
69
82
|
end
|
@@ -56,7 +56,7 @@ module Restapi
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def doc_url
|
59
|
-
"#{ENV["RAILS_RELATIVE_URL_ROOT"]}#{Restapi.configuration.doc_base_url}
|
59
|
+
"#{ENV["RAILS_RELATIVE_URL_ROOT"]}#{Restapi.configuration.doc_base_url}/#{@_id}"
|
60
60
|
end
|
61
61
|
|
62
62
|
def api_url; "#{Restapi.configuration.api_base_url}#{@_path}"; end
|
@@ -28,6 +28,21 @@ module Restapi
|
|
28
28
|
class Configuration
|
29
29
|
attr_accessor :app_name, :app_info, :copyright, :markup,
|
30
30
|
:validate, :api_base_url, :doc_base_url
|
31
|
+
|
32
|
+
# matcher to be used in Dir.glob to find controllers to be reloaded e.g.
|
33
|
+
#
|
34
|
+
# "#{Rails.root}/app/controllers/api/*.rb"
|
35
|
+
attr_accessor :api_controllers_matcher
|
36
|
+
|
37
|
+
# set to true if you want to reload the controllers at each refresh of the
|
38
|
+
# documentation. It requires +:api_controllers_matcher+ to be set to work
|
39
|
+
# properly.
|
40
|
+
attr_writer :reload_controllers
|
41
|
+
|
42
|
+
def reload_controllers?
|
43
|
+
@reload_controllers = Rails.env.development? unless defined? @reload_controllers
|
44
|
+
return @reload_controllers && @api_controllers_matcher
|
45
|
+
end
|
31
46
|
|
32
47
|
def app_info
|
33
48
|
Restapi.markup_to_html(@app_info)
|