ruby-swagger 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ruby-swagger.rb +7 -0
  3. data/lib/ruby-swagger/data/contact.rb +49 -0
  4. data/lib/ruby-swagger/data/definitions.rb +49 -0
  5. data/lib/ruby-swagger/data/document.rb +181 -0
  6. data/lib/ruby-swagger/data/example.rb +29 -0
  7. data/lib/ruby-swagger/data/external_documentation.rb +24 -0
  8. data/lib/ruby-swagger/data/header.rb +34 -0
  9. data/lib/ruby-swagger/data/headers.rb +48 -0
  10. data/lib/ruby-swagger/data/info.rb +56 -0
  11. data/lib/ruby-swagger/data/items.rb +45 -0
  12. data/lib/ruby-swagger/data/license.rb +51 -0
  13. data/lib/ruby-swagger/data/mime.rb +31 -0
  14. data/lib/ruby-swagger/data/operation.rb +82 -0
  15. data/lib/ruby-swagger/data/parameter.rb +88 -0
  16. data/lib/ruby-swagger/data/parameters.rb +53 -0
  17. data/lib/ruby-swagger/data/path.rb +115 -0
  18. data/lib/ruby-swagger/data/paths.rb +50 -0
  19. data/lib/ruby-swagger/data/reference.rb +30 -0
  20. data/lib/ruby-swagger/data/response.rb +25 -0
  21. data/lib/ruby-swagger/data/responses.rb +50 -0
  22. data/lib/ruby-swagger/data/schema.rb +68 -0
  23. data/lib/ruby-swagger/data/scopes.rb +44 -0
  24. data/lib/ruby-swagger/data/security_definitions.rb +49 -0
  25. data/lib/ruby-swagger/data/security_requirement.rb +35 -0
  26. data/lib/ruby-swagger/data/security_scheme.rb +67 -0
  27. data/lib/ruby-swagger/data/tag.rb +24 -0
  28. data/lib/ruby-swagger/data/url.rb +26 -0
  29. data/lib/ruby-swagger/data/xml_object.rb +15 -0
  30. data/lib/ruby-swagger/grape/grape.rb +2 -0
  31. data/lib/ruby-swagger/grape/grape_config.rb +160 -0
  32. data/lib/ruby-swagger/grape/grape_presenter.rb +48 -0
  33. data/lib/ruby-swagger/grape/grape_template.rb +67 -0
  34. data/lib/ruby-swagger/grape/method.rb +295 -0
  35. data/lib/ruby-swagger/grape/param.rb +33 -0
  36. data/lib/ruby-swagger/grape/route_path.rb +37 -0
  37. data/lib/ruby-swagger/grape/routes.rb +52 -0
  38. data/lib/ruby-swagger/grape/type.rb +141 -0
  39. data/lib/ruby-swagger/io/comparable.rb +30 -0
  40. data/lib/ruby-swagger/io/definitions.rb +48 -0
  41. data/lib/ruby-swagger/io/file_system.rb +97 -0
  42. data/lib/ruby-swagger/io/paths.rb +55 -0
  43. data/lib/ruby-swagger/io/security.rb +45 -0
  44. data/lib/ruby-swagger/object.rb +67 -0
  45. data/lib/ruby-swagger/railtie.rb +7 -0
  46. data/lib/ruby-swagger/template.rb +29 -0
  47. data/lib/tasks/swagger.rake +125 -0
  48. metadata +176 -0
