apipie-rails 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.travis.yml +1 -2
  2. data/CHANGELOG.md +26 -0
  3. data/README.rst +94 -3
  4. data/app/controllers/apipie/apipies_controller.rb +28 -10
  5. data/app/views/apipie/apipies/_disqus.html.erb +4 -2
  6. data/app/views/apipie/apipies/_languages.erb +6 -0
  7. data/app/views/apipie/apipies/_method_detail.erb +7 -7
  8. data/app/views/apipie/apipies/_params.html.erb +2 -2
  9. data/app/views/apipie/apipies/_params_plain.html.erb +2 -2
  10. data/app/views/apipie/apipies/apipie_404.html.erb +7 -4
  11. data/app/views/apipie/apipies/getting_started.html.erb +5 -3
  12. data/app/views/apipie/apipies/index.html.erb +7 -6
  13. data/app/views/apipie/apipies/method.html.erb +4 -2
  14. data/app/views/apipie/apipies/plain.html.erb +3 -3
  15. data/app/views/apipie/apipies/resource.html.erb +3 -2
  16. data/app/views/apipie/apipies/static.html.erb +7 -7
  17. data/app/views/layouts/apipie/apipie.html.erb +1 -1
  18. data/config/locales/en.yml +27 -0
  19. data/lib/apipie-rails.rb +7 -0
  20. data/lib/apipie/apipie_module.rb +5 -2
  21. data/lib/apipie/application.rb +27 -16
  22. data/lib/apipie/configuration.rb +6 -1
  23. data/lib/apipie/extractor.rb +35 -26
  24. data/lib/apipie/extractor/recorder.rb +9 -5
  25. data/lib/apipie/extractor/writer.rb +36 -7
  26. data/lib/apipie/method_description.rb +6 -6
  27. data/lib/apipie/param_description.rb +9 -4
  28. data/lib/apipie/resource_description.rb +5 -5
  29. data/lib/apipie/routing.rb +1 -1
  30. data/lib/apipie/version.rb +1 -1
  31. data/lib/generators/apipie/install/templates/initializer.rb.erb +1 -1
  32. data/lib/tasks/apipie.rake +89 -47
  33. data/spec/dummy/doc/apipie_examples.json +1 -0
  34. data/spec/lib/extractor/middleware_spec.rb +21 -0
  35. data/spec/lib/extractor/writer_spec.rb +76 -0
  36. metadata +10 -5
  37. data/Gemfile.rails30 +0 -5
  38. data/spec/dummy/doc/apipie_examples.yml +0 -28
data/.travis.yml CHANGED
@@ -2,9 +2,8 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 2.0.0
5
- - 2.1.0
5
+ - 2.1.1
6
6
  gemfile:
7
- - Gemfile.rails30
8
7
  - Gemfile.rails32
9
8
  - Gemfile.rails40
10
9
  - Gemfile.rails41
data/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
  Changelog
3
3
  ===========
4
4
 
