apipie-rails 0.0.24 → 0.1.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 (51) hide show
  1. data/.gitignore +1 -1
  2. data/.travis.yml +6 -0
  3. data/CHANGELOG.md +97 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.rails30 +5 -0
  6. data/Gemfile.rails32 +5 -0
  7. data/Gemfile.rails40 +5 -0
  8. data/Gemfile.rails41 +5 -0
  9. data/README.rst +126 -11
  10. data/apipie-rails.gemspec +1 -1
  11. data/app/controllers/apipie/apipies_controller.rb +3 -0
  12. data/app/helpers/apipie_helper.rb +9 -0
  13. data/app/views/apipie/apipies/_metadata.erb +1 -0
  14. data/app/views/apipie/apipies/_method_detail.erb +46 -0
  15. data/app/views/apipie/apipies/_params.html.erb +12 -0
  16. data/app/views/apipie/apipies/_params_plain.html.erb +4 -0
  17. data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
  18. data/app/views/apipie/apipies/method.html.erb +1 -37
  19. data/app/views/apipie/apipies/plain.html.erb +1 -0
  20. data/app/views/apipie/apipies/resource.html.erb +6 -37
  21. data/app/views/apipie/apipies/static.html.erb +1 -0
  22. data/lib/apipie/application.rb +16 -2
  23. data/lib/apipie/configuration.rb +8 -2
  24. data/lib/apipie/dsl_definition.rb +25 -6
  25. data/lib/apipie/error_description.rb +22 -10
  26. data/lib/apipie/extractor.rb +2 -1
  27. data/lib/apipie/extractor/writer.rb +8 -6
  28. data/lib/apipie/method_description.rb +7 -4
  29. data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
  30. data/lib/apipie/param_description.rb +25 -4
  31. data/lib/apipie/resource_description.rb +8 -4
  32. data/lib/apipie/routing.rb +1 -0
  33. data/lib/apipie/validator.rb +71 -3
  34. data/lib/apipie/version.rb +1 -1
  35. data/lib/tasks/apipie.rake +26 -5
  36. data/spec/controllers/apipies_controller_spec.rb +2 -0
  37. data/spec/controllers/concerns_controller_spec.rb +1 -1
  38. data/spec/controllers/users_controller_spec.rb +130 -19
  39. data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +1 -0
  40. data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +22 -20
  41. data/spec/dummy/app/controllers/concerns/sample_controller.rb +32 -30
  42. data/spec/dummy/app/controllers/users_controller.rb +18 -5
  43. data/spec/lib/method_description_spec.rb +22 -0
  44. data/spec/lib/param_description_spec.rb +77 -0
  45. data/spec/lib/rake_spec.rb +68 -0
  46. data/spec/lib/resource_description_spec.rb +18 -0
  47. data/spec/lib/validator_spec.rb +9 -0
  48. data/spec/spec_helper.rb +2 -1
  49. data/spec/support/rake.rb +21 -0
  50. metadata +20 -7
  51. data/CHANGELOG +0 -72
@@ -0,0 +1 @@
1
+ <pre class="prettyprint lang-yaml"><%= meta.to_yaml.gsub(/---\n/, "") %></pre>
@@ -0,0 +1,46 @@
1
+ <%= raw method[:full_description] %>
2
+
3
+ <% unless method[:formats].blank? %>
4
+ <%= heading('Supported Formats', h_level) %>
5
+ <%= method[:formats].join(', ') %>
6
+ <% end %>
7
+
8
+ <% unless method[:errors].blank? %>
9
+ <%= heading('Errors', h_level) %>
10
+ <% method[:errors].each do |err| %>
11
+ <%= err[:code] %>
12
+ <%= err[:description] %>
13
+ <br>
14
+ <% unless err[:metadata].blank? %>
15
+ Metadata:
16
+ <pre class="prettyprint lang-yaml"><%= err[:metadata].to_yaml %></pre>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
20
+
21
+ <% unless method[:metadata].blank? %>
22
+ <%= heading('Metadata', h_level) %>
23
+ <%= render(:partial => "metadata", :locals => {:meta => method[:metadata]}) %>
24
+ <% end %>
25
+
26
+ <% unless method[:examples].blank? %>
27
+ <%= heading('Examples', h_level) %>
28
+ <% method[:examples].each do |example| %>
29
+ <pre class="prettyprint"><%= example %></pre>
30
+ <% end %>
31
+ <% end %>
32
+
33
+ <% unless method[:params].blank? %>
34
+ <%= heading('Params', h_level) %>
35
+ <table class='table'>
36
+ <thead>
37
+ <tr>
38
+ <th>Param name</th>
39
+ <th>Description</th>
40
+ </tr>
41
+ </thead>
42
+ <tbody>
43
+ <%= render(:partial => "params", :locals => {:params => method[:params]}) %>
44
+ </tbody>
45
+ </table>
46
+ <% end %>
@@ -1,6 +1,10 @@
1
1
  <% level ||= 0 %>
