swagger_yard 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +113 -0
  4. data/Rakefile +40 -0
  5. data/app/controllers/swagger_yard/application_controller.rb +4 -0
  6. data/app/controllers/swagger_yard/swagger_controller.rb +21 -0
  7. data/app/views/swagger_yard/swagger/doc.html.erb +80 -0
  8. data/config/routes.rb +6 -0
  9. data/lib/generators/swagger_yard/doc_generator.rb +11 -0
  10. data/lib/generators/swagger_yard/js_generator.rb +13 -0
  11. data/lib/swagger_yard.rb +113 -0
  12. data/lib/swagger_yard/api.rb +132 -0
  13. data/lib/swagger_yard/api_declaration.rb +42 -0
  14. data/lib/swagger_yard/cache.rb +50 -0
  15. data/lib/swagger_yard/engine.rb +18 -0
  16. data/lib/swagger_yard/local_dispatcher.rb +51 -0
  17. data/lib/swagger_yard/parameter.rb +9 -0
  18. data/lib/swagger_yard/parser.rb +35 -0
  19. data/lib/swagger_yard/resource_listing.rb +32 -0
  20. data/lib/swagger_yard/version.rb +3 -0
  21. data/public/swagger-ui/css/hightlight.default.css +135 -0
  22. data/public/swagger-ui/css/screen.css +1759 -0
  23. data/public/swagger-ui/images/logo_small.png +0 -0
  24. data/public/swagger-ui/images/pet_store_api.png +0 -0
  25. data/public/swagger-ui/images/throbber.gif +0 -0
  26. data/public/swagger-ui/images/wordnik_api.png +0 -0
  27. data/public/swagger-ui/lib/MD5.js +319 -0
  28. data/public/swagger-ui/lib/backbone-min.js +38 -0
  29. data/public/swagger-ui/lib/handlebars-1.0.rc.1.js +1920 -0
  30. data/public/swagger-ui/lib/highlight.7.3.pack.js +1 -0
  31. data/public/swagger-ui/lib/jquery-1.8.0.min.js +2 -0
  32. data/public/swagger-ui/lib/jquery.ba-bbq.min.js +18 -0
  33. data/public/swagger-ui/lib/jquery.slideto.min.js +1 -0
  34. data/public/swagger-ui/lib/jquery.wiggle.min.js +8 -0
  35. data/public/swagger-ui/lib/swagger.js +794 -0
  36. data/public/swagger-ui/lib/underscore-min.js +32 -0
  37. data/public/swagger-ui/swagger-ui.js +2090 -0
  38. data/public/swagger-ui/swagger-ui_org.js +2005 -0
  39. metadata +125 -0
