aws-sdk-code-generator 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/aws-sdk-code-generator.rb +91 -0
- data/lib/aws-sdk-code-generator/apply_docs.rb +37 -0
- data/lib/aws-sdk-code-generator/code_builder.rb +201 -0
- data/lib/aws-sdk-code-generator/dsl/access_control_statement.rb +23 -0
- data/lib/aws-sdk-code-generator/dsl/attribute_accessor.rb +43 -0
- data/lib/aws-sdk-code-generator/dsl/attribute_reader.rb +11 -0
- data/lib/aws-sdk-code-generator/dsl/attribute_writer.rb +11 -0
- data/lib/aws-sdk-code-generator/dsl/autoload_statement.rb +15 -0
- data/lib/aws-sdk-code-generator/dsl/block_param.rb +11 -0
- data/lib/aws-sdk-code-generator/dsl/class.rb +27 -0
- data/lib/aws-sdk-code-generator/dsl/code_literal.rb +66 -0
- data/lib/aws-sdk-code-generator/dsl/code_object.rb +33 -0
- data/lib/aws-sdk-code-generator/dsl/docstring.rb +36 -0
- data/lib/aws-sdk-code-generator/dsl/eigenclass.rb +15 -0
- data/lib/aws-sdk-code-generator/dsl/extend_statement.rb +12 -0
- data/lib/aws-sdk-code-generator/dsl/formatter.rb +25 -0
- data/lib/aws-sdk-code-generator/dsl/include_statement.rb +17 -0
- data/lib/aws-sdk-code-generator/dsl/main.rb +105 -0
- data/lib/aws-sdk-code-generator/dsl/method.rb +108 -0
- data/lib/aws-sdk-code-generator/dsl/module.rb +167 -0
- data/lib/aws-sdk-code-generator/dsl/option_tag.rb +36 -0
- data/lib/aws-sdk-code-generator/dsl/param.rb +43 -0
- data/lib/aws-sdk-code-generator/dsl/param_list.rb +38 -0
- data/lib/aws-sdk-code-generator/dsl/return_tag.rb +19 -0
- data/lib/aws-sdk-code-generator/dsl/tag_default.rb +20 -0
- data/lib/aws-sdk-code-generator/dsl/tag_docstring.rb +27 -0
- data/lib/aws-sdk-code-generator/dsl/tag_type.rb +18 -0
- data/lib/aws-sdk-code-generator/errors.rb +30 -0
- data/lib/aws-sdk-code-generator/gem_builder.rb +71 -0
- data/lib/aws-sdk-code-generator/generators/client_api_module.rb +334 -0
- data/lib/aws-sdk-code-generator/generators/client_class.rb +389 -0
- data/lib/aws-sdk-code-generator/generators/client_operation_documentation.rb +166 -0
- data/lib/aws-sdk-code-generator/generators/errors_module.rb +25 -0
- data/lib/aws-sdk-code-generator/generators/resource/action.rb +88 -0
- data/lib/aws-sdk-code-generator/generators/resource/batch_builder.rb +211 -0
- data/lib/aws-sdk-code-generator/generators/resource/builder.rb +50 -0
- data/lib/aws-sdk-code-generator/generators/resource/client_getter.rb +15 -0
- data/lib/aws-sdk-code-generator/generators/resource/client_request.rb +49 -0
- data/lib/aws-sdk-code-generator/generators/resource/client_request_docs.rb +97 -0
- data/lib/aws-sdk-code-generator/generators/resource/client_request_params.rb +88 -0
- data/lib/aws-sdk-code-generator/generators/resource/collection_class.rb +180 -0
- data/lib/aws-sdk-code-generator/generators/resource/data_attribute_getter.rb +24 -0
- data/lib/aws-sdk-code-generator/generators/resource/data_loaded_method.rb +18 -0
- data/lib/aws-sdk-code-generator/generators/resource/data_method.rb +49 -0
- data/lib/aws-sdk-code-generator/generators/resource/exists_method.rb +29 -0
- data/lib/aws-sdk-code-generator/generators/resource/extract_identifier_method.rb +32 -0
- data/lib/aws-sdk-code-generator/generators/resource/has_association.rb +101 -0
- data/lib/aws-sdk-code-generator/generators/resource/has_many_association.rb +108 -0
- data/lib/aws-sdk-code-generator/generators/resource/identifier_getter.rb +26 -0
- data/lib/aws-sdk-code-generator/generators/resource/identifiers_method.rb +28 -0
- data/lib/aws-sdk-code-generator/generators/resource/initialize_method.rb +67 -0
- data/lib/aws-sdk-code-generator/generators/resource/load_method.rb +65 -0
- data/lib/aws-sdk-code-generator/generators/resource/value_source.rb +68 -0
- data/lib/aws-sdk-code-generator/generators/resource/waiter_method.rb +61 -0
- data/lib/aws-sdk-code-generator/generators/resource_class.rb +325 -0
- data/lib/aws-sdk-code-generator/generators/response_structure_example.rb +83 -0
- data/lib/aws-sdk-code-generator/generators/root_resource_class.rb +42 -0
- data/lib/aws-sdk-code-generator/generators/service_documentation.rb +64 -0
- data/lib/aws-sdk-code-generator/generators/shared_example.rb +132 -0
- data/lib/aws-sdk-code-generator/generators/structure_type_class.rb +95 -0
- data/lib/aws-sdk-code-generator/generators/syntax_example.rb +169 -0
- data/lib/aws-sdk-code-generator/generators/types_module.rb +52 -0
- data/lib/aws-sdk-code-generator/generators/waiter_class.rb +62 -0
- data/lib/aws-sdk-code-generator/generators/waiters_module.rb +20 -0
- data/lib/aws-sdk-code-generator/hash_formatter.rb +122 -0
- data/lib/aws-sdk-code-generator/helper.rb +215 -0
- data/lib/aws-sdk-code-generator/service.rb +126 -0
- data/lib/aws-sdk-code-generator/underscore.rb +45 -0
- data/lib/aws-sdk-code-generator/view.rb +23 -0
- data/lib/aws-sdk-code-generator/views.rb +3 -0
- data/lib/aws-sdk-code-generator/views/features/env.rb +24 -0
- data/lib/aws-sdk-code-generator/views/features/step_definitions.rb +20 -0
- data/lib/aws-sdk-code-generator/views/gemspec.rb +41 -0
- data/lib/aws-sdk-code-generator/views/service_module.rb +85 -0
- data/lib/aws-sdk-code-generator/views/spec/spec_helper.rb +24 -0
- data/lib/aws-sdk-code-generator/views/version.rb +16 -0
- metadata +120 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module AwsSdkCodeGenerator
|
4
|
+
module Generators
|
5
|
+
class TypesModule < Dsl::Module
|
6
|
+
|
7
|
+
include Helper
|
8
|
+
|
9
|
+
# @option options [required, Hash] :api
|
10
|
+
def initialize(options)
|
11
|
+
@api = options.fetch(:api)
|
12
|
+
super('Types')
|
13
|
+
input_shapes = compute_input_shapes(@api)
|
14
|
+
structures.each do |shape_name, shape|
|
15
|
+
add(StructureTypeClass.new(
|
16
|
+
name: shape_name,
|
17
|
+
api: @api,
|
18
|
+
used_as_input: input_shapes.include?(shape_name)
|
19
|
+
))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def compute_input_shapes(api)
|
26
|
+
inputs = Set.new
|
27
|
+
(api['operations'] || {}).each do |_, operation|
|
28
|
+
visit_inputs(operation['input'], inputs) if operation['input']
|
29
|
+
end
|
30
|
+
inputs
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit_inputs(shape_ref, inputs)
|
34
|
+
return if inputs.include?(shape_ref['shape']) # recursion
|
35
|
+
inputs << shape_ref['shape']
|
36
|
+
s = shape(shape_ref)
|
37
|
+
case s['type']
|
38
|
+
when 'structure'
|
39
|
+
s['members'].each_pair do |_, member_ref|
|
40
|
+
visit_inputs(member_ref, inputs)
|
41
|
+
end
|
42
|
+
when 'list'
|
43
|
+
visit_inputs(s['member'], inputs)
|
44
|
+
when 'map'
|
45
|
+
visit_inputs(s['key'], inputs)
|
46
|
+
visit_inputs(s['value'], inputs)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module AwsSdkCodeGenerator
|
2
|
+
module Generators
|
3
|
+
class WaiterClass < Dsl::Class
|
4
|
+
|
5
|
+
# @option options [required, String] :waiter_name
|
6
|
+
# @option options [required, Hash] :waiter
|
7
|
+
def initialize(options)
|
8
|
+
waiter = options.fetch(:waiter)
|
9
|
+
client_method = underscore(waiter['operation'])
|
10
|
+
super(options.fetch(:waiter_name))
|
11
|
+
code <<-CODE
|
12
|
+
# @param [Hash] options
|
13
|
+
# @option options [required, Client] :client
|
14
|
+
# @option options [Integer] :max_attempts (#{waiter['maxAttempts']})
|
15
|
+
# @option options [Integer] :delay (#{waiter['delay']})
|
16
|
+
# @option options [Proc] :before_attempt
|
17
|
+
# @option options [Proc] :before_wait
|
18
|
+
def initialize(options)
|
19
|
+
@client = options.fetch(:client)
|
20
|
+
@waiter = Aws::Waiters::Waiter.new({
|
21
|
+
max_attempts: #{waiter['maxAttempts']},
|
22
|
+
delay: #{waiter['delay']},
|
23
|
+
poller: Aws::Waiters::Poller.new(#{poller_args(waiter)} )
|
24
|
+
}.merge(options))
|
25
|
+
end
|
26
|
+
|
27
|
+
# @option (see Client##{client_method})
|
28
|
+
# @return (see Client##{client_method})
|
29
|
+
def wait(params = {})
|
30
|
+
@waiter.wait(client: @client, params: params)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @api private
|
34
|
+
attr_reader :waiter
|
35
|
+
CODE
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def poller_args(hash)
|
41
|
+
hash = hash.dup
|
42
|
+
hash.delete('delay')
|
43
|
+
hash.delete('maxAttempts')
|
44
|
+
hash[:operation_name] = Underscore.underscore(hash.delete('operation')).to_sym
|
45
|
+
hash[:acceptors] = hash.delete('acceptors').map do |acceptor|
|
46
|
+
if acceptor['argument']
|
47
|
+
acceptor['argument'] = Underscore.underscore_jmespath(acceptor['argument'])
|
48
|
+
end
|
49
|
+
acceptor
|
50
|
+
end
|
51
|
+
formatter = HashFormatter.new(
|
52
|
+
wrap: false,
|
53
|
+
inline: false,
|
54
|
+
quote_strings: true
|
55
|
+
)
|
56
|
+
lines = formatter.format(hash).lines
|
57
|
+
lines.map { |line| " #{line}" }.join
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module AwsSdkCodeGenerator
|
2
|
+
module Generators
|
3
|
+
class WaitersModule < Dsl::Module
|
4
|
+
|
5
|
+
include Helper
|
6
|
+
|
7
|
+
# @option options [required, Module] :parent
|
8
|
+
# @option options [required, Hash, nil] :waiters
|
9
|
+
def initialize(options)
|
10
|
+
waiters = options.fetch(:waiters)
|
11
|
+
super('Waiters', parent: options.fetch(:parent))
|
12
|
+
require_statement('aws-sdk-core/waiters')
|
13
|
+
waiters['waiters'].each do |waiter_name, waiter|
|
14
|
+
add(WaiterClass.new(waiter_name: waiter_name, waiter: waiter))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module AwsSdkCodeGenerator
|
2
|
+
class HashFormatter
|
3
|
+
|
4
|
+
# @option options [Boolean] :wrap (true) When `true`, the formatted hash will
|
5
|
+
# be wrapped with curly braces.
|
6
|
+
#
|
7
|
+
# @option options [Boolean] :inline (false) When `true` the formatted hash will
|
8
|
+
# contain no newlines.
|
9
|
+
#
|
10
|
+
# @option options [Boolean] :quote_strings (false) By default, all hash string values
|
11
|
+
# must contain their own quotes. If you pass `true`, then all hash string
|
12
|
+
# values will be inspected via `#inspect` which will auto-quote them.
|
13
|
+
#
|
14
|
+
def initialize(options = {})
|
15
|
+
@wrap = options.fetch(:wrap, true)
|
16
|
+
@inline = options.fetch(:inline, false)
|
17
|
+
@quote_strings = options.fetch(:quote_strings, false)
|
18
|
+
end
|
19
|
+
|
20
|
+
def format(obj)
|
21
|
+
result = hash(obj, i:'', inline:@inline)
|
22
|
+
result = unwrap(result, obj.size) if !@wrap
|
23
|
+
result = result.strip if @inline && result.lines.to_a.length == 1
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def value(obj, options)
|
30
|
+
i = options.fetch(:i)
|
31
|
+
inline = options.fetch(:inline)
|
32
|
+
case obj
|
33
|
+
when Hash then hash(obj, i:i, inline:inline)
|
34
|
+
when Array then array(obj, i:i)
|
35
|
+
when String then @quote_strings ? obj.inspect : obj
|
36
|
+
when Symbol then obj.inspect
|
37
|
+
when Fixnum, true, false then obj.inspect
|
38
|
+
else raise ArgumentError, "unsupported value `#{obj.class}'"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash(hash, options)
|
43
|
+
i = options.fetch(:i)
|
44
|
+
inline = options.fetch(:inline)
|
45
|
+
if hash.empty?
|
46
|
+
'{}'
|
47
|
+
elsif inline_hash?(hash, inline)
|
48
|
+
inline_hash(hash)
|
49
|
+
else
|
50
|
+
multiline_hash(hash, i:i)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def inline_hash(hash)
|
55
|
+
"{ #{hash_entry(hash.keys[0], hash.values[0], i:'')} }"
|
56
|
+
end
|
57
|
+
|
58
|
+
def multiline_hash(hash, options)
|
59
|
+
i = options.fetch(:i)
|
60
|
+
str = "{\n"
|
61
|
+
hash.each.with_index do |(key, value), n|
|
62
|
+
str += "#{i} #{hash_entry(key, value, i:i)}"
|
63
|
+
str += "," unless n == hash.keys.length - 1
|
64
|
+
str += "\n"
|
65
|
+
end
|
66
|
+
str + "#{i}}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def hash_entry(key, value, options)
|
70
|
+
i = options.fetch(:i)
|
71
|
+
value = value(value, i: i + ' ', inline:false)
|
72
|
+
if Symbol === key
|
73
|
+
"#{key}: #{value}"
|
74
|
+
else
|
75
|
+
"#{key.inspect} => #{value}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def array(array, options)
|
80
|
+
i = options.fetch(:i)
|
81
|
+
if array.empty?
|
82
|
+
'[]'
|
83
|
+
elsif inline_array?(array)
|
84
|
+
"[#{value(array[0], i:i, inline:true)}]"
|
85
|
+
else
|
86
|
+
format_multiline_array(array, i:i)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def format_multiline_array(array, options)
|
91
|
+
i = options.fetch(:i)
|
92
|
+
str = "[\n"
|
93
|
+
array.each.with_index do |value, n|
|
94
|
+
str += "#{i} #{value(value, i:i + ' ', inline:true)}"
|
95
|
+
str += "," unless n == array.length - 1
|
96
|
+
str += "\n"
|
97
|
+
end
|
98
|
+
str + "#{i}]"
|
99
|
+
end
|
100
|
+
|
101
|
+
def inline_hash?(hash, inline)
|
102
|
+
hash.length == 1 && String === hash.values[0] && inline
|
103
|
+
end
|
104
|
+
|
105
|
+
def inline_array?(array)
|
106
|
+
array.length == 1# && String === array[0]
|
107
|
+
end
|
108
|
+
|
109
|
+
def unwrap(str, size)
|
110
|
+
if @inline || size > 1
|
111
|
+
str[1..-2]
|
112
|
+
else
|
113
|
+
lines = str.lines.to_a
|
114
|
+
lines.shift
|
115
|
+
lines.pop
|
116
|
+
lines = lines.map { |line| line[2..-1] }
|
117
|
+
lines.join.rstrip
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
# disable inline attribute lists
|
5
|
+
class Kramdown::Converter::Kramdown
|
6
|
+
def ial_for_element(*args)
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module AwsSdkCodeGenerator
|
12
|
+
module Helper
|
13
|
+
|
14
|
+
def identifier_type(identifier)
|
15
|
+
case identifier['type']
|
16
|
+
when nil, 'string' then 'String'
|
17
|
+
when 'integer' then 'Integer'
|
18
|
+
else
|
19
|
+
msg = "unsupported identifier type `#{identifier['type']}'"
|
20
|
+
raise ArgumentError, msg
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param [Array<Array<String>>]
|
25
|
+
def markdown_table(table)
|
26
|
+
# compute the width of each column by scanning for longest values
|
27
|
+
column_width = lambda do |col|
|
28
|
+
table.map { |row| row[col].size }.max
|
29
|
+
end
|
30
|
+
widths = [
|
31
|
+
column_width.call(0),
|
32
|
+
column_width.call(1),
|
33
|
+
column_width.call(2),
|
34
|
+
column_width.call(3),
|
35
|
+
]
|
36
|
+
|
37
|
+
# insert a dashed line after the header row
|
38
|
+
table = [
|
39
|
+
table[0],
|
40
|
+
['-' * widths[0], '-' * widths[1], '-' * widths[2], '-' * widths[3]]
|
41
|
+
] + table[1..-1]
|
42
|
+
|
43
|
+
# build the final table
|
44
|
+
line = "| #{widths.map{|n| "%-#{n}s" }.join(' | ')} |"
|
45
|
+
table.map { |row| line % row }.join("\n")
|
46
|
+
end
|
47
|
+
module_function :markdown_table
|
48
|
+
|
49
|
+
def underscore(str)
|
50
|
+
str.split('.').map do |part|
|
51
|
+
Underscore.underscore(part)
|
52
|
+
end.join('.')
|
53
|
+
end
|
54
|
+
|
55
|
+
def structures
|
56
|
+
Enumerator.new do |y|
|
57
|
+
(@api['shapes'] || {}).each do |shape_name, shape|
|
58
|
+
if shape['type'] == 'structure' && !shape['error'] && !shape['exception']
|
59
|
+
y.yield(shape_name, shape)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @option options [Boolean] :nested (false)
|
66
|
+
def ruby_input_type(shape_ref, options = {})
|
67
|
+
nested = options.fetch(:nested, false)
|
68
|
+
shape = @api['shapes'][shape_ref['shape']]
|
69
|
+
case shape['type']
|
70
|
+
when 'byte' then 'Integer<byte>'
|
71
|
+
when 'blob' then 'String, IO'
|
72
|
+
when 'boolean' then 'Boolean'
|
73
|
+
when 'character' then 'String<character>'
|
74
|
+
when 'double' then 'Float'
|
75
|
+
when 'float' then 'Float'
|
76
|
+
when 'integer' then 'Integer'
|
77
|
+
when 'list'
|
78
|
+
if nested
|
79
|
+
"Array"
|
80
|
+
else
|
81
|
+
"Array<#{ruby_input_type(shape['member'], nested:true)}>"
|
82
|
+
end
|
83
|
+
when 'long' then 'Integer'
|
84
|
+
when 'map'
|
85
|
+
if nested
|
86
|
+
"Hash"
|
87
|
+
else
|
88
|
+
"Hash<String,#{ruby_input_type(shape['value'], nested:true)}>"
|
89
|
+
end
|
90
|
+
when 'string' then 'String'
|
91
|
+
when 'structure' then "Types::#{shape_ref['shape']}"
|
92
|
+
when 'timestamp' then 'Time,DateTime,Date,Integer,String'
|
93
|
+
else
|
94
|
+
raise "unhandled type #{shape.type}.inspect"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def ruby_type(shape_ref)
|
99
|
+
shape = @api['shapes'][shape_ref['shape']]
|
100
|
+
case shape['type']
|
101
|
+
when 'blob' then streaming?(shape_ref, shape) ? 'IO' : 'String'
|
102
|
+
when 'boolean' then 'Boolean'
|
103
|
+
when 'byte' then 'Integer<byte>'
|
104
|
+
when 'character' then 'String<character>'
|
105
|
+
when 'double' then 'Float'
|
106
|
+
when 'float' then 'Float'
|
107
|
+
when 'integer' then 'Integer'
|
108
|
+
when 'list' then "Array<#{ruby_type(shape['member'])}>"
|
109
|
+
when 'long' then 'Integer'
|
110
|
+
when 'map' then "Hash<String,#{ruby_type(shape['value'])}>"
|
111
|
+
when 'string' then 'String'
|
112
|
+
when 'structure' then "Types::#{shape_ref['shape']}"
|
113
|
+
when 'timestamp' then 'Time'
|
114
|
+
else
|
115
|
+
raise "unhandled type #{shape['type'].inspect}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def streaming?(ref, shape)
|
120
|
+
ref['streaming'] || shape['streaming']
|
121
|
+
end
|
122
|
+
|
123
|
+
# @option options [Integer] :line_width (70)
|
124
|
+
def documentation(ref_or_shape, options = {})
|
125
|
+
line_width = options.fetch(:line_width, 70)
|
126
|
+
shape = ref_or_shape.key?('type') ? ref_or_shape : shape(ref_or_shape)
|
127
|
+
docstring = ref_or_shape['documentation'] || shape['documentation'] || ''
|
128
|
+
|
129
|
+
# append boilerplate idempotency docs
|
130
|
+
if ref_or_shape['idempotencyToken']
|
131
|
+
docstring = "#{docstring}<p>**A suitable default value is "
|
132
|
+
docstring += "auto-generated.** You should normally "
|
133
|
+
docstring += "not need to pass this option.</p>"
|
134
|
+
docstring = docstring.strip
|
135
|
+
end
|
136
|
+
|
137
|
+
docstring == '' ? docstring : markdown(docstring, line_width:line_width)
|
138
|
+
end
|
139
|
+
|
140
|
+
def member_shape(shape_name, member_name)
|
141
|
+
shape = @api['shapes'][shape_name]
|
142
|
+
member_ref = shape['members'][member_name]
|
143
|
+
shape(member_ref)
|
144
|
+
end
|
145
|
+
|
146
|
+
def shape(ref)
|
147
|
+
if ref.nil?
|
148
|
+
nil
|
149
|
+
else
|
150
|
+
shape = @api['shapes'][ref['shape']]
|
151
|
+
raise ArgumentError, "no such shape `#{ref['shape']}'" unless shape
|
152
|
+
shape
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# @option options [Integer] :line_width (70)
|
157
|
+
def markdown(html, options = {})
|
158
|
+
line_width = options.fetch(:line_width, 70)
|
159
|
+
# TODO : this section of code is **very slow** and runs many times
|
160
|
+
# while building a service.
|
161
|
+
if html
|
162
|
+
html = "<p>#{html}</p>" unless html.match(/<\w+>/)
|
163
|
+
|
164
|
+
# unescaped curly braces cause YARD errors, they are interpreted
|
165
|
+
# as code links.
|
166
|
+
html = html.gsub('{', "\\{").gsub('}', "\\}")
|
167
|
+
|
168
|
+
# Kramdown generates invalid markup when there are attributes
|
169
|
+
# on the code tag, have to reduce these down to get the proper markdown.
|
170
|
+
html = html.gsub(/<code.*?>(.+?)<\/code>/) { "<code>#{$1}</code>" }
|
171
|
+
|
172
|
+
# Kramdown creates invalid markup with target="_blank" attributes.
|
173
|
+
html = html.gsub(' target="_blank"', '')
|
174
|
+
|
175
|
+
# There are quite a few empty <a> tags. These appear to be code names,
|
176
|
+
# such as structure member names, or structure type names. We should
|
177
|
+
# investigate if it is possible to inflect these properly and then
|
178
|
+
# turn them into YARD links.
|
179
|
+
html = html.gsub(/<a>(.+?)<\/a>/) { $1 }
|
180
|
+
|
181
|
+
# <important> tag doesn't render well
|
182
|
+
html = html.gsub(/<important>(.+?)<\/important>/){ "<p>#{$1}</p>" }
|
183
|
+
|
184
|
+
markdown = Kramdown::Document.new(
|
185
|
+
html,
|
186
|
+
input: 'html',
|
187
|
+
line_width: line_width,
|
188
|
+
auto_ids: false
|
189
|
+
).to_kramdown.strip
|
190
|
+
|
191
|
+
# remove extra escape
|
192
|
+
markdown.gsub(/\\(\*|`|'|")/, '\1')
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def deep_copy(obj)
|
197
|
+
case obj
|
198
|
+
when nil then nil
|
199
|
+
when true then true
|
200
|
+
when false then false
|
201
|
+
when Hash then obj.inject({}) { |h,(k,v)| h[deep_copy(k)] = deep_copy(v); h }
|
202
|
+
when Array then obj.map { |v| deep_copy(v) }
|
203
|
+
else
|
204
|
+
if obj.respond_to?(:dup)
|
205
|
+
obj.dup
|
206
|
+
elsif obj.respond_to?(:clone)
|
207
|
+
obj.clone
|
208
|
+
else
|
209
|
+
obj
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
end
|