2
2
  <% col = 255 - level * 5 %>
3
3
  <% params.each do |param| %>
4
+ <% if !param[:show] %>
5
+ <%= render(:partial => "params", :locals => {:level => level, :params => param[:params]}) unless param[:params].blank? %>
6
+ <% next %>
7
+ <% end %>
4
8
  <tr style='background-color:rgb(<%= "#{col},#{col},#{col}" %>);'>
5
9
  <td>
6
10
  <strong><%= param[:full_name] %> </strong><br>
@@ -15,7 +19,15 @@
15
19
  <br>
16
20
  Value: <%= param[:validator] %>
17
21
  <% end %>
22
+
23
+ <% unless param[:metadata].blank? %>
24
+ <br>
25
+ Metadata:
26
+ <%= render(:partial => "metadata", :locals => {:meta => param[:metadata]}) %>
27
+ <% end %>
28
+
18
29
  </td>
30
+
19
31
  </tr>
20
32
 
21
33
  <%= render(:partial => "params", :locals => {:level => level + 1, :params => param[:params]}) unless param[:params].blank? %>
@@ -1,5 +1,9 @@
1
1
  <ul>
2
2
  <% params.each do |param| %>
3
+ <% if !param[:show] %>
4
+ <%= render(:partial => "params_plain", :locals => {:params => param[:params]}) unless param[:params].blank? %>
5
+ <% next %>
6
+ <% end %>
3
7
  <li>
4
8
  <strong><%= param[:name] %> </strong>:
5
9
  <small>
@@ -0,0 +1 @@
1
+ { "checksum": "<%= raw Apipie.checksum %>" }
@@ -27,43 +27,7 @@
27
27
  Also see <%= @method[:see].map { |s| link_to(s[:description], "#{s[:link]}.html") }.to_sentence.html_safe %>.
28
28
  <% end %>
29
29
 
30
- <%= raw @method[:full_description] %>
31
-
32
- <% unless @method[:examples].blank? %>
33
- <h2>Examples</h2>
34
- <% @method[:examples].each do |example| %>
35
- <pre class="prettyprint"><%= example %></pre>
36
- <% end %>
37
- <% end %>
38
-
39
- <% unless @method[:formats].blank? %>
40
- <h2>Supported Formats</h2>
41
- <%= @method[:formats].join(', ') %>
42
- <% end %>
43
-
44
- <% unless @method[:errors].blank? %>
45
- <h2>Errors</h2>
46
- <% @method[:errors].each do |err| %>
47
- <%= err[:code] %>
48
- <%= err[:description] %>
49
- <br>
50
- <% end %>
51
- <% end %>
52
-
53
- <% unless @method[:params].blank? %>
54
- <h2>Params</h2>
55
- <table class='table'>
56
- <thead>
57
- <tr>
58
- <th>Param name</th>
59
- <th>Description</th>
60
- </tr>
61
- </thead>
62
- <tbody>
63
- <%= render(:partial => "params", :locals => {:params => @method[:params]}) %>
64
- </tbody>
65
- </table>
66
- <% end %>
30
+ <%= render(:partial => "method_detail", :locals => {:method => @method, :h_level => 2}) %>
67
31
  </div>
