api_taster 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # ApiTaster [![Build Status](https://secure.travis-ci.org/fredwu/api_taster.png?branch=master)](http://travis-ci.org/fredwu/api_taster) [![Dependency Status](https://gemnasium.com/fredwu/api_taster.png)](https://gemnasium.com/fredwu/api_taster)
2
2
 
3
- A quick and easy way to visually test out your application's API.
3
+ A quick and easy way to visually test out your Rails application's API.
4
4
 
5
- ![](http://i.imgur.com/ryjOH.png)
5
+ ![](http://i.imgur.com/8Dnto.png)
6
6
 
7
7
  ## Why?
8
8
 
@@ -67,15 +67,23 @@ if Rails.env.development?
67
67
  end
68
68
  ```
69
69
 
70
- That's it! Enjoy! :)
70
+ ### Share Params with Test Factories
71
71
 
72
- ## Obsolete / Mismatched Route Definitions Detection
72
+ If you use a test factory such as [FactoryGirl](https://github.com/thoughtbot/factory_girl), you can require your test factories and share the params. For example in FactoryGirl you can use the `attributes_for(:name_of_factory)` method.
73
+
74
+ ### Missing Route Definitions Detection
75
+
76
+ Instead of manually finding out which route definitions you need, API Taster provides a warning page that shows you all the missing definitions.
77
+
78
+ ![](http://i.imgur.com/vZb93.png)
79
+
80
+ ### Obsolete / Mismatched Route Definitions Detection
73
81
 
74
82
  APIs evolve - especially during the development stage. To keep `ApiTaster.routes` in sync with your route definitions, API Taster provides a warning page that shows you the definitions that are obsolete/mismatched therefore you could correct or remove them.
75
83
 
76
- ![](http://i.imgur.com/rqYiY.png)
84
+ ![](http://i.imgur.com/Fo7kQ.png)
77
85
 
78
- ## Use with an Engine
86
+ ### Use with an Engine
79
87
 
80
88
  Rails Engines are largely self contained and separated from your main app. Therefore, to use API Taster with an Engine, you would need some extra efforts:
81
89
 
@@ -48,6 +48,8 @@ $.fn.extend({
48
48
  var replacedAction = ApiTaster.formAction.replace(regex, paramValue);
49
49
 
50
50
  form.attr("action", replacedAction);
51
+ } else {
52
+ ApiTaster.storeFormActionFor(form);
51
53
  }
52
54
  });
53
55
  },
@@ -2,7 +2,8 @@ module ApiTaster
2
2
  class RoutesController < ApplicationController
3
3
  def index
4
4
  @routes = Route.grouped_routes
5
- @has_obsolete_definitions = Route.obsolete_definitions.size > 0
5
+ @has_missing_definitions = Route.missing_definitions.present?
6
+ @has_obsolete_definitions = Route.obsolete_definitions.present?
6
7
  end
7
8
 
8
9
  def show
@@ -10,6 +11,10 @@ module ApiTaster
10
11
  @inputs = Route.inputs_for(@route)
11
12
  end
12
13
 
14
+ def missing_definitions
15
+ @missing_definitions = Route.missing_definitions
16
+ end
17
+
13
18
  def obsolete_definitions
14
19
  @obsolete_definitions = Route.obsolete_definitions
15
20
  end
@@ -0,0 +1,8 @@
1
+ <li>
2
+ <a href="<%= path %>">
3
+ <div class="label-api">
4
+ <span class="label label-warning">Warning</span>
5
+ </div>
6
+ <%= text %>
7
+ </a>
8
+ </li>
@@ -0,0 +1,7 @@
1
+ <pre class="prettyprint lang-rb">ApiTaster.routes do
2
+
3
+ <% routes.each do |route| %>
4
+ <%= route[:verb].downcase %> '<%= route[:path] %>'<%= ", #{route[:params]}" if route[:params].present? %>
5
+
6
+ <% end %>
7
+ end</pre>
@@ -2,16 +2,20 @@
2
2
  <div id="list-api-div" class="span5">
3
3
  <div class="div-container">
4
4
  <ul class="well nav nav-list">
5
- <% if @has_obsolete_definitions %>
5
+ <% if @has_missing_definitions || @has_obsolete_definitions %>
6
6
  <li class="nav-header">Information</li>
7
- <li>
8
- <a href="<%= obsolete_definitions_routes_path %>">
9
- <div class="label-api">
10
- <span class="label label-warning">Warning</span>
11
- </div>
12
- Obsolete Definitions Detected
13
- </a>
14
- </li>
7
+ <% if @has_missing_definitions %>
8
+ <%= render 'information_warning_li',
9
+ :text => 'Missing Definitions Detected',
10
+ :path => missing_definitions_routes_path
11
+ %>
12
+ <% end %>
13
+ <% if @has_obsolete_definitions %>
14
+ <%= render 'information_warning_li',
15
+ :text => 'Obsolete Definitions Detected',
16
+ :path => obsolete_definitions_routes_path
17
+ %>
18
+ <% end %>
15
19
  <% end %>
16
20
  <% @routes.each do |controller, routes| %>
17
21
  <li class="nav-header"><%= controller %></li>
@@ -0,0 +1,12 @@
1
+ <%= render 'breadcrumb',
2
+ :parent => 'Information',
3
+ :current => 'Missing Definitions Detected',
4
+ :label => 'Warning',
5
+ :label_type => 'warning'
6
+ %>
7
+
8
+ <div class="alert alert-warning">
9
+ <p>The following route definitions are missing from <code>ApiTaster.routes</code>.</p>
10
+
11
+ <%= render 'route_definitions', :routes => @missing_definitions %>
12
+ </div>
@@ -5,14 +5,8 @@
5
5
  :label_type => 'warning'
6
6
  %>
7
7
 
8
- <div class="alert alert-error">
9
- <p><strong>The following route definitions are found within <code>ApiTaster.routes</code> but they are not defined in your routes. Please feel free to correct or remove them.</strong></p>
8
+ <div class="alert alert-warning">
9
+ <p>The following route definitions are found within <code>ApiTaster.routes</code> but they are not defined in your routes. Please feel free to correct or remove them.</p>
10
10
 
11
- <pre class="prettyprint lang-rb">ApiTaster.routes do
12
-
13
- <% @obsolete_definitions.each do |route| %>
14
- <%= route[:verb].downcase %> '<%= route[:path] %>'<%= ", #{route[:params]}" if route[:params].present? %>
15
-
16
- <% end %>
17
- end</pre>
11
+ <%= render 'route_definitions', :routes => @obsolete_definitions %>
18
12
  </div>
@@ -1,6 +1,9 @@
1
1
  ApiTaster::Engine.routes.draw do
2
2
  resources :routes, :only => [:index, :show] do
3
- get :obsolete_definitions, :on => :collection
3
+ collection do
4
+ get :missing_definitions
5
+ get :obsolete_definitions
6
+ end
4
7
  end
5
8
 
6
9
  root :to => 'routes#index'
@@ -8,7 +8,11 @@ module ApiTaster
8
8
  def self.routes(&block)
9
9
  Route.route_set = Rails.application.routes
10
10
  Route.inputs = {}
11
+ Route.missing_definitions = []
11
12
  Route.obsolete_definitions = []
13
+
12
14
  Mapper.instance_eval(&block)
15
+
16
+ Route.calculate_missing_definitions
13
17
  end
14
18
  end
@@ -20,16 +20,7 @@ module ApiTaster
20
20
 
21
21
  def add_to_buffer(params, parent_labels = [])
22
22
  params.each do |label, value|
23
- if value.is_a?(String)
24
- @_buffer += render(
25
- :partial => 'api_taster/routes/param_form_element',
26
- :locals => {
27
- :label => "#{print_labels(parent_labels)}#{label}",
28
- :label_text => label,
29
- :value => value
30
- }
31
- )
32
- else
23
+ if value.is_a?(Hash)
33
24
  parent_labels << label
34
25
 
35
26
  @_buffer += render(
@@ -38,10 +29,27 @@ module ApiTaster
38
29
  )
39
30
 
40
31
  add_to_buffer(value, parent_labels)
32
+ elsif value.is_a?(Array)
33
+ value.each do |v|
34
+ add_element_to_buffer(parent_labels, "[#{label}][]", v)
35
+ end
36
+ else
37
+ add_element_to_buffer(parent_labels, label, value)
41
38
  end
42
39
  end
43
40
  end
44
41
 
42
+ def add_element_to_buffer(parent_labels, label, value)
43
+ @_buffer += render(
44
+ :partial => 'api_taster/routes/param_form_element',
45
+ :locals => {
46
+ :label => "#{print_labels(parent_labels)}#{label}",
47
+ :label_text => label,
48
+ :value => value.to_s
49
+ }
50
+ )
51
+ end
52
+
45
53
  def print_labels(parent_labels)
46
54
  "[#{parent_labels * ']['}]"
47
55
  end
@@ -2,6 +2,7 @@ module ApiTaster
2
2
  class Route
3
3
  cattr_accessor :route_set
4
4
  cattr_accessor :inputs
5
+ cattr_accessor :missing_definitions
5
6
  cattr_accessor :obsolete_definitions
6
7
 
7
8
  class << self
@@ -13,7 +14,7 @@ module ApiTaster
13
14
  next if route.app.is_a?(Sprockets::Environment)
14
15
  next if route.app == ApiTaster::Engine
15
16
 
16
- if rack_app = discover_rack_app(route.app)
17
+ if (rack_app = discover_rack_app(route.app)) && rack_app.respond_to?(:routes)
17
18
  rack_app.routes.routes.each do |rack_route|
18
19
  _routes << normalise_route(rack_route, i+=1)
19
20
  end
@@ -50,8 +51,21 @@ module ApiTaster
50
51
  inputs[route[:id]].collect { |input| split_input(input, route) }
51
52
  end
52
53
 
54
+ def calculate_missing_definitions
55
+ routes.each do |route|
56
+ if undefined_route?(route)
57
+ self.missing_definitions << route
58
+ end
59
+ end
60
+ end
61
+
53
62
  private
54
63
 
64
+ def undefined_route?(route)
65
+ r = inputs_for(route)
66
+ r.is_a?(Hash) && r.has_key?(:undefined)
67
+ end
68
+
55
69
  def discover_rack_app(app)
56
70
  class_name = app.class.name.to_s
57
71
  if class_name == "ActionDispatch::Routing::Mapper::Constraints"
@@ -1,3 +1,3 @@
1
1
  module ApiTaster
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -18,6 +18,12 @@ module ApiTaster
18
18
  assigns(:inputs).should be_kind_of(Array)
19
19
  end
20
20
 
21
+ it "#missing_definitions" do
22
+ get :missing_definitions, :use_route => :api_taster
23
+
24
+ assigns(:missing_definitions).should be_kind_of(Array)
25
+ end
26
+
21
27
  it "#obsolete_definitions" do
22
28
  get :obsolete_definitions, :use_route => :api_taster
23
29
 
@@ -19,7 +19,7 @@ ApiTaster.routes do
19
19
  :user => {
20
20
  :name => 'Fred',
21
21
  :comment => {
22
- :title => 'hi!'
22
+ :title => [1, 2, 3]
23
23
  }
24
24
  }
25
25
  }
@@ -13,7 +13,9 @@ module ApiTaster
13
13
  FormBuilder.new({
14
14
  :hello => 'world',
15
15
  :nested => {
16
- :foo => 'bar'
16
+ :foo => 'bar',
17
+ :integer => 1,
18
+ :array => [1, 2, 3]
17
19
  }
18
20
  })
19
21
  end
@@ -25,5 +27,19 @@ module ApiTaster
25
27
  it "outputs html" do
26
28
  builder.html.should match('bar')
27
29
  end
30
+
31
+ context "data types" do
32
+ it "does strings" do
33
+ builder.html.should match('value="world"')
34
+ end
35
+
36
+ it "does numbers" do
37
+ builder.html.should match('value="1"')
38
+ end
39
+
40
+ it "does arrays" do
41
+ builder.html.should match(/name="\[nested\]\[array\]\[\]" value="2"/)
42
+ end
43
+ end
28
44
  end
29
45
  end
@@ -6,7 +6,7 @@ module ApiTaster
6
6
  before(:all) do
7
7
  routes = ActionDispatch::Routing::RouteSet.new
8
8
  routes.draw do
9
- # nothing
9
+ get '/awesome_route' => 'awesome#route'
10
10
  end
11
11
 
12
12
  ApiTaster.routes do
@@ -23,6 +23,7 @@ module ApiTaster
23
23
  resources :comments
24
24
  end
25
25
  mount Rails.application => '/app'
26
+ mount proc {} => '/rack_app'
26
27
  end
27
28
 
28
29
  Route.route_set = routes
@@ -71,6 +72,19 @@ module ApiTaster
71
72
  end
72
73
  end
73
74
 
75
+ it "#missing_definitions" do
76
+ routes = ActionDispatch::Routing::RouteSet.new
77
+ routes.draw do
78
+ get 'awesome_route' => 'awesome#route'
79
+ end
80
+ Rails.application.stub(:routes).and_return(routes)
81
+ ApiTaster.routes do
82
+ # nothing
83
+ end
84
+
85
+ Route.missing_definitions.first[:path].should == '/awesome_route'
86
+ end
87
+
74
88
  context "private methods" do
75
89
  it "#discover_rack_app" do
76
90
  klass = Class.new
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_taster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-21 00:00:00.000000000 Z
12
+ date: 2012-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -182,10 +182,13 @@ files:
182
182
  - app/controllers/api_taster/routes_controller.rb
183
183
  - app/helpers/api_taster/application_helper.rb
184
184
  - app/views/api_taster/routes/_breadcrumb.html.erb
185
+ - app/views/api_taster/routes/_information_warning_li.html.erb
185
186
  - app/views/api_taster/routes/_param_form_element.html.erb
186
187
  - app/views/api_taster/routes/_param_form_legend.html.erb
188
+ - app/views/api_taster/routes/_route_definitions.html.erb
187
189
  - app/views/api_taster/routes/_undefined_route.html.erb
188
190
  - app/views/api_taster/routes/index.html.erb
191
+ - app/views/api_taster/routes/missing_definitions.html.erb
189
192
  - app/views/api_taster/routes/obsolete_definitions.html.erb
190
193
  - app/views/api_taster/routes/show.html.erb
191
194
  - app/views/layouts/api_taster/application.html.erb
@@ -351,7 +354,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
351
354
  version: '0'
352
355
  segments:
353
356
  - 0
354
- hash: 2945703428300743977
357
+ hash: -907459549939205334
355
358
  required_rubygems_version: !ruby/object:Gem::Requirement
356
359
  none: false
357
360
  requirements:
@@ -360,7 +363,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
360
363
  version: '0'
361
364
  segments:
362
365
  - 0
363
- hash: 2945703428300743977
366
+ hash: -907459549939205334
364
367
  requirements: []
365
368
  rubyforge_project:
366
369
  rubygems_version: 1.8.24