apipie-rails 0.1.3 → 0.2.0

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.
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>