68
32
 
69
33
  <% content_for :apipie_footer do %>
@@ -56,6 +56,7 @@
56
56
  <% method[:errors].each do |err| %>
57
57
  <%= err[:code] %>
58
58
  <%= err[:description] %>
59
+ <%= render(:partial => "metadata", :locals => {:meta => err[:metadata]}) %>
59
60
  <br>
60
61
  <% end %>
61
62
  <% end %>
@@ -21,6 +21,11 @@
21
21
  <div><%= raw @resource[:full_description] %></div>
22
22
  <% end %>
23
23
 
24
+ <% unless @resource[:metadata].blank? %>
25
+ <h2>Metadata</h2>
26
+ <%= render(:partial => "metadata", :locals => {:meta => @resource[:metadata]}) %>
27
+ <% end %>
28
+
24
29
  <% unless @resource[:formats].blank? %>
25
30
  <h2>Supported Formats</h2>
26
31
  <%= @resource[:formats].join(', ') %>
@@ -52,43 +57,7 @@
52
57
  <% end %>
53
58
 
54
59
  <div id='description-<%= m[:name] %>' class='collapse accordion-body'>
55
- <%= raw m[:full_description] %>
56
-
57
- <% unless m[:formats].blank? %>
58
- <h3>Supported Formats</h3>
59
- <%= m[:formats].join(', ') %>
60
- <% end %>
61
-
62
- <% unless m[:errors].blank? %>
63
- <h3>Errors</h3>
64
- <% m[:errors].each do |err| %>
65
- <%= err[:code] %>
66
- <%= err[:description] %>
67
- <br>
68
- <% end %>
69
- <% end %>
70
-
71
- <% unless m[:examples].blank? %>
72
- <h3>Examples</h3>
73
- <% m[:examples].each do |example| %>
74
- <pre class="prettyprint"><%= example %></pre>
75
- <% end %>
76
- <% end %>
77
-
78
- <% unless m[:params].blank? %>
79
- <h3>Params</h3>
80
- <table class='table'>
81
- <thead>
82
- <tr>
83
- <th>Param name</th>
84
- <th>Description</th>
85
- </tr>
86
- </thead>
87
- <tbody>
88
- <%= render(:partial => "params", :locals => {:params => m[:params]}) %>
89
- </tbody>
90
- </table>
91
- <% end %>
60
+ <%= render(:partial => "method_detail", :locals => {:method => m, :h_level => 3}) %>
92
61
  </div>
93
62
  <% end %>
94
63
  </div>
@@ -73,6 +73,7 @@
73
73
  <% method[:errors].each do |err| %>
74
74
  <%= err[:code] %>
75
75
  <%= err[:description] %>
76
+ <%= render(:partial => "metadata", :locals => {:meta => err[:metadata]}) %>
76
77
  <br>
77
78
  <% end %>
78
79
  <% end %>
@@ -1,5 +1,7 @@
1
1
  require 'apipie/static_dispatcher'
2
2
  require 'yaml'
3
+ require 'digest/md5'
4
+ require 'json'
3
5
 
4
6
  module Apipie
5
7
 
@@ -208,8 +210,8 @@ module Apipie
208
210
  tape_file = File.join(Rails.root,"doc","apipie_examples.yml")
209
211
  if File.exists?(tape_file)
210
212
  #if SafeYAML gem is enabled, it will load examples as an array of Hash, instead of hash
211
- if defined? SafeYAML
212
- @recorded_examples = YAML.load_file(tape_file, :safe=>false)
213
+ if YAML.respond_to?(:safe_load_file) && defined?(SafeYAML)
214
+ @recorded_examples = SafeYAML.load_file(tape_file, :safe=>false)
213
215
  else
214
216
  @recorded_examples = YAML.load_file(tape_file)
215
217
  end
@@ -264,6 +266,18 @@ module Apipie
264
266
  api_controllers_paths.each do |f|
265
267
  load_controller_from_file f
266
268
  end