5
+ v0.2.0
6
+ ------
7
+
8
+ This is not full backward compatible release, as the format of storing
9
+ examples changed from YAML to JSON: the default location is at
10
+ `doc/apipie_examples.json`. The migration should be as easy as
11
+ running:
12
+
13
+ ```
14
+ rake apipie:convert_examples
15
+ ```
16
+
17
+ Also please not Rails 3.0 support was deprecated and the compatibility
18
+ wont be tracked anymore in next releases.
19
+
20
+ * dump examples as json
21
+ [#125](https://github.com/Apipie/apipie-rails/pull/125) [@johanneswuerbach][]
22
+ * support for localized API documentation
23
+ [#232](https://github.com/Apipie/apipie-rails/pull/232) [@mbacovsky][]
24
+ * configuration option to always record examples
25
+ [#239](https://github.com/Apipie/apipie-rails/pull/239) [@arathunku][]
26
+ * deprecate Rails 3.0
27
+ [#241](https://github.com/Apipie/apipie-rails/pull/241) [@iNecas][]
28
+
5
29
  v0.1.3
6
30
  ------
7
31
 
@@ -119,3 +143,5 @@ v0.0.15
119
143
  [@mkrajewski]: https://github.com/mkrajewski
120
144
  [@iNecas]: https://github.com/iNecas
121
145
  [@clamoris]: https://github.com/clamoris
146
+ [@arathunku]: https://github.com/arathunku
147
+ [@johanneswuerbach]: https://github.com/johanneswuerbach
data/README.rst CHANGED
@@ -554,7 +554,25 @@ show_all_examples
554
554
 
555
555
  link_extension
556
556
  The extension to use for API pages ('.html' by default). Link extensions
557
- in static API docs cannot be changed from '.html'.
557
+ in static API docs cannot be changed from '.html'.
558
+
559
+ languages
560
+ List of languages API documentation should be translated into. Empty list by default.
561
+
562
+ default_locale
563
+ Locale used for generating documentation when no specific locale is set.
564
+ Set to 'en' by default.
565
+
566
+ locale
567
+ Pass locale setter/getter
568
+
569
+ .. code:: ruby
570
+
571
+ config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
572
+
573
+ translate
574
+ Pass proc to translate strings using localization library your project uses.
575
+ For example see `Localization`_
558
576
 
559
577
  Example:
560
578
 
@@ -863,6 +881,79 @@ For inspiration this is how Textile markup usage looks like:
863
881
  end
864
882
  end
865
883
 
884
+ ============
885
+ Localization
886
+ ============
887
+
888
+ Apipie has support for localized API documentation in both formats (JSON and HTML).
889
+ Apipie uses the library I18n for localization of itself.
890
+ Check ``config/locales`` directory for available translation.
891
+
892
+ Major part of strings in the documentation comes from the API.
893
+ As prefferences about localization libraries differs among project, Apipie needs to know how to set locale for your project
894
+ and how to translate a string using library your project use. That can be done using lambdas in configuration.
895
+
896
+ Sample configuration when your project use FastGettext
897
+
898
+
899
+ .. code:: ruby
900
+
901
+ Apipie.configure do |config|
902
+ ...
903
+ config.languages = ['en', 'cs']
904
+ config.default_locale = 'en'
905
+ config.locale = lambda { |loc| loc ? FastGettext.set_locale(loc) : FastGettext.locale }
906
+ config.translate = lambda do |str, loc|
907
+ old_loc = FastGettext.locale
908
+ FastGettext.set_locale(loc)
909
+ trans = _(str)
910
+ FastGettext.set_locale(old_loc)
911
+ trans
912
+ end
913
+ end
914
+
915
+ And the strings in API documentation needs to be marked with the ``N_()`` function
916
+
917
+ .. code:: ruby
918
+
919
+ api :GET, "/users/:id", N_("Show user profile")
920
+ param :session, String, :desc => N_("user is logged in"), :required => true
921
+
922
+
923
+
924
+ When your project use I18n, localization related configuration could look like as follows
925
+
926
+ .. code:: ruby
927
+
928
+ Apipie.configure do |config|
929
+ ...
930
+ config.languages = ['en', 'cs']
931
+ config.default_locale = 'en'
932
+ config.locale = lambda { |loc| loc ? I18n.locale = loc : I18n.locale }
933
+ config.translate = lambda do |str, loc|
934
+ old_loc = I18n.locale
935
+ I18n.locale = loc
936
+ trans = I18n.t(str)
937
+ I18n.locale = old_loc
938
+ trans
939
+ end
940
+ end
941
+
942
+ And the strings in API documentation needs to be in the form of translation keys
943
+
944
+ .. code:: ruby
945
+
946
+ api :GET, "/users/:id", "show_user_profile"
947
+ param :session, String, :desc => "user_is_logged_in", :required => true
948
+
949
+
950
+ The localized versions of the documentation are distinguished by languge in the filename.
951
+ E.g. ``doc/apidoc/apidoc.cs.html`` is static documentation in the Czech language.
952
+ If the language is missing, e.g. ``doc/apidoc/apidoc.html``,
953
+ the documentation is localized with the ``default_locale``.
954
+
955
+ The dynamic documentation follows the same schema. The ``http://localhost:3000/apidoc/v1.cs.html`` is documentation for version '1' of the API in the Czech language. For JSON description of the API applies the same: ``http://localhost:3000/apidoc/v1.cs.json``
956
+
866
957
 
867
958
  ================
868
959
  Modifying Views
@@ -940,7 +1031,7 @@ of information is already included in this tests, it just needs to be
940
1031
  extracted somehow. Luckily, Apipie provides such a feature.
941
1032
 
942
1033
  When running the tests, set the ``APIPIE_RECORD=params`` environment
943
- variable. You can either use it with functional tests
1034
+ variable or call ``Apipie.record('params')`` from specs starter. You can either use it with functional tests
944
1035
 
945
1036
  .. code::
946
1037
 
@@ -962,7 +1053,7 @@ Examples Recording
962
1053
 
963
1054
  You can also use the tests to generate up-to-date examples for your
964
1055
  code. Similarly to the bootstrapping, you can use it with functional
965
- tests or a running server, setting ``APIPIE_RECORD=examples``
1056
+ tests or a running server, setting ``APIPIE_RECORD=examples`` or by calling ``Apipie.record('examples')`` in your specs starter.
966
1057
 
967
1058
  .. code::
968
1059
 
@@ -24,8 +24,11 @@ module Apipie
24
24
  return
25
25
  end
26
26
 
27
+ @language = get_language
28
+
27
29
  Apipie.reload_documentation if Apipie.configuration.reload_controllers?
28
- @doc = Apipie.to_json(params[:version], params[:resource], params[:method])
30
+ I18n.locale = @language
31
+ @doc = Apipie.to_json(params[:version], params[:resource], params[:method], @language)
29
32
 
30
33
  format.json do
31
34
  if @doc
@@ -43,12 +46,13 @@ module Apipie
43
46
 
44
47
  @versions = Apipie.available_versions
45
48
  @doc = @doc[:docs]
46
- @doc[:link_extension] = Apipie.configuration.link_extension
49
+ @doc[:link_extension] = (@language ? ".#{@language}" : '')+Apipie.configuration.link_extension
47
50
  if @doc[:resources].blank?
48
51
  render "getting_started" and return
49
52
  end
50
53
  @resource = @doc[:resources].first if params[:resource].present?
51
54
  @method = @resource[:methods].first if params[:method].present?
55
+ @languages = Apipie.configuration.languages
52
56
 
53
57
  if @resource && @method
54
58
  render 'method'
@@ -68,20 +72,34 @@ module Apipie
68
72
 
69
73
  private
70
74
 
75
+ def get_language
76
+ lang = nil
77
+ [:resource, :method, :version].each do |par|
78
+ if params[par]
79
+ splitted = params[par].split('.')
80
+ if splitted.length > 1 && Apipie.configuration.languages.include?(splitted.last)
81
+ lang = splitted.last
82
+ params[par].sub!(".#{lang}", '')
83
+ end
84
+ end
85
+ end
86
+ lang
87
+ end
88
+
71
89
  def get_format
72
- params[:format] = :html unless params[:version].sub!('.html', '').nil?
73
- params[:format] = :json unless params[:version].sub!('.json', '').nil?
90
+ [:resource, :method, :version].each do |par|
91
+ if params[par]
92
+ params[:format] = :html unless params[par].sub!('.html', '').nil?
93
+ params[:format] = :json unless params[par].sub!('.json', '').nil?
94
+ end
95
+ end
74
96
  request.format = params[:format] if params[:format]
75
97
  end
76
98
 
77
99
  def render_from_cache
78
100
  path = Apipie.configuration.doc_base_url.dup
79
- if [:resource, :method, :format].any? { |p| params[p].to_s =~ /\W/ }
80
- head :bad_request and return
81
- end
82
- # version can contain dot, but only one in row
83
- if params[:version].to_s.gsub(".", "") =~ /\W/ ||
84
- params[:version].to_s =~ /\.\./
101
+ # some params can contain dot, but only one in row
102
+ if [:resource, :method, :format, :version].any? { |p| params[p].to_s.gsub(".", "") =~ /\W/ || params[p].to_s =~ /\.\./ }
85
103
  head :bad_request and return
86
104
  end
87
105
 
@@ -7,5 +7,7 @@
7
7
  (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
8
8
  })();
9
9
  </script>
10
- <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
11
- <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
10
+ <noscript><%= t('apipie.enable_javascript_html', :comments_href => link_to(
11
+ t('apipie.comments_powered_by_disqus', :disqus => 'Disqus'),
12
+ "http://disqus.com/?ref_noscript")) %></noscript>
13
+ <a href="http://disqus.com" class="dsq-brlink"><%= t('apipie.comments_powered_by_disqus', :disqus => "<span class="logo-disqus">Disqus</span>") %></a>
@@ -0,0 +1,6 @@
1
+ <% if @languages && @languages.size > 1 %>
2
+ <li class='pull-right'>
3
+ &nbsp;[ <%= @languages.collect { |lang| link = link_to(lang, "#{doc_url}.#{lang}.html");
4
+ lang==@language ? content_tag(:b, link) : link }.join(' | ').html_safe %> ]
5
+ </li>
6
+ <% end %>
@@ -1,12 +1,12 @@
1
1
  <%= raw method[:full_description] %>
2
2
 
3
3
  <% unless method[:formats].blank? %>
4
- <%= heading('Supported Formats', h_level) %>
4
+ <%= heading(t('apipie.supported_formats'), h_level) %>
5
5
  <%= method[:formats].join(', ') %>
6
6
  <% end %>
7
7
 
8
8
  <% unless method[:errors].blank? %>
9
- <%= heading('Errors', h_level) %>
9
+ <%= heading(t('apipie.errors'), h_level) %>
10
10
  <% method[:errors].each do |err| %>
11
11
  <%= err[:code] %>
12
12
  <%= err[:description] %>
@@ -19,24 +19,24 @@
19
19
  <% end %>
20
20
 
21
21
  <% unless method[:metadata].blank? %>
22
- <%= heading('Metadata', h_level) %>
22
+ <%= heading(t('apipie.metadata'), h_level) %>
23
23
  <%= render(:partial => "metadata", :locals => {:meta => method[:metadata]}) %>
24
24
  <% end %>
25
25
 
26
26
  <% unless method[:examples].blank? %>
27
- <%= heading('Examples', h_level) %>
27
+ <%= heading(t('apipie.examples'), h_level) %>
28
28
  <% method[:examples].each do |example| %>
29
29
  <pre class="prettyprint"><%= example %></pre>
30
30
  <% end %>
31
31
  <% end %>
32
32
 
33
33
  <% unless method[:params].blank? %>
34
- <%= heading('Params', h_level) %>
34
+ <%= heading(t('apipie.params'), h_level) %>
35
35
  <table class='table'>
36
36
  <thead>
37
37
  <tr>
38
- <th>Param name</th>
39
- <th>Description</th>
38
+ <th><%= t('aapipie.param_name') %></th>
39
+ <th><%= t('apipie.description') %></th>
40
40
  </tr>
41
41
  </thead>
42
42
  <tbody>
@@ -9,8 +9,8 @@
9
9
  <td>
10
10
  <strong><%= param[:full_name] %> </strong><br>
11
11
  <small>
12
- <%= param[:required] ? 'required' : 'optional' %>
13
- <%= param[:allow_nil] ? ', nil allowed' : '' %>
12
+ <%= param[:required] ? t('apipie.required') : t('apipie.optional') %>
13
+ <%= param[:allow_nil] ? ', '+t('apipie.nil_allowed') : '' %>
14
14
  </small>
15
15
  </td>
16
16
  <td>
@@ -7,8 +7,8 @@
7
7
  <li>
8
8
  <strong><%= param[:name] %> </strong>:
9
9
  <small>
10
- <%= param[:required] ? 'required' : 'optional' %>
11
- <%= param[:allow_nil] ? ', nil allowed' : '' %>
10
+ <%= param[:required] ? t('apipie.required') : t('apipie.optional') %>
11
+ <%= param[:allow_nil] ? ', '+t('apipie.nil_allowed') : '' %>
12
12
  <% if param[:validator] %>
13
13
  [ <%= param[:validator] %> ]
14
14
  <% end %>
@@ -1,14 +1,17 @@
1
1
  <h1 class='page-header'>
2
- Oops!
2
+ <%= t('apipie.oops') %>
3
3
  <small>
4
4
  <% if @resource == 'null' %>
5
- Resource <code><%= params[:resource] %></code> not found.
5
+ <%= t('apipie.resource_not_found_html', :resource => "<code>#{params[:resource]}</code>") %>
6
6
  <% else %>
7
- Method <code><%= params[:method] %></code> not found for resource <code><%= params[:resource] %></code>.
7
+ <%= t('apipie.method_not_found_html', :resource => "<code>#{params[:resource]}</code>",
8
+ :method => "<code>#{params[:resource]}</code>" %>
8
9
  <% end %>
9
10
  </small>
10
11
  </h1>
11
12
 
12
13
  <% if @doc %>
13
- Try going to <a href='<%= @doc[:doc_url] %><%= @doc[:link_extension] %>'><%= @doc[:name] %> API documentation homepage</a>
14
+ <%= t('apipie.goto_homepage_html', :href = link_to(
15
+ t('apipie.goto_homepage_href', :app_name => @doc[:name]),
16
+ File.join(@doc[:doc_url], @doc[:link_extension]))) %>
14
17
  <% end %>
@@ -1,4 +1,6 @@
1
- <h1 class='page-header'>No documentation found</h1>
2
- <p>We have not found any documentation for your API.</p>
3
- <p>Follow <a href="https://github.com/Pajk/apipie-rails#getting-started" target="_blank">further instructions</a> on how to describe your controllers.</p>
1
+ <h1 class='page-header'><%= t('apipie.no_doc_found') %></h1>
2
+ <p><%= t('apipie.no_docs_found_descr') %></p>
3
+ <p><%= t('apipie.follow_instructions_html',
4
+ :href => link_to(t('apipie.follow_instructions_href'),
5
+ "https://github.com/Pajk/apipie-rails#getting-started", :target => "_blank")) %></p>
4
6
 
@@ -1,15 +1,16 @@
1
1
  <ul class='breadcrumb'>
2
2
  <li class='active'><a href='<%= @doc[:doc_url] %><%= @doc[:link_extension] %>'><%= @doc[:name] %> <%= @doc[:resources].values.first[:version] %></a></li>
3
+ <%= render(:partial => "languages", :locals => {:doc_url => @doc[:doc_url]}) %>
3
4
  <% if @versions && @versions.size > 1 %>
4
5
  <li class='pull-right'>
5
- <%= @versions.collect { |v| link_to v, Apipie.full_url(v) }.join(' / ').html_safe %>
6
+ <%= @versions.collect { |v| link_to v, Apipie.full_url(v+@doc[:link_extension]) }.join(' / ').html_safe %>
6
7
  </li>
7
8
  <% end %>
8
9
  </ul>
9
10
 
10
11
  <div><%= raw @doc[:info] %></div>
11
12
 
12
- <h1 class='page-header'>Resources</h1>
13
+ <h1 class='page-header'><%= t('apipie.resources') %></h1>
13
14
 
14
15
  <% @doc[:resources].sort_by(&:first).each do |key, api| %>
15
16
  <h2>
@@ -21,8 +22,8 @@
21
22
  <table class='table'>
22
23
  <thead>
23
24
  <tr>
24
- <th>Resource</th>
25
- <th>Description</th>
25
+ <th><%= t('apipie.resource') %></th>
26
+ <th><%= t('apipie.description') %></th>
26
27
  </tr>
27
28
  </thead>
28
29
  <tbody>
@@ -38,6 +39,6 @@
38
39
  </table>
39
40
  <% end %>
40
41
 
41
- <% content_for :apipie_footer do %>
42
- <%= raw @doc[:copyright] %>
42
+ <% unless content_for(:apipie_footer) == @doc[:copyright] %>
43
+ <%= content_for :apipie_footer, raw(@doc[:copyright]) %>
43
44
  <% end %>
@@ -11,6 +11,8 @@
11
11
  <span class='divider'>/</span>
12
12
  </li>
13
13
  <li class='active'><%= @method[:name] %></li>
14
+ <%= render(:partial => "languages", :locals => {:doc_url => @method[:doc_url]}) %>
15
+
14
16
  </ul>
15
17
 
16
18
  <% @method[:apis].each do |api| %>
@@ -30,6 +32,6 @@
30
32
  <%= render(:partial => "method_detail", :locals => {:method => @method, :h_level => 2}) %>
31
33
  </div>
32
34
 
33
- <% content_for :apipie_footer do %>
34
- <%= raw @doc[:copyright] %>
35
+ <% unless content_for(:apipie_footer) == @doc[:copyright] %>
36
+ <%= content_for :apipie_footer, raw(@doc[:copyright]) %>
35
37
  <% end %>
@@ -45,14 +45,14 @@
45
45
  <div>
46
46
  <%= raw method[:full_description] %>
47
47
  <% unless method[:examples].blank? %>
48
- <h4>Examples</h4>
48
+ <h4><%= t('apipie.examples') %></h4>
49
49
  <% method[:examples].each do |example| %>
50
50
  <pre class="wiki"><%= example %></pre>
51
51
  <% end %>
52
52
  <% end %>
53
53
 
54
54
  <% unless method[:errors].blank? %>
55
- <h4>Errors</h4>
55
+ <h4><%= t('apipie.errors') %></h4>
56
56
  <% method[:errors].each do |err| %>
57
57
  <%= err[:code] %>
58
58
  <%= err[:description] %>
@@ -62,7 +62,7 @@
62
62
  <% end %>
63
63
 
64
64
  <% unless method[:params].blank? %>
65
- <h4>Params</h4>
65
+ <h4><%= t('apipie.params') %></h4>
66
66
  <%= render(:partial => "params_plain", :locals => {:params => method[:params]}) %>
67
67
  <% end %>
68
68
  </div>