apipie-rails 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +5 -3
- data/README.rst +688 -0
- data/apipie-rails.gemspec +2 -4
- data/app/controllers/apipie/apipies_controller.rb +73 -41
- data/app/views/apipie/apipies/index.html.erb +10 -3
- data/app/views/apipie/apipies/method.html.erb +5 -2
- data/app/views/apipie/apipies/resource.html.erb +10 -3
- data/lib/apipie-rails.rb +1 -0
- data/lib/apipie/apipie_module.rb +28 -79
- data/lib/apipie/application.rb +194 -97
- data/lib/apipie/client/generator.rb +5 -4
- data/lib/apipie/configuration.rb +112 -0
- data/lib/apipie/dsl_definition.rb +93 -16
- data/lib/apipie/extractor.rb +12 -5
- data/lib/apipie/extractor/collector.rb +1 -1
- data/lib/apipie/extractor/recorder.rb +2 -1
- data/lib/apipie/extractor/writer.rb +11 -4
- data/lib/apipie/helpers.rb +15 -4
- data/lib/apipie/markup.rb +3 -4
- data/lib/apipie/method_description.rb +28 -22
- data/lib/apipie/resource_description.rb +44 -42
- data/lib/apipie/routing.rb +3 -1
- data/lib/apipie/static_dispatcher.rb +0 -1
- data/lib/apipie/version.rb +1 -1
- data/lib/generators/apipie/install/README +6 -0
- data/lib/generators/apipie/install/install_generator.rb +25 -0
- data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
- data/lib/tasks/apipie.rake +31 -39
- data/spec/controllers/api/v1/architectures_controller_spec.rb +30 -0
- data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
- data/spec/controllers/apipies_controller_spec.rb +18 -12
- data/spec/controllers/users_controller_spec.rb +56 -19
- data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
- data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +32 -0
- data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +32 -0
- data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
- data/spec/dummy/app/controllers/twitter_example_controller.rb +1 -1
- data/spec/dummy/app/controllers/users_controller.rb +2 -3
- data/spec/dummy/config/initializers/apipie.rb +29 -6
- data/spec/lib/method_description_spec.rb +29 -0
- data/spec/lib/param_description_spec.rb +41 -0
- data/spec/lib/resource_description_spec.rb +28 -0
- data/spec/spec_helper.rb +1 -1
- metadata +99 -164
- data/README.rdoc +0 -367
- data/lib/apipie/client/base.rb +0 -133
- data/lib/apipie/client/cli_command.rb +0 -130
- data/lib/apipie/client/main.rb +0 -101
- data/lib/apipie/client/rest_client_oauth.rb +0 -19
- data/lib/apipie/client/template/Gemfile.tt +0 -3
- data/lib/apipie/client/template/README.tt +0 -3
- data/lib/apipie/client/template/Rakefile.tt +0 -2
- data/lib/apipie/client/template/a_name.gemspec.tt +0 -23
- data/lib/apipie/client/template/bin/bin.rb.tt +0 -30
- data/lib/apipie/client/template/lib/a_name.rb.tt +0 -27
- data/lib/apipie/client/template/lib/a_name/commands/cli.rb.tt +0 -22
- data/lib/apipie/client/template/lib/a_name/config.yml +0 -6
- data/lib/apipie/client/template/lib/a_name/resources/resource.rb.tt +0 -22
- data/lib/apipie/client/template/lib/a_name/version.rb.tt +0 -3
- data/lib/apipie/client/thor.rb +0 -21
- data/rubygem-apipie-rails.spec +0 -122
- data/spec/lib/parameter_description_spec.rb +0 -41
data/apipie-rails.gemspec
CHANGED
@@ -16,13 +16,11 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
|
+
s.add_dependency "rails", ">= 3.0.10"
|
19
20
|
s.add_development_dependency "rspec-rails"
|
20
|
-
s.add_development_dependency "rails", ">= 3.0.10"
|
21
21
|
s.add_development_dependency "sqlite3"
|
22
22
|
s.add_development_dependency "minitest"
|
23
|
-
s.add_development_dependency "
|
23
|
+
s.add_development_dependency "maruku"
|
24
24
|
s.add_development_dependency "RedCloth"
|
25
25
|
s.add_development_dependency "rake"
|
26
|
-
s.add_development_dependency "rest-client"
|
27
|
-
s.add_development_dependency "oauth"
|
28
26
|
end
|
@@ -2,61 +2,39 @@ module Apipie
|
|
2
2
|
class ApipiesController < ActionController::Base
|
3
3
|
layout Apipie.configuration.layout
|
4
4
|
|
5
|
+
around_filter :set_script_name
|
6
|
+
|
5
7
|
def index
|
8
|
+
|
9
|
+
params[:version] ||= Apipie.configuration.default_version
|
10
|
+
|
11
|
+
get_format
|
12
|
+
|
6
13
|
respond_to do |format|
|
7
14
|
|
8
15
|
if Apipie.configuration.use_cache?
|
9
|
-
|
10
|
-
if [:resource, :method, :format].any? { |p| params[p].to_s =~ /\W/ }
|
11
|
-
head :bad_request and return
|
12
|
-
end
|
13
|
-
|
14
|
-
path << "/" << params[:resource] if params[:resource].present?
|
15
|
-
path << "/" << params[:method] if params[:method].present?
|
16
|
-
if params[:format].present?
|
17
|
-
path << ".#{params[:format]}"
|
18
|
-
else
|
19
|
-
path << ".html"
|
20
|
-
end
|
21
|
-
cache_file = File.join(Apipie.configuration.cache_dir, path)
|
22
|
-
if File.exists?(cache_file)
|
23
|
-
content_type = case params[:format]
|
24
|
-
when "json" then "application/json"
|
25
|
-
else "text/html"
|
26
|
-
end
|
27
|
-
send_file cache_file, :type => content_type, :disposition => "inline"
|
28
|
-
else
|
29
|
-
Rails.logger.error("API doc cache not found for '#{path}'. Perhaps you have forgot to run `rake apipie:cache`")
|
30
|
-
head :not_found
|
31
|
-
end
|
32
|
-
return
|
16
|
+
render_from_cache and return
|
33
17
|
end
|
34
18
|
|
35
19
|
Apipie.reload_documentation if Apipie.configuration.reload_controllers?
|
36
|
-
@doc = Apipie.to_json(params[:resource], params[:method])
|
20
|
+
@doc = Apipie.to_json(params[:version], params[:resource], params[:method])
|
37
21
|
|
38
22
|
format.json do
|
39
23
|
render :json => @doc
|
40
24
|
end
|
41
25
|
|
42
26
|
format.html do
|
43
|
-
|
27
|
+
@versions = Apipie.available_versions
|
44
28
|
@doc = @doc[:docs]
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@resource = @doc[:resources].first
|
55
|
-
if @resource == 'null'
|
56
|
-
render 'apipie_404', :status => 404
|
57
|
-
else
|
58
|
-
render 'resource'
|
59
|
-
end
|
29
|
+
@resource = @doc[:resources].first if params[:resource].present?
|
30
|
+
@method = @resource[:methods].first if params[:method].present?
|
31
|
+
|
32
|
+
if @resource && @method
|
33
|
+
render 'method'
|
34
|
+
elsif @resource
|
35
|
+
render 'resource'
|
36
|
+
elsif params[:resource].present? || params[:method].present?
|
37
|
+
render 'apipie_404', :status => 404
|
60
38
|
else
|
61
39
|
render 'index'
|
62
40
|
end
|
@@ -64,5 +42,59 @@ module Apipie
|
|
64
42
|
end
|
65
43
|
end
|
66
44
|
|
45
|
+
private
|
46
|
+
|
47
|
+
def get_format
|
48
|
+
params[:format] = :html unless params[:version].sub!('.html', '').nil?
|
49
|
+
params[:format] = :json unless params[:version].sub!('.json', '').nil?
|
50
|
+
request.format = params[:format] if params[:format]
|
51
|
+
end
|
52
|
+
|
53
|
+
def render_from_cache
|
54
|
+
path = Apipie.configuration.doc_base_url.dup
|
55
|
+
if [:resource, :method, :format].any? { |p| params[p].to_s =~ /\W/ }
|
56
|
+
head :bad_request and return
|
57
|
+
end
|
58
|
+
# version can contain dot, but only one in row
|
59
|
+
if params[:version].to_s.gsub(".", "") =~ /\W/ ||
|
60
|
+
params[:version].to_s =~ /\.\./
|
61
|
+
head :bad_request and return
|
62
|
+
end
|
63
|
+
|
64
|
+
path << "/" << params[:version] if params[:version].present?
|
65
|
+
path << "/" << params[:resource] if params[:resource].present?
|
66
|
+
path << "/" << params[:method] if params[:method].present?
|
67
|
+
if params[:format].present?
|
68
|
+
path << ".#{params[:format]}"
|
69
|
+
else
|
70
|
+
path << ".html"
|
71
|
+
end
|
72
|
+
|
73
|
+
# we sanitize the params before so in ideal case, this condition
|
74
|
+
# will be never satisfied. It's here for cases somebody adds new
|
75
|
+
# param into the path later and forgets about sanitation.
|
76
|
+
if path =~ /\.\./
|
77
|
+
head :bad_request and return
|
78
|
+
end
|
79
|
+
|
80
|
+
cache_file = File.join(Apipie.configuration.cache_dir, path)
|
81
|
+
if File.exists?(cache_file)
|
82
|
+
content_type = case params[:format]
|
83
|
+
when "json" then "application/json"
|
84
|
+
else "text/html"
|
85
|
+
end
|
86
|
+
send_file cache_file, :type => content_type, :disposition => "inline"
|
87
|
+
else
|
88
|
+
Rails.logger.error("API doc cache not found for '#{path}'. Perhaps you have forgot to run `rake apipie:cache`")
|
89
|
+
head :not_found
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_script_name
|
94
|
+
Apipie.request_script_name = request.env["SCRIPT_NAME"]
|
95
|
+
yield
|
96
|
+
ensure
|
97
|
+
Apipie.request_script_name = nil
|
98
|
+
end
|
67
99
|
end
|
68
100
|
end
|
@@ -1,14 +1,21 @@
|
|
1
1
|
<ul class='breadcrumb'>
|
2
|
-
<li class='active'><a href='<%= @doc[:doc_url] %>.html'><%= @doc[:name] %></a></li>
|
2
|
+
<li class='active'><a href='<%= @doc[:doc_url] %>.html'><%= @doc[:name] %> <%= @doc[:resources].values.first[:version] %></a></li>
|
3
|
+
<% if @versions && @versions.size > 1 %>
|
4
|
+
<li class='pull-right'>
|
5
|
+
<%= @versions.collect { |v| link_to v, Apipie.full_url(v) }.join(' / ').html_safe %>
|
6
|
+
</li>
|
7
|
+
<% end %>
|
3
8
|
</ul>
|
4
9
|
|
5
|
-
<div><%= @doc[:info]
|
10
|
+
<div><%= raw @doc[:info] %></div>
|
6
11
|
|
7
12
|
<h1 class='page-header'>Resources</h1>
|
8
13
|
|
9
14
|
<% @doc[:resources].sort_by(&:first).each do |key, api| %>
|
10
15
|
<h2>
|
11
|
-
<a href='<%= api[:doc_url] %>.html'
|
16
|
+
<a href='<%= api[:doc_url] %>.html'>
|
17
|
+
<%= api[:name] %>
|
18
|
+
</a><br>
|
12
19
|
<small><%= api[:short_description] %></small>
|
13
20
|
</h2>
|
14
21
|
<table class='table'>
|
@@ -1,10 +1,13 @@
|
|
1
1
|
<ul class='breadcrumb'>
|
2
2
|
<li>
|
3
|
-
<a href='<%= @doc[:doc_url] %>.html'><%= @doc[:name] %></a>
|
3
|
+
<a href='<%= @doc[:doc_url] %>.html'><%= @doc[:name] %> <%= @resource[:version] %></a>
|
4
4
|
<span class='divider'>/</span>
|
5
5
|
</li>
|
6
6
|
<li>
|
7
|
-
<a href='<%= @resource[:doc_url] %>.html'
|
7
|
+
<a href='<%= @resource[:doc_url] %>.html'>
|
8
|
+
<%= @resource[:name] %>
|
9
|
+
<% if @resource[:version] %><% end %>
|
10
|
+
</a>
|
8
11
|
<span class='divider'>/</span>
|
9
12
|
</li>
|
10
13
|
<li class='active'><%= @method[:name] %></li>
|
@@ -1,11 +1,18 @@
|
|
1
1
|
<ul class='breadcrumb'>
|
2
|
-
<li
|
3
|
-
|
2
|
+
<li>
|
3
|
+
<a href='<%= @doc[:doc_url] %>.html'><%= @doc[:name] %> <%= @resource[:version] %></a>
|
4
|
+
<span class='divider'>/</span>
|
5
|
+
</li>
|
6
|
+
<li class='active'>
|
7
|
+
<%= @resource[:name] %>
|
8
|
+
<% if @resource[:version] %><% end %>
|
9
|
+
</li>
|
4
10
|
</ul>
|
5
11
|
|
6
12
|
<div class='page-header'>
|
7
13
|
<h1>
|
8
|
-
<%= @resource[:name]
|
14
|
+
<%= @resource[:name] %>
|
15
|
+
<br>
|
9
16
|
<small><%= raw @resource[:short_description] %></small>
|
10
17
|
</h1>
|
11
18
|
</div>
|
data/lib/apipie-rails.rb
CHANGED
data/lib/apipie/apipie_module.rb
CHANGED
@@ -8,8 +8,9 @@ module Apipie
|
|
8
8
|
@application ||= Apipie::Application.new
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.to_json(resource_name = nil, method_name = nil)
|
12
|
-
|
11
|
+
def self.to_json(version = nil, resource_name = nil, method_name = nil)
|
12
|
+
version ||= Apipie.configuration.default_version
|
13
|
+
app.to_json(version, resource_name, method_name)
|
13
14
|
end
|
14
15
|
|
15
16
|
# all calls delegated to Apipie::Application instance
|
@@ -25,89 +26,37 @@ module Apipie
|
|
25
26
|
@configuration ||= Configuration.new
|
26
27
|
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
alias_method :validate?, :validate
|
33
|
-
alias_method :required_by_default?, :required_by_default
|
34
|
-
|
35
|
-
# matcher to be used in Dir.glob to find controllers to be reloaded e.g.
|
36
|
-
#
|
37
|
-
# "#{Rails.root}/app/controllers/api/*.rb"
|
38
|
-
attr_accessor :api_controllers_matcher
|
39
|
-
|
40
|
-
# set to true if you want to reload the controllers at each refresh of the
|
41
|
-
# documentation. It requires +:api_controllers_matcher+ to be set to work
|
42
|
-
# properly.
|
43
|
-
attr_writer :reload_controllers
|
44
|
-
|
45
|
-
def reload_controllers?
|
46
|
-
@reload_controllers = Rails.env.development? unless defined? @reload_controllers
|
47
|
-
return @reload_controllers && @api_controllers_matcher
|
48
|
-
end
|
49
|
-
|
50
|
-
# set to true if you want to use pregenerated documentation cache and avoid
|
51
|
-
# generating the documentation on runtime (usefull for production
|
52
|
-
# environment).
|
53
|
-
# You can generate the cache by running
|
54
|
-
#
|
55
|
-
# rake apipie:cache
|
56
|
-
attr_accessor :use_cache
|
57
|
-
alias_method :use_cache?, :use_cache
|
58
|
-
|
59
|
-
attr_writer :cache_dir
|
60
|
-
def cache_dir
|
61
|
-
@cache_dir ||= File.join(Rails.root, "public", "apipie-cache")
|
62
|
-
end
|
63
|
-
|
64
|
-
# if there is not obvious reason why the DSL should be turned on (no
|
65
|
-
# validations, cache turned on etc.), it's disabled to avoid unneeded
|
66
|
-
# allocation. It you need the DSL for other reasons, you can force the
|
67
|
-
# activation.
|
68
|
-
attr_writer :force_dsl
|
69
|
-
def force_dsl?
|
70
|
-
@force_dsl
|
71
|
-
end
|
72
|
-
|
73
|
-
# array of controller names (strings) (might include actions as well)
|
74
|
-
# to be ignored # when extracting description form calls.
|
75
|
-
# e.g. %w[Api::CommentsController Api::PostsController#post]
|
76
|
-
attr_writer :ignored_by_recorder
|
77
|
-
def ignored_by_recorder
|
78
|
-
@ignored_by_recorder ||= []
|
79
|
-
@ignored_by_recorder.map(&:to_s)
|
80
|
-
end
|
29
|
+
def self.debug(message)
|
30
|
+
puts message if Apipie.configuration.debug
|
31
|
+
end
|
81
32
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
33
|
+
# get application description for given or default version
|
34
|
+
def self.app_info(version = nil)
|
35
|
+
if app_info_version_valid? version
|
36
|
+
Apipie.markup_to_html(self.configuration.app_info[version])
|
37
|
+
elsif app_info_version_valid? Apipie.configuration.default_version
|
38
|
+
Apipie.markup_to_html(self.configuration.app_info[Apipie.configuration.default_version])
|
39
|
+
else
|
40
|
+
"Another API description"
|
89
41
|
end
|
42
|
+
end
|
90
43
|
|
91
|
-
|
92
|
-
|
44
|
+
def self.api_base_url(version = nil)
|
45
|
+
if api_base_url_version_valid? version
|
46
|
+
self.configuration.api_base_url[version]
|
47
|
+
elsif api_base_url_version_valid? Apipie.configuration.default_version
|
48
|
+
self.configuration.api_base_url[Apipie.configuration.default_version]
|
49
|
+
else
|
50
|
+
"/api"
|
93
51
|
end
|
52
|
+
end
|
94
53
|
|
95
|
-
|
96
|
-
|
97
|
-
|
54
|
+
def self.app_info_version_valid?(version)
|
55
|
+
version && self.configuration.app_info.has_key?(version)
|
56
|
+
end
|
98
57
|
|
99
|
-
|
100
|
-
|
101
|
-
@app_name = "Another API"
|
102
|
-
@app_info = "Another API description"
|
103
|
-
@copyright = nil
|
104
|
-
@validate = true
|
105
|
-
@required_by_default = false
|
106
|
-
@api_base_url = ""
|
107
|
-
@doc_base_url = "/apipie"
|
108
|
-
@layout = "apipie/apipie"
|
109
|
-
@disqus_shortname = nil
|
110
|
-
end
|
58
|
+
def self.api_base_url_version_valid?(version)
|
59
|
+
version && self.configuration.api_base_url.has_key?(version)
|
111
60
|
end
|
112
61
|
|
113
62
|
end
|
data/lib/apipie/application.rb
CHANGED
@@ -12,147 +12,210 @@ module Apipie
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
attr_accessor :
|
16
|
-
|
15
|
+
attr_accessor :last_dsl_data
|
16
|
+
|
17
|
+
attr_reader :resource_descriptions
|
17
18
|
|
18
19
|
def initialize
|
19
20
|
super
|
20
|
-
|
21
|
-
@resource_descriptions = Hash.new
|
21
|
+
init_env
|
22
22
|
clear_last
|
23
23
|
end
|
24
24
|
|
25
|
+
def available_versions
|
26
|
+
@resource_descriptions.keys.sort
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_resource_id(controller, resource_id)
|
30
|
+
@controller_to_resource_id[controller] = resource_id
|
31
|
+
end
|
32
|
+
|
25
33
|
# create new method api description
|
26
|
-
def define_method_description(controller, method_name)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
def define_method_description(controller, method_name, versions = [])
|
35
|
+
return if ignored?(controller, method_name)
|
36
|
+
ret_method_description = nil
|
37
|
+
|
38
|
+
versions = controller_versions(controller) if versions.empty?
|
39
|
+
|
40
|
+
versions.each do |version|
|
41
|
+
resource_name_with_version = "#{version}##{get_resource_name(controller)}"
|
42
|
+
resource_description = get_resource_description(resource_name_with_version)
|
32
43
|
|
33
|
-
|
44
|
+
if resource_description.nil?
|
45
|
+
resource_description = define_resource_description(controller, version)
|
46
|
+
end
|
47
|
+
|
48
|
+
method_description = Apipie::MethodDescription.new(method_name, resource_description, self)
|
34
49
|
|
35
|
-
|
50
|
+
# we create separate method description for each version in
|
51
|
+
# case the method belongs to more versions. We return just one
|
52
|
+
# becuase the version doesn't matter for the purpose it's used
|
53
|
+
# (to wrap the original version with validators)
|
54
|
+
ret_method_description ||= method_description
|
55
|
+
resource_description.add_method_description(method_description)
|
56
|
+
end
|
36
57
|
|
37
|
-
|
58
|
+
return ret_method_description
|
38
59
|
end
|
39
60
|
|
40
61
|
# create new resource api description
|
41
|
-
def define_resource_description(controller,
|
62
|
+
def define_resource_description(controller, version, dsl_data = nil)
|
63
|
+
return if ignored?(controller)
|
64
|
+
|
42
65
|
resource_name = get_resource_name(controller)
|
66
|
+
resource_description = @resource_descriptions[version][resource_name]
|
67
|
+
if resource_description
|
68
|
+
# we already defined the description somewhere (probably in
|
69
|
+
# some method. Updating just meta data from dsl
|
70
|
+
resource_description.update_from_dsl_data(dsl_data) if dsl_data
|
71
|
+
else
|
72
|
+
resource_description = Apipie::ResourceDescription.new(controller, resource_name, dsl_data, version)
|
73
|
+
|
74
|
+
Apipie.debug("@resource_descriptions[#{version}][#{resource_name}] = #{resource_description}")
|
75
|
+
@resource_descriptions[version][resource_name] ||= resource_description
|
76
|
+
end
|
77
|
+
|
78
|
+
return resource_description
|
79
|
+
end
|
43
80
|
|
44
|
-
|
81
|
+
# recursively searches what versions has the controller specified in
|
82
|
+
# resource_description? It's used to derivate the default value of
|
83
|
+
# versions for methods.
|
84
|
+
def controller_versions(controller)
|
85
|
+
ret = @controller_versions[controller]
|
86
|
+
return ret unless ret.empty?
|
87
|
+
if controller == ActionController::Base || controller.nil?
|
88
|
+
return [Apipie.configuration.default_version]
|
89
|
+
else
|
90
|
+
return controller_versions(controller.superclass)
|
91
|
+
end
|
92
|
+
end
|
45
93
|
|
46
|
-
|
47
|
-
|
94
|
+
def set_controller_versions(controller, versions)
|
95
|
+
@controller_versions[controller] = versions
|
48
96
|
end
|
49
97
|
|
50
98
|
def add_method_description_args(method, path, desc)
|
51
|
-
@
|
99
|
+
@last_dsl_data[:api_args] << MethodDescription::Api.new(method, path, desc)
|
52
100
|
end
|
53
101
|
|
54
102
|
def add_example(example)
|
55
|
-
@
|
103
|
+
@last_dsl_data[:examples] << example.strip_heredoc
|
56
104
|
end
|
57
105
|
|
58
106
|
# check if there is some saved description
|
59
107
|
def apipie_provided?
|
60
|
-
true unless
|
108
|
+
true unless last_dsl_data[:api_args].blank?
|
61
109
|
end
|
62
110
|
|
63
111
|
# get api for given method
|
64
112
|
#
|
65
113
|
# There are two ways how this method can be used:
|
66
114
|
# 1) Specify both parameters
|
67
|
-
# resource_name:
|
115
|
+
# resource_name:
|
116
|
+
# controller class - UsersController
|
117
|
+
# string with resource name (plural) and version - "v1#users"
|
68
118
|
# method_name: name of the method (string or symbol)
|
119
|
+
#
|
69
120
|
# 2) Specify only first parameter:
|
70
121
|
# resource_name: string containing both resource and method name joined
|
71
|
-
# with #
|
122
|
+
# with '#' symbol.
|
123
|
+
# - "users#create" get default version
|
124
|
+
# - "v2#users#create" get specific version
|
72
125
|
def get_method_description(resource_name, method_name = nil)
|
73
|
-
resource_name
|
74
|
-
|
75
|
-
|
126
|
+
if resource_name.is_a?(String)
|
127
|
+
crumbs = resource_name.split('#')
|
128
|
+
if method_name.nil?
|
129
|
+
method_name = crumbs.pop
|
130
|
+
end
|
131
|
+
resource_name = crumbs.join("#")
|
132
|
+
resource_description = get_resource_description(resource_name)
|
133
|
+
elsif resource_name.respond_to? :apipie_resource_descriptions
|
134
|
+
resource_description = get_resource_description(resource_name)
|
135
|
+
else
|
136
|
+
raise ArgumentError.new("Resource #{resource_name} does not exists.")
|
137
|
+
end
|
138
|
+
unless resource_description.nil?
|
139
|
+
resource_description.method_description(method_name.to_sym)
|
140
|
+
end
|
76
141
|
end
|
77
142
|
alias :[] :get_method_description
|
78
143
|
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
# Clear all apis in this application.
|
99
|
-
def clear
|
100
|
-
@resource_descriptions.clear
|
101
|
-
@method_descriptions.clear
|
102
|
-
end
|
103
|
-
|
104
|
-
# clear all saved data
|
105
|
-
def clear_last
|
106
|
-
@last_api_args = []
|
107
|
-
@last_errors = []
|
108
|
-
@last_params = []
|
109
|
-
@last_description = nil
|
110
|
-
@last_examples = []
|
111
|
-
@last_see = nil
|
112
|
-
@last_formats = []
|
113
|
-
end
|
144
|
+
# options:
|
145
|
+
# => "users"
|
146
|
+
# => "v2#users"
|
147
|
+
# => V2::UsersController
|
148
|
+
def get_resource_description(resource, version = nil)
|
149
|
+
if resource.is_a?(String)
|
150
|
+
crumbs = resource.split('#')
|
151
|
+
if crumbs.size == 2
|
152
|
+
version = crumbs.first
|
153
|
+
end
|
154
|
+
version ||= Apipie.configuration.default_version
|
155
|
+
if @resource_descriptions.has_key?(version)
|
156
|
+
return @resource_descriptions[version][crumbs.last]
|
157
|
+
end
|
158
|
+
else
|
159
|
+
resource_name = get_resource_name(resource)
|
160
|
+
if version
|
161
|
+
resource_name = "#{version}##{resource_name}"
|
162
|
+
end
|
114
163
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
164
|
+
if resource_name.nil?
|
165
|
+
return nil
|
166
|
+
end
|
167
|
+
resource_description = get_resource_description(resource_name)
|
168
|
+
if resource_description && resource_description.controller == resource
|
169
|
+
return resource_description
|
170
|
+
end
|
171
|
+
end
|
120
172
|
end
|
121
173
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
174
|
+
# get all versions of resource description
|
175
|
+
def get_resource_descriptions(resource)
|
176
|
+
available_versions.map do |version|
|
177
|
+
get_resource_description(resource, version)
|
178
|
+
end.compact
|
126
179
|
end
|
127
180
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
181
|
+
# get all versions of method description
|
182
|
+
def get_method_descriptions(resource, method)
|
183
|
+
get_resource_descriptions(resource).map do |resource_description|
|
184
|
+
resource_description.method_description(method.to_sym)
|
185
|
+
end.compact
|
132
186
|
end
|
133
187
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
188
|
+
def remove_method_description(resource, versions, method_name)
|
189
|
+
versions.each do |version|
|
190
|
+
resource = get_resource_name(resource)
|
191
|
+
if resource_description = get_resource_description("#{version}##{resource}")
|
192
|
+
resource_description.remove_method_description(method_name)
|
193
|
+
end
|
194
|
+
end
|
138
195
|
end
|
139
196
|
|
140
|
-
|
141
|
-
|
142
|
-
@
|
143
|
-
|
144
|
-
end
|
197
|
+
# initialize variables for gathering dsl data
|
198
|
+
def init_env
|
199
|
+
@resource_descriptions = HashWithIndifferentAccess.new { |h, version| h[version] = {} }
|
200
|
+
@controller_to_resource_id = {}
|
145
201
|
|
146
|
-
|
147
|
-
|
148
|
-
@last_params.clear
|
149
|
-
params
|
202
|
+
# what versions does the controller belong in (specified by resource_description)?
|
203
|
+
@controller_versions = Hash.new { |h, controller| h[controller] = [] }
|
150
204
|
end
|
151
|
-
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
205
|
+
# clear all saved data
|
206
|
+
def clear_last
|
207
|
+
@last_dsl_data = {
|
208
|
+
:api_args => [],
|
209
|
+
:errors => [],
|
210
|
+
:params => [],
|
211
|
+
:resouce_id => nil,
|
212
|
+
:short_description => nil,
|
213
|
+
:description => nil,
|
214
|
+
:examples => [],
|
215
|
+
:see => nil,
|
216
|
+
:formats => nil,
|
217
|
+
:api_versions => []
|
218
|
+
}
|
156
219
|
end
|
157
220
|
|
158
221
|
def recorded_examples
|
@@ -170,26 +233,28 @@ module Apipie
|
|
170
233
|
@recorded_examples = nil
|
171
234
|
end
|
172
235
|
|
173
|
-
def to_json(resource_name, method_name)
|
236
|
+
def to_json(version, resource_name, method_name)
|
174
237
|
|
175
238
|
_resources = if resource_name.blank?
|
176
239
|
# take just resources which have some methods because
|
177
240
|
# we dont want to show eg ApplicationController as resource
|
178
|
-
resource_descriptions.inject({}) do |result, (k,v)|
|
241
|
+
resource_descriptions[version].inject({}) do |result, (k,v)|
|
179
242
|
result[k] = v.to_json unless v._methods.blank?
|
180
243
|
result
|
181
244
|
end
|
182
245
|
else
|
183
|
-
[@resource_descriptions[resource_name].to_json(method_name)]
|
246
|
+
[@resource_descriptions[version][resource_name].to_json(method_name)]
|
184
247
|
end
|
185
248
|
|
249
|
+
url_args = Apipie.configuration.version_in_url ? version : ''
|
250
|
+
|
186
251
|
{
|
187
252
|
:docs => {
|
188
253
|
:name => Apipie.configuration.app_name,
|
189
|
-
:info => Apipie.
|
254
|
+
:info => Apipie.app_info(version),
|
190
255
|
:copyright => Apipie.configuration.copyright,
|
191
|
-
:doc_url => Apipie.full_url(
|
192
|
-
:api_url => Apipie.
|
256
|
+
:doc_url => Apipie.full_url(url_args),
|
257
|
+
:api_url => Apipie.api_base_url(version),
|
193
258
|
:resources => _resources
|
194
259
|
}
|
195
260
|
}
|
@@ -200,7 +265,10 @@ module Apipie
|
|
200
265
|
end
|
201
266
|
|
202
267
|
def reload_documentation
|
268
|
+
rails_mark_classes_for_reload
|
269
|
+
init_env
|
203
270
|
reload_examples
|
271
|
+
|
204
272
|
api_controllers_paths.each do |f|
|
205
273
|
load_controller_from_file f
|
206
274
|
end
|
@@ -218,8 +286,21 @@ module Apipie
|
|
218
286
|
def get_resource_name(klass)
|
219
287
|
if klass.class == String
|
220
288
|
klass
|
289
|
+
elsif @controller_to_resource_id.has_key?(klass)
|
290
|
+
@controller_to_resource_id[klass]
|
221
291
|
elsif klass.respond_to?(:controller_name)
|
292
|
+
return nil if klass == ActionController::Base
|
222
293
|
klass.controller_name
|
294
|
+
else
|
295
|
+
raise "Apipie: Can not resolve resource #{klass} name."
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def get_resource_version(resource_description)
|
300
|
+
if resource_description.respond_to? :_version
|
301
|
+
resource_description._version
|
302
|
+
else
|
303
|
+
Apipie.configuration.default_version
|
223
304
|
end
|
224
305
|
end
|
225
306
|
|
@@ -228,5 +309,21 @@ module Apipie
|
|
228
309
|
controller_class_name.constantize
|
229
310
|
end
|
230
311
|
|
312
|
+
def ignored?(controller, method = nil)
|
313
|
+
ignored = Apipie.configuration.ignored
|
314
|
+
return true if ignored.include?(controller.name)
|
315
|
+
return true if ignored.include?("#{controller.name}##{method}")
|
316
|
+
end
|
317
|
+
|
318
|
+
# Since Rails 3.2, the classes are reloaded only on file change.
|
319
|
+
# We need to reload all the controller classes to rebuild the
|
320
|
+
# docs, therefore we just force to reload all the code. This
|
321
|
+
# happens only when reload_controllers is set to true and only
|
322
|
+
# when showing the documentation.
|
323
|
+
def rails_mark_classes_for_reload
|
324
|
+
ActiveSupport::DescendantsTracker.clear
|
325
|
+
ActiveSupport::Dependencies.clear
|
326
|
+
end
|
327
|
+
|
231
328
|
end
|
232
329
|
end
|