269
+ @checksum = compute_checksum if Apipie.configuration.update_checksum
270
+ end
271
+
272
+ def compute_checksum
273
+ all_docs = Apipie.available_versions.inject({}) do |all, version|
274
+ all.update(version => Apipie.to_json(version))
275
+ end
276
+ Digest::MD5.hexdigest(JSON.dump(all_docs))
277
+ end
278
+
279
+ def checksum
280
+ @checksum ||= compute_checksum
267
281
  end
268
282
 
269
283
  # Is there a reason to interpret the DSL for this run?
@@ -4,8 +4,8 @@ module Apipie
4
4
  attr_accessor :app_name, :app_info, :copyright, :markup, :disqus_shortname,
5
5
  :api_base_url, :doc_base_url, :required_by_default, :layout,
6
6
  :default_version, :debug, :version_in_url, :namespaced_resources,
7
- :validate, :validate_value, :validate_presence, :authenticate, :doc_path
8
-
7
+ :validate, :validate_value, :validate_presence, :authenticate, :doc_path,
8
+ :show_all_examples, :process_params, :update_checksum, :checksum_path
9
9
 
10
10
  alias_method :validate?, :validate
11
11
  alias_method :required_by_default?, :required_by_default
@@ -36,6 +36,9 @@ module Apipie
36
36
  end
37
37
  alias_method :validate_presence?, :validate_presence
38
38
 
39
+ def process_value?
40
+ @process_params
41
+ end
39
42
  # set to true if you want to use pregenerated documentation cache and avoid
40
43
  # generating the documentation on runtime (usefull for production
41
44
  # environment).
@@ -124,6 +127,9 @@ module Apipie
124
127
  @version_in_url = true
125
128
  @namespaced_resources = false
126
129
  @doc_path = "doc"
130
+ @process_params = false
131
+ @checksum_path = [@doc_base_url, '/api/']
132
+ @update_checksum = false
127
133
  end
128
134
  end
129
135
  end
@@ -6,7 +6,7 @@ module Apipie
6
6
  module DSL
7
7
 
8
8
  module Base
9
- attr_reader :apipie_resource_descriptions
9
+ attr_reader :apipie_resource_descriptions, :api_params
10
10
 
11
11
  private
12
12
 
@@ -29,7 +29,8 @@ module Apipie
29
29
  :examples => [],
30
30
  :see => [],
31
31
  :formats => nil,
32
- :api_versions => []
32
+ :api_versions => [],
33
+ :meta => nil
33
34
  }
34
35
  end
35
36
  end
@@ -76,7 +77,7 @@ module Apipie
76
77
  # Example:
77
78
  # api :GET, "/resource_route", "short description",
78
79
  #
79
- def api(method, path, desc = nil) #:doc:
80
+ def api(method, path, desc = nil, options={}) #:doc:
80
81
  return unless Apipie.active_dsl?
81
82
  _apipie_dsl_data[:api_args] << [method, path, desc]
82
83
  end
@@ -164,20 +165,27 @@ module Apipie
164
165
  _apipie_dsl_data[:formats] = formats
165
166
  end
166
167
 
168
+ # Describe additional metadata
169
+ #
170
+ # meta :author => { :name => 'John', :surname => 'Doe' }
171
+ def meta(meta) #:doc:
172
+ _apipie_dsl_data[:meta] = meta
173
+ end
174
+
167
175
 
168
176
  # Describe possible errors
169
177
  #
170
178
  # Example:
171
- # error :desc => "speaker is sleeping", :code => 500
179
+ # error :desc => "speaker is sleeping", :code => 500, :meta => [:some, :more, :data]
172
180
  # error 500, "speaker is sleeping"
173
181
  # def hello_world
174
182
  # return 500 if self.speaker.sleeping?
175
183
  # puts "hello world"
176
184
  # end
177
185
  #
178
- def error(*args) #:doc:
186
+ def error(code_or_options, desc=nil, options={}) #:doc:
179
187
  return unless Apipie.active_dsl?
180
- _apipie_dsl_data[:errors] << args
188
+ _apipie_dsl_data[:errors] << [code_or_options, desc, options]
181
189
  end
182
190
 
183
191
  def _apipie_define_validators(description)