@@ -0,0 +1,132 @@
1
+ module SwaggerYard
2
+ class Api
3
+ attr_reader :nickname
4
+ attr_accessor :path, :parameters, :description, :http_method, :response_class, :summary, :notes, :error_responses
5
+
6
+ def initialize(yard_object)
7
+ @description = yard_object.docstring
8
+ @parameters = []
9
+
10
+ yard_object.tags.each do |tag|
11
+ value = tag.text
12
+
13
+ case tag.tag_name
14
+ when "path"
15
+ parse_path(value)
16
+ when "parameter"
17
+ @parameters << parse_parameter(value)
18
+ when "parameter_list"
19
+ @parameters << parse_parameter_list(value)
20
+ when "summary"
21
+ @summary = value
22
+ when "notes"
23
+ @notes = value.gsub("\n", "<br\>")
24
+ end
25
+ end
26
+
27
+ @parameters.sort_by { |parameter| parameter["name"] }
28
+ @parameters << add_format_parameters
29
+ end
30
+
31
+ def nickname
32
+ @nickname ||= "#{http_method}".camelize
33
+ end
34
+
35
+ def operation
36
+ {
37
+ "httpMethod" => http_method,
38
+ "nickname" => path[1..-1].gsub(/[^a-zA-Z\d:]/, '-').squeeze("-") + http_method.downcase,
39
+ "responseClass" => response_class || "void",
40
+ "produces" => ["application/json", "application/xml"],
41
+ "parameters" => parameters,
42
+ "summary" => summary || description,
43
+ "notes" => notes,
44
+ "errorResponses" => error_responses
45
+ }
46
+ end
47
+
48
+ def to_h
49
+ {
50
+ "path" => path,
51
+ "description" => description,
52
+ "operations" => [operation],
53
+ }
54
+ end
55
+
56
+ def valid?
57
+ path.present?
58
+ end
59
+
60
+ private
61
+ ##
62
+ # Example: [GET] /api/v2/ownerships.{format_type}
63
+ def parse_path(string)
64
+ @http_method, @path = string.match(/^\[(\w*)\]\s*(.*)$/).captures
65
+
66
+ path_params = @path.scan(/\{([^\}]+)\}/).flatten.reject { |value| value == "format_type" }
67
+
68
+ path_params.each do |path_param|
69
+ @parameters << {
70
+ "paramType" => "path",
71
+ "name" => path_param,
72
+ "description" => "Scope response to #{path_param}",
73
+ "dataType" => "string",
74
+ "required" => true,
75
+ "allowMultiple" => false
76
+ }
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Example: [Array] status Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
82
+ # Example: [Array] status(required) Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
83
+ # Example: [Integer] media[media_type_id] ID of the desired media type.
84
+ def parse_parameter(string)
85
+ data_type, name, required, description = string.match(/\A\[(\w*)\]\s*([\w\[\]]*)(\(required\))?\s*(.*)\Z/).captures
86
+ allow_multiple = name.gsub!("[]", "")
87
+
88
+ parameter = {
89
+ "paramType" => "query",
90
+ "name" => name,
91
+ "description" => description,
92
+ "dataType" => data_type.downcase,
93
+ "required" => required.present?,
94
+ "allowMultiple" => allow_multiple.present?
95
+ }
96
+ end
97
+
98
+ ##
99
+ # Example: [String] sort_order Orders ownerships by fields. (e.g. sort_order=created_at)
100
+ # [List] id
101
+ # [List] begin_at
102
+ # [List] end_at
103
+ # [List] created_at
104
+ def parse_parameter_list(string)
105
+ data_type, name, required, description, set_string = string.match(/\A\[(\w*)\]\s*(\w*)(\(required\))?\s*(.*)\n([.\s\S]*)\Z/).captures
106
+
107
+ list_values = set_string.split("[List]").map(&:strip).reject { |string| string.empty? }
108
+
109
+ parameter = {
110
+ "paramType" => "query",
111
+ "name" => name,
112
+ "description" => description,
113
+ "dataType" => data_type.downcase,
114
+ "required" => required.present?,
115
+ "allowMultiple" => false,
116
+ "allowableValues" => {"valueType" => 'LIST', "values" => list_values}
117
+ }
118
+ end
119
+
120
+ def add_format_parameters
121
+ @add_format_parameters ||= {
122
+ "paramType" => "path",
123
+ "name" => "format_type",
124
+ "description" => "Response format either JSON or XML",
125
+ "dataType" => "string",
126
+ "required" => true,
127
+ "allowMultiple" => false,
128
+ "allowableValues" => {"valueType" => "LIST", "values" => ["json", "xml"]}
129
+ }
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,42 @@
1
+ module SwaggerYard
2
+ class ApiDeclaration
3
+ attr_accessor :description, :resource_path
4
+
5
+ def initialize
6
+ @apis = {}
7
+ @models = []
8
+ end
9
+
10
+ def add_listing_info(yard_object)
11
+ @description = yard_object.docstring if yard_object.docstring.present?
12
+ tag = yard_object.tags.find { |tag| tag.tag_name == "resource_path"}
13
+ @resource_path = tag.text.downcase if tag.present?
14
+ tag.present?
15
+ end
16
+
17
+ def add_api(api)
18
+ if @apis.keys.include?(api.path)
19
+ same_api_path = @apis[api.path]
20
+ same_api_path["operations"] << api.operation
21
+ @apis[api.path] = same_api_path
22
+ else
23
+ @apis[api.path] = api.to_h
24
+ end
25
+ end
26
+
27
+ def resource_name
28
+ @resource_path
29
+ end
30
+
31
+ def to_h
32
+ {
33
+ "apiVersion" => SwaggerYard.api_version,
34
+ "swaggerVersion" => SwaggerYard.swagger_version,
35
+ "basePath" => SwaggerYard.api_base_path,
36
+ "resource_path" => @resource_path,
37
+ "apis" => @apis.values,
38
+ "models" => @models
39
+ }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,50 @@
1
+ module SwaggerYard
2
+ # For now just a simple wrapper class for a Memcache client.
3
+ class Cache
4
+
5
+ attr_reader :prefix, :store
6
+
7
+ def initialize(store, prefix)
8
+ @store = store
9
+ @prefix = prefix
10
+ end
11
+
12
+ # Read from the Cache.
13
+ def [](resource_name)
14
+ case
15
+ when store.respond_to?(:read)
16
+ store.read key_for(resource_name)
17
+ when store.respond_to?(:[])
18
+ store[key_for(resource_name)]
19
+ when store.respond_to?(:get)
20
+ store.get key_for(resource_name)
21
+ end
22
+ end
23
+
24
+ # Write to the Cache.
25
+ def []=(resource_name, value)
26
+ case
27
+ when store.respond_to?(:write)
28
+ store.write key_for(resource_name), value
29
+ when store.respond_to?(:[]=)
30
+ store[key_for(resource_name)] = value
31
+ when store.respond_to?(:set)
32
+ store.set key_for(resource_name), value
33
+ end
34
+ end
35
+
36
+ def fetch(resource_name)
37
+ value = self[resource_name]
38
+ if value.nil? && block_given?
39
+ value = yield
40
+ self[resource_name] = yield
41
+ end
42
+ value
43
+ end
44
+
45
+ # Cache key for a given entry.
46
+ def key_for(resource_name)
47
+ [prefix, resource_name].join
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,18 @@
1
+ require "swagger_yard/local_dispatcher"
2
+
3
+ module SwaggerYard
4
+ class Engine < ::Rails::Engine
5
+ if SwaggerYard::LocalDispatcher.new.server?
6
+ isolate_namespace SwaggerYard
7
+
8
+ # NOTE: We should opt for asset pipeline instead of this.
9
+ initializer 'swagger_yard.load_static_assets' do |app|
10
+ app.middleware.use(::ActionDispatch::Static, "#{root}/public")
11
+ end
12
+
13
+ initializer "swagger_yard.finisher_hook" do |app|
14
+ SwaggerYard.generate!("#{app.root}/app/controllers/**/*.rb")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ module SwaggerYard
2
+ # An instance of LocalEnvironment is responsible for determining the dispatcher.
3
+ # This is useful to determine whether or not to run SwaggerYard#generate!.
4
+ #
5
+ # Implementation heavily borrowed from NewRelic.
6
+ class LocalDispatcher
7
+ def discovered_dispatcher
8
+ discover_dispatcher unless @discovered_dispatcher
9
+ @discovered_dispatcher
10
+ end
11
+
12
+ def server?
13
+ [:thin, :unicorn].include?(discovered_dispatcher)
14
+ end
15
+
16
+ private
17
+
18
+ def discover_dispatcher
19
+ dispatchers = %w[sidekiq thin unicorn]
20
+ while dispatchers.any? && @discovered_dispatcher.nil?
21
+ send 'check_for_' + (dispatchers.shift)
22
+ end
23
+ end
24
+
25
+ def find_class_in_object_space(klass)
26
+ ObjectSpace.each_object(klass) do |x|
27
+ return x
28
+ end
29
+ return nil
30
+ end
31
+
32
+ def check_for_unicorn
33
+ if defined?(::Unicorn) && defined?(::Unicorn::HttpServer)
34
+ v = find_class_in_object_space(::Unicorn::HttpServer)
35
+ @discovered_dispatcher = :unicorn if v
36
+ end
37
+ end
38
+
39
+ def check_for_sidekiq
40
+ if defined?(::Sidekiq) && File.basename($0) == 'sidekiq'
41
+ @discovered_dispatcher = :sidekiq
42
+ end
43
+ end
44
+
45
+ def check_for_thin
46
+ if defined?(::Thin) && defined?(::Thin::VERSION)
47
+ @discovered_dispatcher = :thin
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ module SwaggerYard
2
+ class Parameter
3
+ attr_accessor :param_type, :name, :description, :data_type, :required, :allow_multiple, :allowable_values
4
+
5
+ def initialize(yard_object)
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'api'
2
+ require_relative 'api_declaration'
3
+ require_relative 'resource_listing'
4
+
5
+ module SwaggerYard
6
+ class Parser
7
+ attr_reader :listing
8
+
9
+ def initialize
10
+ @listing = ResourceListing.new
11
+ end
12
+
13
+ def run(yard_objects)
14
+ api_declaration = ApiDeclaration.new
15
+ retain_api = true
16
+
17
+ yard_objects.each do |yard_object|
18
+ case yard_object.type
19
+ when :class
20
+ break unless retain_api = api_declaration.add_listing_info(yard_object)
21
+ when :method
22
+ api = Api.new(yard_object)
23
+ api_declaration.add_api(api) if api.valid?
24
+ end
25
+ end
26
+
27
+ if retain_api
28
+ @listing.add(api_declaration)
29
+ api_declaration
30
+ else
31
+ nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ module SwaggerYard
2
+ class ResourceListing
3
+ attr_reader :api_declarations
4
+
5
+ def initialize
6
+ @api_declarations = []
7
+ end
8
+
9
+ def add(api_declaration)
10
+ @api_declarations << api_declaration
11
+ end
12
+
13
+ def to_h
14
+ {
15
+ "apiVersion" => SwaggerYard.api_version,
16
+ "swaggerVersion" => SwaggerYard.swagger_version,
17
+ "basePath" => SwaggerYard.doc_base_path,
18
+ "apis" => list_api
19
+ }
20
+ end
21
+
22
+ private
23
+ def list_api
24
+ @api_declarations.map do |api_declaration|
25
+ {
26
+ "path" => api_declaration.resource_path,
27
+ "description" => api_declaration.description
28
+ }
29
+ end.sort_by { |hsh| hsh["path"] }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module SwaggerYard
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,135 @@
1
+ /*
2
+
3
+ Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
4
+
5
+ */
6
+
7
+ pre code {
8
+ display: block; padding: 0.5em;
9
+ background: #F0F0F0;
10
+ }
11
+
12
+ pre code,
13
+ pre .subst,
14
+ pre .tag .title,
15
+ pre .lisp .title,
16
+ pre .clojure .built_in,
17
+ pre .nginx .title {
18
+ color: black;
19
+ }
20
+
21
+ pre .string,
22
+ pre .title,
23
+ pre .constant,
24
+ pre .parent,
25
+ pre .tag .value,
26
+ pre .rules .value,
27
+ pre .rules .value .number,
28
+ pre .preprocessor,
29
+ pre .ruby .symbol,
30
+ pre .ruby .symbol .string,
31
+ pre .aggregate,
32
+ pre .template_tag,
33
+ pre .django .variable,
34
+ pre .smalltalk .class,
35
+ pre .addition,
36
+ pre .flow,
37
+ pre .stream,
38
+ pre .bash .variable,
39
+ pre .apache .tag,
40
+ pre .apache .cbracket,
41
+ pre .tex .command,
42
+ pre .tex .special,
43
+ pre .erlang_repl .function_or_atom,
44
+ pre .markdown .header {
45
+ color: #800;
46
+ }
47
+
48
+ pre .comment,
49
+ pre .annotation,
50
+ pre .template_comment,
51
+ pre .diff .header,
52
+ pre .chunk,
53
+ pre .markdown .blockquote {
54
+ color: #888;
55
+ }
56
+
57
+ pre .number,
58
+ pre .date,
59
+ pre .regexp,
60
+ pre .literal,
61
+ pre .smalltalk .symbol,
62
+ pre .smalltalk .char,
63
+ pre .go .constant,
64
+ pre .change,
65
+ pre .markdown .bullet,
66
+ pre .markdown .link_url {
67
+ color: #080;
68
+ }
69
+
70
+ pre .label,
71
+ pre .javadoc,
72
+ pre .ruby .string,
73
+ pre .decorator,
74
+ pre .filter .argument,
75
+ pre .localvars,
76
+ pre .array,
77
+ pre .attr_selector,
78
+ pre .important,
79
+ pre .pseudo,
80
+ pre .pi,
81
+ pre .doctype,
82
+ pre .deletion,
83
+ pre .envvar,
84
+ pre .shebang,
85
+ pre .apache .sqbracket,
86
+ pre .nginx .built_in,
87
+ pre .tex .formula,
88
+ pre .erlang_repl .reserved,
89
+ pre .prompt,
90
+ pre .markdown .link_label,
91
+ pre .vhdl .attribute,
92
+ pre .clojure .attribute,
93
+ pre .coffeescript .property {
94
+ color: #88F
95
+ }
96
+
97
+ pre .keyword,
98
+ pre .id,
99
+ pre .phpdoc,
100
+ pre .title,
101
+ pre .built_in,
102
+ pre .aggregate,
103
+ pre .css .tag,
104
+ pre .javadoctag,
105
+ pre .phpdoc,
106
+ pre .yardoctag,
107
+ pre .smalltalk .class,
108
+ pre .winutils,
109
+ pre .bash .variable,
110
+ pre .apache .tag,
111
+ pre .go .typename,
112
+ pre .tex .command,
113
+ pre .markdown .strong,
114
+ pre .request,
115
+ pre .status {
116
+ font-weight: bold;
117
+ }
118
+
119
+ pre .markdown .emphasis {
120
+ font-style: italic;
121
+ }
122
+
123
+ pre .nginx .built_in {
124
+ font-weight: normal;
125
+ }
126
+
127
+ pre .coffeescript .javascript,
128
+ pre .javascript .xml,
129
+ pre .tex .formula,
130
+ pre .xml .javascript,
131
+ pre .xml .vbscript,
132
+ pre .xml .css,
133
+ pre .xml .cdata {
134
+ opacity: 0.5;
135
+ }