@@ -0,0 +1,33 @@
1
+ require 'ruby-swagger/grape/type'
2
+
3
+ module Swagger::Grape
4
+ class Param
5
+
6
+ def initialize(param)
7
+ @param = param
8
+ end
9
+
10
+ def to_swagger
11
+ swagger_param = {}
12
+ swagger_param['description'] = @param[:desc] if @param[:desc].present?
13
+ swagger_param['default'] = @param[:default] if @param[:default].present?
14
+
15
+ swagger_param.merge! Swagger::Grape::Type.new(@param[:type]).to_swagger
16
+
17
+ swagger_param
18
+ end
19
+
20
+ def has_type_definition?
21
+ type.downcase == 'object'
22
+ end
23
+
24
+ def type_definition
25
+ (Object.const_get(type)).to_s
26
+ end
27
+
28
+ def type
29
+ @param[:type].to_s || 'string'
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ require 'ruby-swagger/data/path'
2
+ require 'ruby-swagger/data/operation'
3
+ require 'ruby-swagger/grape/method'
4
+
5
+ module Swagger::Grape
6
+ class RoutePath
7
+
8
+ attr_reader :types, :scopes
9
+
10
+ def initialize(route_name)
11
+ @name = route_name
12
+ @operations = {}
13
+ @types = []
14
+ @scopes = []
15
+ end
16
+
17
+ def add_operation(route)
18
+ method = Swagger::Grape::Method.new(@name, route)
19
+ grape_operation = method.operation
20
+
21
+ @types = (@types | method.types).uniq
22
+ @scopes = (@scopes | method.scopes).uniq
23
+ @operations[route.route_method.downcase] = grape_operation
24
+ end
25
+
26
+ def to_swagger
27
+ path = Swagger::Data::Path.new
28
+
29
+ @operations.each do |operation_verb, operation|
30
+ path.send("#{operation_verb}=", operation)
31
+ end
32
+
33
+ path
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,52 @@
1
+ require 'ruby-swagger/data/paths'
2
+ require 'ruby-swagger/data/path'
3
+ require 'ruby-swagger/grape/route_path'
4
+
5
+ module Swagger::Grape
6
+ class Routes
7
+
8
+ attr_reader :types, :scopes
9
+
10
+ def initialize(routes)
11
+ @routes = routes
12
+ @types = []
13
+ @scopes = []
14
+ end
15
+
16
+ def to_swagger
17
+ swagger = Swagger::Data::Paths.new
18
+ paths = {}
19
+
20
+ @routes.each do |route|
21
+
22
+ next if route.route_hidden == true #implement custom "hidden" extension
23
+
24
+ swagger_path_name = swagger_path_name(route)
25
+ paths[swagger_path_name] ||= Swagger::Grape::RoutePath.new(swagger_path_name)
26
+ paths[swagger_path_name].add_operation(route)
27
+ end
28
+
29
+ paths.each do |path_name, path|
30
+ swagger.add_path(path_name, path.to_swagger)
31
+ @types = (@types | path.types).uniq
32
+ @scopes = (@scopes | path.scopes).uniq
33
+ end
34
+
35
+ swagger
36
+ end
37
+
38
+ private
39
+
40
+ def swagger_path_name(grape_route)
41
+ grape_path_name = grape_route.route_path
42
+ grape_prefix = grape_route.route_prefix
43
+ grape_path_name.gsub!(/^\/#{grape_prefix}/, '') if grape_prefix
44
+ grape_path_name.gsub!(/^\/:version/, '') #remove api version - if any
45
+ grape_path_name.gsub!(/\(\.:format\)$/, '') #remove api format - if any
46
+ grape_path_name.gsub!(/\(\..+\)$/, '') #remove api format - if any
47
+ grape_path_name.gsub!(/\/:([a-zA-Z0-9_]+)/, '/{\1}') #convert parameters from :format into {format}
48
+ grape_path_name
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,141 @@
1
+ module Swagger::Grape
2
+ class Type
3
+
4
+ attr_reader :discovered_types
5
+
6
+ def initialize(type)
7
+ @type = type.to_s || 'String'
8
+ end
9
+
10
+ def to_swagger(with_definition = true)
11
+ type_convert(@type.to_s, with_definition)
12
+ end
13
+
14
+ def sub_types
15
+ type = Object.const_get(@type)
16
+ return [] unless type.respond_to?(:exposures)
17
+
18
+ types = []
19
+
20
+ type.exposures.each do |property, definition|
21
+ types << definition[:using] if definition[:using].present?
22
+ end
23
+
24
+ types.uniq
25
+ end
26
+
27
+ private
28
+
29
+ def type_convert(type, with_definition = true)
30
+ swagger_type = {}
31
+
32
+ case type.downcase
33
+ when 'string'
34
+ swagger_type['type'] = 'string'
35
+ when 'integer'
36
+ swagger_type['type'] = 'integer'
37
+ when 'array'
38
+ swagger_type['type'] = 'array'
39
+ swagger_type['items'] = {'type' => 'string'}
40
+ when 'hash'
41
+ swagger_type['type'] = 'object'
42
+ swagger_type['properties'] = {}
43
+ when 'boolean'
44
+ swagger_type['type'] = 'boolean'
45
+ when 'virtus::attribute::boolean'
46
+ swagger_type['type'] = 'boolean'
47
+ when 'symbol'
48
+ swagger_type['type'] = 'string'
49
+ when 'float'
50
+ swagger_type['type'] = 'number'
51
+ swagger_type['format'] = 'float'
52
+ when 'rack::multipart::uploadedfile'
53
+ swagger_type['type'] = 'string'
54
+ STDERR.puts "Warning - I have no idea how to handle the type file. Right now I will consider this a string, but we should probably handle it..."
55
+ when 'date'
56
+ swagger_type['type'] = 'date'
57
+ when 'datetime'
58
+ swagger_type['format'] = 'date-time'
59
+ swagger_type['format'] = 'string'
60
+ else
61
+ swagger_type['type'] = "object"
62
+
63
+ if with_definition
64
+ # I can just reference the name of the object here
65
+ swagger_type['$ref'] = "#/definitions/#{type}"
66
+ else
67
+ type = Object.const_get(@type)
68
+ # I need to define the full object
69
+ raise ArgumentError.new("Don't know how to translate the object #{@type}") unless type.respond_to?(:exposures)
70
+
71
+ swagger_type['properties'] = {}
72
+
73
+ type.exposures.each do |property, definition|
74
+
75
+ cursor = swagger_type
76
+ target = property.to_s
77
+
78
+ if definition[:nested]
79
+ # it's a nested parameter
80
+ path = target.split('__')
81
+ cursor = find_elem_in_schema(cursor, path.dup)
82
+ target = path.last
83
+ end
84
+
85
+ target = definition[:as].to_s if definition[:as].present?
86
+
87
+ cursor['properties'][target] = {}
88
+
89
+ if definition[:documentation].present? && definition[:documentation][:type].present?
90
+ cursor['properties'][target] = type_convert(definition[:documentation][:type].to_s, true)
91
+ end
92
+
93
+ if definition[:using].present?
94
+ #it's either an object or an array of object
95
+ using = type_convert(definition[:using].to_s, true)
96
+
97
+ if cursor['type'].present? && cursor['type'] == 'array'
98
+ cursor['items'] = using
99
+ else
100
+ cursor['properties'][target] = using
101
+ end
102
+
103
+ end
104
+
105
+ cursor['properties'][target]['description'] = definition[:documentation][:desc] if definition[:documentation].present?
106
+ cursor['properties'][target]['type'] ||= 'string' #no type defined, assuming it's a string
107
+ end
108
+ end
109
+ end
110
+
111
+ swagger_type
112
+ end
113
+
114
+ def find_elem_in_schema(root, schema_path)
115
+ return root if schema_path.nil? || schema_path.empty?
116
+
117
+ next_elem = schema_path.shift
118
+
119
+ return root if root['properties'][next_elem].nil?
120
+
121
+ case root['properties'][next_elem]['type']
122
+ when 'array'
123
+ #to descend an array this must be an array of objects
124
+ root['properties'][next_elem]['items']['type'] = 'object'
125
+ root['properties'][next_elem]['items']['properties'] ||= {}
126
+
127
+ find_elem_in_schema(root['properties'][next_elem]['items'], schema_path)
128
+ when 'object'
129
+ find_elem_in_schema(root['properties'][next_elem], schema_path)
130
+ else
131
+ # I'm discending an object that before I assumed was something else
132
+ root['properties'][next_elem]['type'] = 'object'
133
+ root['properties'][next_elem]['properties'] ||= {}
134
+
135
+ find_elem_in_schema(root['properties'][next_elem], schema_path)
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,30 @@
1
+ module Swagger::IO
2
+ class Comparable
3
+
4
+ def self.copy_description_old_definition(definition, old_definition)
5
+ return if definition.nil? || old_definition.nil? || definition.class != old_definition.class
6
+
7
+ case definition
8
+ when Hash
9
+
10
+ definition.keys.each do |key|
11
+ old_v = definition[key]
12
+
13
+ if (key == 'description' || key == 'summary') && old_definition[key]
14
+ definition[key] = old_definition[key]
15
+ end
16
+
17
+ if old_v.is_a?(Hash) || old_v.is_a?(Array)
18
+ copy_description_old_definition(definition[key], old_definition[key])
19
+ end
20
+ end
21
+ when Array
22
+ definition.each_with_index do |item, index|
23
+ copy_description_old_definition(definition[index], old_definition[index])
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,48 @@
1
+ require 'ruby-swagger/io/file_system'
2
+ require 'ruby-swagger/io/comparable'
3
+
4
+ module Swagger::IO
5
+ class Definitions
6
+
7
+ def self.read_definitions
8
+ definitions = {}
9
+
10
+ Swagger::IO::FileSystem.all_files("definitions/**/*.yml").each do |file|
11
+ definitions[File.basename(file, ".yml")] = YAML::load_file(file)
12
+ end
13
+
14
+ definitions
15
+ end
16
+
17
+ def self.write_definitions(definitions)
18
+ return if definitions.nil?
19
+
20
+ #Remove dead definitions
21
+ Swagger::IO::FileSystem.all_files("definitions/**/*.yml").each do |file|
22
+ def_name = File.basename(file, ".yml")
23
+
24
+ unless definitions[def_name]
25
+ STDERR.puts "#{def_name} is not present anymore, removing #{file}"
26
+ Swagger::IO::FileSystem.delete_file(file)
27
+ end
28
+
29
+ end
30
+
31
+ # Write new definitions
32
+ definitions.each do |definition_name, definition|
33
+
34
+ # If an old definition exists, we copy over the documentation to the generated definition
35
+ if Swagger::IO::FileSystem.file_exists?("definitions/#{definition_name}.yml")
36
+ old_definition = Swagger::IO::FileSystem.read_file("definitions/#{definition_name}.yml")
37
+
38
+ Swagger::IO::Comparable.copy_description_old_definition(definition, old_definition)
39
+ end
40
+
41
+ Swagger::IO::FileSystem.write_file(definition.to_yaml, "definitions/#{definition_name}.yml", true)
42
+ end
43
+ end
44
+
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,97 @@
1
+ require 'ruby-swagger/object'
2
+ require 'ruby-swagger/data/document'
3
+ require 'ruby-swagger/io/security'
4
+ require 'ruby-swagger/io/definitions'
5
+ require 'ruby-swagger/io/paths'
6
+
7
+ module Swagger::IO
8
+ class FileSystem
9
+
10
+ DOC_SUBPARTS = %w(responses security tags)
11
+
12
+ @@default_path = './doc/swagger'
13
+
14
+ def self.default_path=(new_path)
15
+ @@default_path = new_path
16
+ end
17
+
18
+ def self.default_path
19
+ @@default_path
20
+ end
21
+
22
+ def self.init_fs_structure
23
+ FileUtils.mkdir_p(@@default_path) unless Dir.exists?(@@default_path)
24
+ end
25
+
26
+ def self.read_file(name)
27
+ YAML::load_file(@@default_path + '/' + name)
28
+ end
29
+
30
+ def self.write_file(content, location, overwrite = false)
31
+ file_path = @@default_path + '/' + location
32
+
33
+ return if !overwrite && File.exists?(file_path)
34
+
35
+ dir_path = File.dirname(file_path)
36
+
37
+ FileUtils.mkdir_p(dir_path) unless Dir.exists?(dir_path)
38
+ File.open(file_path, 'w') {|f| f.write(content) }
39
+ end
40
+
41
+ def self.file_exists?(name)
42
+ File.exists?(@@default_path + '/' + name)
43
+ end
44
+
45
+ def self.all_files(pattern)
46
+ Dir["#{@@default_path}/#{pattern}"]
47
+ end
48
+
49
+ def self.delete_file(file)
50
+ FileUtils.rm_f(file)
51
+ end
52
+
53
+ def initialize(swagger_doc)
54
+ @doc = swagger_doc
55
+ end
56
+
57
+ def write!
58
+ Swagger::IO::FileSystem.init_fs_structure
59
+
60
+ swagger = @doc.to_swagger
61
+
62
+ Swagger::IO::Paths.write_paths(swagger.delete('paths'))
63
+
64
+ DOC_SUBPARTS.each {|doc_part| write_subpart(doc_part, swagger.delete(doc_part))}
65
+ Swagger::IO::Definitions.write_definitions(swagger.delete('definitions'))
66
+ Swagger::IO::Security.write_security_definitions(swagger.delete('securityDefinitions'))
67
+ Swagger::IO::FileSystem.write_file(swagger.to_yaml, 'base_doc.yml')
68
+ end
69
+
70
+ def self.read
71
+ doc = YAML::load_file("#{default_path}/base_doc.yml")
72
+
73
+ DOC_SUBPARTS.each do |doc_part|
74
+ file_path = "#{default_path}/#{doc_part}.yml"
75
+ doc[doc_part] = YAML::load_file(file_path) if File.exists?(file_path)
76
+ end
77
+
78
+ doc['paths'] = Swagger::IO::Paths.read_paths
79
+ doc['definitions'] = Swagger::IO::Definitions.read_definitions
80
+ doc['securityDefinitions'] = Swagger::IO::Security.read_security_definitions
81
+
82
+ Swagger::Data::Document.parse(doc)
83
+ end
84
+
85
+ def compile!
86
+ Swagger::IO::FileSystem.write_file(JSON.pretty_generate(@doc.to_swagger), 'swagger.json', true)
87
+ end
88
+
89
+ private
90
+
91
+ def write_subpart(subpart, content)
92
+ return unless content
93
+ write_file(content.to_yaml, "#{subpart}.yml")
94
+ end
95
+
96
+ end
97
+ end