@@ -186,6 +194,8 @@ module Apipie
186
194
 
187
195
  old_method = instance_method(description.method)
188
196
 
197
+
198
+ # @todo we should use before_filter
189
199
  define_method(description.method) do |*args|
190
200
 
191
201
  if Apipie.configuration.validate_presence?
@@ -202,6 +212,15 @@ module Apipie
202
212
  end
203
213
  end
204
214
 
215
+ if Apipie.configuration.process_value?
216
+ @api_params = {}
217
+
218
+ description.params.each do |_, param|
219
+ # params processing
220
+ @api_params[param.as] = param.process_value(params[:"#{param.name}"]) if params.has_key?(param.name)
221
+ end
222
+ end
223
+
205
224
  # run the original method code
206
225
  old_method.bind(self).call(*args)
207
226
  end
@@ -2,22 +2,34 @@ module Apipie
2
2
 
3
3
  class ErrorDescription
4
4
 
5
- attr_reader :code, :description
5
+ attr_reader :code, :description, :metadata
6
6
 
7
- def initialize(args)
8
- if args.first.is_a? Hash
9
- args = args.first
10
- elsif args.count == 2
11
- args = {:code => args.first, :description => args.second}
7
+ def self.from_dsl_data(args)
8
+ code_or_options, desc, options = args
9
+ Apipie::ErrorDescription.new(code_or_options,
10
+ desc,
11
+ options)
12
+ end
13
+
14
+ def initialize(code_or_options, desc=nil, options={})
15
+ if code_or_options.is_a? Hash
16
+ code_or_options.symbolize_keys!
17
+ @code = code_or_options[:code]
18
+ @metadata = code_or_options[:meta]
19
+ @description = code_or_options[:desc] || code_or_options[:description]
12
20
  else
13
- raise ArgumentError "ApipieError: Bad use of error method."
21
+ @code = code_or_options
22
+ @metadata = options[:meta]
23
+ @description = desc
14
24
  end
15
- @code = args[:code] || args['code']
16
- @description = args[:desc] || args[:description] || args['desc'] || args['description']
17
25
  end
18
26
 
19
27
  def to_json
20
- {:code => code, :description => description}
28
+ {
29
+ :code => code,
30
+ :description => description,
31
+ :metadata => metadata
32
+ }
21
33
  end
22
34
 
23
35
  end
@@ -86,7 +86,8 @@ module Apipie
86
86
  controller_path, action = route[:controller], route[:action]
87
87
  next unless controller_path && action
88
88
 
89
- controller = "#{controller_path}_controller".camelize
89
+ controller_path = controller_path.split('::').map(&:camelize).join('::')
90
+ controller = "#{controller_path}Controller"
90
91
 
91
92
  path = if /^#{Regexp.escape(api_prefix)}(.*)$/ =~ route[:path]
92
93
  $1.sub!(/\(\.:format\)$/,"")
@@ -84,7 +84,9 @@ module Apipie
84
84
  method_descriptions = Apipie.get_method_descriptions(call[:controller], call[:action])
85
85
  call[:versions] = method_descriptions.map(&:version)
86
86
 
87
- if call[:versions].any? { |v| ! showed_in_versions.include?(v) }
87
+ if Apipie.configuration.show_all_examples
88
+ show_in_doc = 1
89
+ elsif call[:versions].any? { |v| ! showed_in_versions.include?(v) }
88
90
  call[:versions].each { |v| showed_in_versions << v }
89
91
  show_in_doc = 1
90
92
  else
@@ -99,11 +101,11 @@ module Apipie
99
101
 
100
102
  def load_old_examples
101
103
  if File.exists?(@examples_file)
102
- if defined? SafeYAML
103
- return YAML.load_file(@examples_file, :safe=>false)
104
- else
105
- return YAML.load_file(@examples_file)
106
- end
104
+ if defined? SafeYAML
105
+ return YAML.load_file(@examples_file, :safe=>false)
106
+ else
107
+ return YAML.load_file(@examples_file)
108
+ end
107
109
  end
108
110
  return {}
109
111
  end