restility 0.0.3
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.
- data/License.txt +340 -0
- data/bin/rest_doc +120 -0
- data/bin/rest_test +151 -0
- data/config/hoe.rb +68 -0
- data/config/requirements.rb +16 -0
- data/lib/doc_book_printer.rb +158 -0
- data/lib/rest.rb +459 -0
- data/lib/rest_htmlprinter.rb +191 -0
- data/lib/rest_test.rb +351 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +9 -0
- data/test/test_helper.rb +2 -0
- data/test/test_restility.rb +11 -0
- metadata +94 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require "rest"
|
4
|
+
|
5
|
+
class DocBookPrinter < Printer
|
6
|
+
|
7
|
+
attr_accessor :output_dir
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super()
|
11
|
+
@output_dir = "docbook"
|
12
|
+
@xml_examples = Hash.new
|
13
|
+
@xml_schemas = Hash.new
|
14
|
+
@section = 0
|
15
|
+
|
16
|
+
@html_tag_mapping = {
|
17
|
+
"tt" => nil,
|
18
|
+
"em" => "emphasis",
|
19
|
+
"b" => "emphasis",
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def do_prepare
|
24
|
+
unless File.exists? @output_dir
|
25
|
+
Dir.mkdir @output_dir
|
26
|
+
end
|
27
|
+
|
28
|
+
@index = File.new @output_dir + "/rest_api_appendix.xml", "w"
|
29
|
+
@xml = Builder::XmlMarkup.new :target => @index, :indent => 2
|
30
|
+
@xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
31
|
+
@xml.declare! :DOCTYPE, :appendix, :PUBLIC, "-//Novell//DTD NovDoc XML V1.0//EN", "novdocx.dtd" do |x|
|
32
|
+
x.declare! :ENTITY, :%, :'NOVDOC.DEACTIVATE.IDREF', "IGNORE"
|
33
|
+
x.declare! :ENTITY, :%, :entities, :SYSTEM, "entity-decl.ent"
|
34
|
+
x << " %entities;\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
@xml.comment! "This file was generated by restility at #{Time.now}"
|
38
|
+
|
39
|
+
@xml << "<appendix xml:base=\"rest_api_appendix.xml\" id=\"app.rest_api_doc\">\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
def do_finish
|
43
|
+
@xml << "</appendix>\n"
|
44
|
+
puts "Written #{@index.path}"
|
45
|
+
@index.close
|
46
|
+
end
|
47
|
+
|
48
|
+
def print_section section
|
49
|
+
if !section.root?
|
50
|
+
level = section.level - 1
|
51
|
+
|
52
|
+
if level.zero?
|
53
|
+
@xml.title section
|
54
|
+
@xml.para
|
55
|
+
section.print_children self
|
56
|
+
else
|
57
|
+
@xml.tag! "sect#{level}", "id" => "app.rest_api_doc.sect#{level}.#{@section}" do
|
58
|
+
@section += 1
|
59
|
+
@xml.title section
|
60
|
+
section.print_children self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
section.print_children self
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def print_request request
|
69
|
+
@xml.variablelist do
|
70
|
+
@xml.varlistentry do
|
71
|
+
|
72
|
+
@xml.term do
|
73
|
+
@xml.literal request.to_s
|
74
|
+
end
|
75
|
+
|
76
|
+
@xml.listitem do
|
77
|
+
request.parameters.each do |p|
|
78
|
+
@xml.para do
|
79
|
+
@xml.emphasis p.name
|
80
|
+
@xml << " (optional)" if p.optional
|
81
|
+
@xml << " - #{p.description}" if p.description && !p.description.empty?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
request.print_children self
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def replace_html_tags text
|
92
|
+
@html_tag_mapping.each do |html, docbook|
|
93
|
+
if docbook.nil?
|
94
|
+
text.gsub! "<#{html}>", ""
|
95
|
+
else
|
96
|
+
text.gsub! "<#{html}>", "<#{docbook}>"
|
97
|
+
text.gsub! "</#{html}>", "</#{docbook}>"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def print_text text
|
103
|
+
@xml.para do |p|
|
104
|
+
text.text.each do |t|
|
105
|
+
replace_html_tags t
|
106
|
+
p << t << "\n"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def print_parameter parameter
|
112
|
+
end
|
113
|
+
|
114
|
+
def print_host host
|
115
|
+
@xml.para "Host: " + host.name
|
116
|
+
end
|
117
|
+
|
118
|
+
def print_result result
|
119
|
+
@xml.para "Result: #{result.name}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def print_body body
|
123
|
+
@xml.para "Body: #{body.name}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def print_xmlresult result
|
127
|
+
print_xml_links result.name, result.schema
|
128
|
+
end
|
129
|
+
|
130
|
+
def print_xmlbody body
|
131
|
+
print_xml_links body.name, body.schema
|
132
|
+
end
|
133
|
+
|
134
|
+
def print_xml_links xmlname, schema
|
135
|
+
example = xmlname + ".xml"
|
136
|
+
if !schema || schema.empty?
|
137
|
+
schema = xmlname + ".xsd"
|
138
|
+
end
|
139
|
+
|
140
|
+
if XmlFile.exist? example
|
141
|
+
@xml.screen File.read(XmlFile.find_file example)
|
142
|
+
end
|
143
|
+
|
144
|
+
if XmlFile.exist? schema
|
145
|
+
@xml.screen File.read(XmlFile.find_file schema)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def print_contents contents
|
150
|
+
# empty, the content is generated by docbook itself
|
151
|
+
@xml.para
|
152
|
+
end
|
153
|
+
|
154
|
+
def print_version version
|
155
|
+
@xml.para "API Version: #{version}"
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
data/lib/rest.rb
ADDED
@@ -0,0 +1,459 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
class XmlFile
|
4
|
+
|
5
|
+
@@include_dir = ""
|
6
|
+
|
7
|
+
def XmlFile.include_dir= dir
|
8
|
+
if !dir
|
9
|
+
dir = ""
|
10
|
+
end
|
11
|
+
@@include_dir = dir
|
12
|
+
end
|
13
|
+
|
14
|
+
def XmlFile.exist? file_name
|
15
|
+
exists? file_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def XmlFile.exists? file_name
|
19
|
+
find_file file_name
|
20
|
+
end
|
21
|
+
|
22
|
+
def XmlFile.copy file_name, output_dir
|
23
|
+
dir_name = File.dirname( file_name )
|
24
|
+
|
25
|
+
if ( dir_name =~ /^\// )
|
26
|
+
puts STDERR, "Absolute file names aren't allowed as XML file names."
|
27
|
+
+ " (#{dir_name})";
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
if ( dir_name )
|
32
|
+
output_dir += "/" + dir_name
|
33
|
+
end
|
34
|
+
|
35
|
+
if ( dir_name && !dir_name.empty? && !File.exist?( dir_name ) )
|
36
|
+
`mkdir -p #{output_dir}`
|
37
|
+
if ( $? != 0 )
|
38
|
+
puts STDERR, "Unable to create directory '#{dir_name}'"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
src_file = find_file( file_name )
|
42
|
+
unless File.absolute_path(output_dir) == File.absolute_path(File.split( src_file).first)
|
43
|
+
# do not copy to itself
|
44
|
+
FileUtils.cp( src_file, output_dir )
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def XmlFile.find_file file_name
|
50
|
+
if ( File.exists? file_name )
|
51
|
+
return file_name
|
52
|
+
end
|
53
|
+
|
54
|
+
if ( !@@include_dir.empty? )
|
55
|
+
file_name = @@include_dir + "/" + file_name
|
56
|
+
if ( File.exists? file_name )
|
57
|
+
return file_name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class Node
|
67
|
+
attr_accessor :parent, :level, :name
|
68
|
+
attr_reader :children
|
69
|
+
|
70
|
+
def initialize n = nil
|
71
|
+
@name = n
|
72
|
+
@children = Array.new
|
73
|
+
@level = 0
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_child c
|
77
|
+
@children.push c
|
78
|
+
c.parent = self
|
79
|
+
c.level = @level + 1
|
80
|
+
end
|
81
|
+
|
82
|
+
def print printer
|
83
|
+
printer.do_print self
|
84
|
+
end
|
85
|
+
|
86
|
+
def print_children printer
|
87
|
+
if ( @children )
|
88
|
+
@children.each do |child|
|
89
|
+
child.print printer
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def root?
|
95
|
+
return !parent
|
96
|
+
end
|
97
|
+
|
98
|
+
def root
|
99
|
+
if parent
|
100
|
+
return parent.root
|
101
|
+
end
|
102
|
+
return self
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_s
|
106
|
+
@name
|
107
|
+
end
|
108
|
+
|
109
|
+
def all_children type
|
110
|
+
@result = Array.new
|
111
|
+
@children.each do |child|
|
112
|
+
if ( child.class == type )
|
113
|
+
@result.push child
|
114
|
+
end
|
115
|
+
@result.concat( child.all_children( type ) )
|
116
|
+
end
|
117
|
+
@result
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
class Section < Node
|
123
|
+
end
|
124
|
+
|
125
|
+
class Request < Node
|
126
|
+
|
127
|
+
attr_accessor :verb, :path, :id
|
128
|
+
|
129
|
+
@@id = 0
|
130
|
+
|
131
|
+
def initialize
|
132
|
+
@id = @@id;
|
133
|
+
@@id += 1
|
134
|
+
super()
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_s
|
138
|
+
p = @path.gsub(/<([^>]*?)\??>=/, "\\1=")
|
139
|
+
@verb + " " + p
|
140
|
+
end
|
141
|
+
|
142
|
+
def parameters
|
143
|
+
result = Array.new
|
144
|
+
@path.scan( /[^=]<(.*?)(\??)>/ ) do |p|
|
145
|
+
node = self
|
146
|
+
found = false
|
147
|
+
optional = $2.empty? ? false : true
|
148
|
+
while( node && !found )
|
149
|
+
node.children.each do |c|
|
150
|
+
if ( c.is_a?( Parameter ) && c.name == $1 )
|
151
|
+
c.optional = optional
|
152
|
+
result.push c
|
153
|
+
found = true
|
154
|
+
break
|
155
|
+
end
|
156
|
+
end
|
157
|
+
node = node.parent
|
158
|
+
end
|
159
|
+
if ( !found )
|
160
|
+
n = Parameter.new( $1 )
|
161
|
+
n.optional = optional
|
162
|
+
result.push n
|
163
|
+
end
|
164
|
+
end
|
165
|
+
result
|
166
|
+
end
|
167
|
+
|
168
|
+
def host
|
169
|
+
node = self
|
170
|
+
while( node )
|
171
|
+
node.children.each do |c|
|
172
|
+
if c.is_a? Host
|
173
|
+
return c
|
174
|
+
end
|
175
|
+
end
|
176
|
+
node = node.parent
|
177
|
+
end
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
class Text < Node
|
184
|
+
|
185
|
+
attr_accessor :text
|
186
|
+
|
187
|
+
def initialize
|
188
|
+
@text = Array.new
|
189
|
+
super()
|
190
|
+
end
|
191
|
+
|
192
|
+
def to_s
|
193
|
+
@text.join("\n")
|
194
|
+
end
|
195
|
+
|
196
|
+
def append t
|
197
|
+
@text.push t
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
class Parameter < Node
|
203
|
+
|
204
|
+
attr_accessor :description, :optional
|
205
|
+
|
206
|
+
def initialize n = nil
|
207
|
+
@optional = false
|
208
|
+
super
|
209
|
+
end
|
210
|
+
|
211
|
+
def to_s
|
212
|
+
s = @name.to_s
|
213
|
+
s += " (optional)" if @optional
|
214
|
+
if ( !@description || @description.empty? )
|
215
|
+
s
|
216
|
+
else
|
217
|
+
s + " - " + @description
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
class Xml < Node
|
224
|
+
attr_accessor :schema
|
225
|
+
end
|
226
|
+
|
227
|
+
class Body < Node
|
228
|
+
end
|
229
|
+
|
230
|
+
class Result < Node
|
231
|
+
end
|
232
|
+
|
233
|
+
class XmlBody < Xml
|
234
|
+
end
|
235
|
+
|
236
|
+
class XmlResult < Xml
|
237
|
+
end
|
238
|
+
|
239
|
+
class Host < Node
|
240
|
+
end
|
241
|
+
|
242
|
+
class Contents < Node
|
243
|
+
end
|
244
|
+
|
245
|
+
class Version < Node
|
246
|
+
end
|
247
|
+
|
248
|
+
class Document < Section
|
249
|
+
|
250
|
+
def initialize
|
251
|
+
super
|
252
|
+
self.name = "DOCUMENT"
|
253
|
+
end
|
254
|
+
|
255
|
+
def parse_args
|
256
|
+
sections = Hash.new
|
257
|
+
|
258
|
+
sections[ 0 ] = self
|
259
|
+
|
260
|
+
@section = nil
|
261
|
+
|
262
|
+
while line = gets
|
263
|
+
if ( line =~ /^\s+(\S.*)$/ )
|
264
|
+
if ( !@text )
|
265
|
+
@text = Text.new
|
266
|
+
end
|
267
|
+
@text.append $1
|
268
|
+
else
|
269
|
+
if ( @text && @current )
|
270
|
+
@current.add_child @text
|
271
|
+
end
|
272
|
+
@text = nil
|
273
|
+
end
|
274
|
+
|
275
|
+
if ( line =~ /^(=+) (.*)/ )
|
276
|
+
level = $1.size
|
277
|
+
title = $2
|
278
|
+
|
279
|
+
@section = Section.new title
|
280
|
+
@current = @section
|
281
|
+
|
282
|
+
parent = sections[ level - 1 ]
|
283
|
+
parent.add_child @section
|
284
|
+
sections[ level ] = @section
|
285
|
+
|
286
|
+
elsif ( line =~ /^(GET|PUT|POST|DELETE) (.*)/ )
|
287
|
+
@request = Request.new
|
288
|
+
@current = @request
|
289
|
+
|
290
|
+
@request.verb = $1
|
291
|
+
@request.path = $2
|
292
|
+
|
293
|
+
@section.add_child( @request )
|
294
|
+
|
295
|
+
elsif ( line =~ /^<(.*)>: (.*)/ )
|
296
|
+
parameter = Parameter.new
|
297
|
+
|
298
|
+
parameter.name = $1
|
299
|
+
parameter.description = $2
|
300
|
+
|
301
|
+
@current.add_child( parameter )
|
302
|
+
|
303
|
+
elsif ( line =~ /^Host: (.*)/ )
|
304
|
+
host = Host.new $1
|
305
|
+
@current.add_child( host )
|
306
|
+
|
307
|
+
elsif ( line =~ /^Body: (.*)/ )
|
308
|
+
body = Body.new $1
|
309
|
+
@current.add_child( body )
|
310
|
+
|
311
|
+
elsif ( line =~ /^Result: (.*)/ )
|
312
|
+
result = Result.new $1
|
313
|
+
@current.add_child( result )
|
314
|
+
|
315
|
+
elsif ( line =~ /^XmlBody: (.*)/ )
|
316
|
+
body = XmlBody.new $1
|
317
|
+
@current.add_child( body )
|
318
|
+
|
319
|
+
elsif ( line =~ /^XmlResult: (.*) +(.*)/ )
|
320
|
+
result = XmlResult.new $1
|
321
|
+
result.schema = $2
|
322
|
+
@current.add_child( result )
|
323
|
+
|
324
|
+
elsif ( line =~ /^XmlResult: (.*)/ )
|
325
|
+
result = XmlResult.new $1
|
326
|
+
@current.add_child( result )
|
327
|
+
|
328
|
+
elsif ( line =~ /^Contents/ )
|
329
|
+
@current.add_child( Contents.new )
|
330
|
+
|
331
|
+
elsif ( line =~ /^Version: (.*)/ )
|
332
|
+
version = Version.new $1
|
333
|
+
@current.add_child( version )
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
class Printer
|
344
|
+
|
345
|
+
def initialize
|
346
|
+
@missing = Hash.new
|
347
|
+
end
|
348
|
+
|
349
|
+
def print node
|
350
|
+
do_prepare
|
351
|
+
do_print node
|
352
|
+
do_finish
|
353
|
+
end
|
354
|
+
|
355
|
+
def print_document printer
|
356
|
+
print_section printer
|
357
|
+
end
|
358
|
+
|
359
|
+
def do_print node
|
360
|
+
method = "print_" + node.class.to_s.downcase
|
361
|
+
send method, node
|
362
|
+
end
|
363
|
+
|
364
|
+
def do_prepare
|
365
|
+
end
|
366
|
+
|
367
|
+
def do_finish
|
368
|
+
end
|
369
|
+
|
370
|
+
def method_missing symbol, *args
|
371
|
+
if ( !@missing[ symbol ] )
|
372
|
+
@missing[ symbol ] = true
|
373
|
+
STDERR.puts "Warning: #{self.class} doesn't support '#{symbol}'."
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
end
|
378
|
+
|
379
|
+
class TextPrinter < Printer
|
380
|
+
|
381
|
+
def indent node
|
382
|
+
node.level.times do
|
383
|
+
printf " "
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def print_section section
|
388
|
+
indent section
|
389
|
+
puts "SECTION " + section.to_s
|
390
|
+
section.print_children self
|
391
|
+
end
|
392
|
+
|
393
|
+
def print_request request
|
394
|
+
indent request
|
395
|
+
puts "Request: " + request.to_s
|
396
|
+
host = request.host
|
397
|
+
if ( host )
|
398
|
+
indent host
|
399
|
+
puts " HOST: " + host.name
|
400
|
+
end
|
401
|
+
request.parameters.each do |p|
|
402
|
+
indent request
|
403
|
+
puts " PARAMETER: #{p.to_s}"
|
404
|
+
end
|
405
|
+
request.print_children self
|
406
|
+
end
|
407
|
+
|
408
|
+
def print_text text
|
409
|
+
text.text.each do |t|
|
410
|
+
indent text
|
411
|
+
puts t
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
def print_parameter parameter
|
416
|
+
indent parameter
|
417
|
+
puts "PARAMETER_DEF: " + parameter.name + " - " + parameter.description
|
418
|
+
end
|
419
|
+
|
420
|
+
def print_host host
|
421
|
+
indent host
|
422
|
+
puts "HOST_DEF: " + host.name
|
423
|
+
end
|
424
|
+
|
425
|
+
def print_result result
|
426
|
+
indent result
|
427
|
+
puts "Result: " + result.name
|
428
|
+
end
|
429
|
+
|
430
|
+
def print_xmlresult result
|
431
|
+
indent result
|
432
|
+
printf "XmlResult: " + result.name
|
433
|
+
if ( result.schema )
|
434
|
+
printf " (Schema: #{result.schema})"
|
435
|
+
end
|
436
|
+
printf "\n"
|
437
|
+
end
|
438
|
+
|
439
|
+
def print_body body
|
440
|
+
indent body
|
441
|
+
puts "Body: " + body.name
|
442
|
+
end
|
443
|
+
|
444
|
+
end
|
445
|
+
|
446
|
+
|
447
|
+
class OutlinePrinter < Printer
|
448
|
+
def print node
|
449
|
+
node.level.times do
|
450
|
+
printf " "
|
451
|
+
end
|
452
|
+
puts "#{node.level} #{node.class}"
|
453
|
+
node.print_children self
|
454
|
+
end
|
455
|
+
|
456
|
+
def print_section node
|
457
|
+
print node
|
458
|
+
end
|
459
|
+
end
|