swagger_yard 0.0.5

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 (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
+ }