seahorse 0.1.0 → 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +12 -0
  3. data/VERSION +1 -0
  4. data/lib/seahorse/api_error.rb +15 -0
  5. data/lib/seahorse/block_io.rb +24 -0
  6. data/lib/seahorse/context.rb +34 -0
  7. data/lib/seahorse/http/api_error.rb +29 -0
  8. data/lib/seahorse/http/client.rb +152 -0
  9. data/lib/seahorse/http/error_parser.rb +105 -0
  10. data/lib/seahorse/http/headers.rb +70 -0
  11. data/lib/seahorse/http/middleware/content_length.rb +28 -0
  12. data/lib/seahorse/http/networking_error.rb +20 -0
  13. data/lib/seahorse/http/request.rb +132 -0
  14. data/lib/seahorse/http/response.rb +29 -0
  15. data/lib/seahorse/http.rb +36 -0
  16. data/lib/seahorse/json/parse_error.rb +18 -0
  17. data/lib/seahorse/json.rb +30 -0
  18. data/lib/seahorse/middleware/around_handler.rb +24 -0
  19. data/lib/seahorse/middleware/build.rb +26 -0
  20. data/lib/seahorse/middleware/host_prefix.rb +48 -0
  21. data/lib/seahorse/middleware/parse.rb +42 -0
  22. data/lib/seahorse/middleware/request_handler.rb +24 -0
  23. data/lib/seahorse/middleware/response_handler.rb +25 -0
  24. data/lib/seahorse/middleware/retry.rb +43 -0
  25. data/lib/seahorse/middleware/send.rb +62 -0
  26. data/lib/seahorse/middleware/validate.rb +29 -0
  27. data/lib/seahorse/middleware.rb +16 -0
  28. data/lib/seahorse/middleware_builder.rb +246 -0
  29. data/lib/seahorse/middleware_stack.rb +73 -0
  30. data/lib/seahorse/output.rb +20 -0
  31. data/lib/seahorse/structure.rb +40 -0
  32. data/lib/seahorse/stubbing/client_stubs.rb +115 -0
  33. data/lib/seahorse/stubbing/stubs.rb +32 -0
  34. data/lib/seahorse/time_helper.rb +35 -0
  35. data/lib/seahorse/union.rb +10 -0
  36. data/lib/seahorse/validator.rb +20 -0
  37. data/lib/seahorse/waiters/errors.rb +15 -0
  38. data/lib/seahorse/waiters/poller.rb +132 -0
  39. data/lib/seahorse/waiters/waiter.rb +79 -0
  40. data/lib/seahorse/xml/formatter.rb +68 -0
  41. data/lib/seahorse/xml/node.rb +123 -0
  42. data/lib/seahorse/xml/parse_error.rb +18 -0
  43. data/lib/seahorse/xml.rb +58 -0
  44. data/lib/seahorse.rb +23 -13
  45. data/sig/lib/seahorse/api_error.rbs +10 -0
  46. data/sig/lib/seahorse/document.rbs +2 -0
  47. data/sig/lib/seahorse/http/api_error.rbs +21 -0
  48. data/sig/lib/seahorse/http/headers.rbs +47 -0
  49. data/sig/lib/seahorse/http/response.rbs +21 -0
  50. data/sig/lib/seahorse/simple_delegator.rbs +3 -0
  51. data/sig/lib/seahorse/structure.rbs +18 -0
  52. data/sig/lib/seahorse/stubbing/client_stubs.rbs +103 -0
  53. data/sig/lib/seahorse/stubbing/stubs.rbs +14 -0
  54. data/sig/lib/seahorse/union.rbs +6 -0
  55. metadata +73 -54
  56. data/LICENSE +0 -12
  57. data/README.md +0 -3
  58. data/Rakefile +0 -7
  59. data/lib/seahorse/api_translator/inflector.rb +0 -37
  60. data/lib/seahorse/api_translator/operation.rb +0 -150
  61. data/lib/seahorse/api_translator/shape.rb +0 -235
  62. data/lib/seahorse/controller.rb +0 -87
  63. data/lib/seahorse/model.rb +0 -82
  64. data/lib/seahorse/operation.rb +0 -66
  65. data/lib/seahorse/param_validator.rb +0 -158
  66. data/lib/seahorse/railtie.rb +0 -7
  67. data/lib/seahorse/router.rb +0 -20
  68. data/lib/seahorse/shape_builder.rb +0 -84
  69. data/lib/seahorse/type.rb +0 -220
  70. data/lib/seahorse/version.rb +0 -3
  71. data/lib/tasks/seahorse_tasks.rake +0 -24
data/Rakefile DELETED
@@ -1,7 +0,0 @@
1
- begin
2
- require 'bundler/setup'
3
- rescue LoadError
4
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
- end
6
-
7
- Bundler::GemHelper.install_tasks
@@ -1,37 +0,0 @@
1
- # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License"). You
4
- # may not use this file except in compliance with the License. A copy of
5
- # the License is located at
6
- #
7
- # http://aws.amazon.com/apache2.0/
8
- #
9
- # or in the "license" file accompanying this file. This file is
10
- # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
- # ANY KIND, either express or implied. See the License for the specific
12
- # language governing permissions and limitations under the License.
13
-
14
- module Seahorse
15
- class ApiTranslator
16
-
17
- # @private
18
- module Inflector
19
-
20
- # Performs a very simple inflection on on the words as they are
21
- # formatted in the source API configurations. These are *not*
22
- # general case inflectors.
23
- # @param [String] string The string to inflect.
24
- # @param [String,nil] format Valid formats include 'snake_case',
25
- # 'camelCase' and `nil` (leave as is).
26
- # @return [String]
27
- def inflect string, format = nil
28
- case format
29
- when 'camelCase' then string.camelize
30
- when 'snake_case' then string.underscore
31
- else string
32
- end
33
- end
34
- end
35
-
36
- end
37
- end
@@ -1,150 +0,0 @@
1
- # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License"). You
4
- # may not use this file except in compliance with the License. A copy of
5
- # the License is located at
6
- #
7
- # http://aws.amazon.com/apache2.0/
8
- #
9
- # or in the "license" file accompanying this file. This file is
10
- # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
- # ANY KIND, either express or implied. See the License for the specific
12
- # language governing permissions and limitations under the License.
13
-
14
- require_relative './inflector'
15
- require_relative './shape'
16
-
17
- module Seahorse
18
- class ApiTranslator
19
-
20
- # @private
21
- class Operation
22
-
23
- include Inflector
24
-
25
- def initialize rules, options = {}
26
- @options = options
27
-
28
- @method_name = rules['name'].sub(/\d{4}_\d{2}_\d{2}$/, '')
29
- @method_name = inflect(@method_name, @options[:inflect_method_names])
30
-
31
- @rules = rules
32
-
33
- if @rules['http']
34
- @rules['http'].delete('response_code')
35
- end
36
-
37
- translate_input
38
- translate_output
39
-
40
- if @options[:documentation]
41
- @rules['errors'] = @rules['errors'].map {|e| e['shape_name'] }
42
- else
43
- @rules.delete('errors')
44
- @rules.delete('documentation')
45
- @rules.delete('documentation_url')
46
- @rules.delete('response_code')
47
- end
48
- end
49
-
50
- # @return [String]
51
- attr_reader :method_name
52
-
53
- # @return [Hash]
54
- attr_reader :rules
55
-
56
- private
57
-
58
- def translate_input
59
- if @rules['input']
60
- rules = InputShape.new(@rules['input'], @options).rules
61
- rules['members'] ||= {}
62
- rules = normalize_inputs(rules)
63
- else
64
- rules = {
65
- 'type' => 'structure',
66
- 'members' => {},
67
- }
68
- end
69
- @rules['input'] = rules
70
- end
71
-
72
- def translate_output
73
- if @rules['output']
74
- rules = OutputShape.new(@rules['output'], @options).rules
75
- move_up_outputs(rules)
76
- cache_payload(rules)
77
- else
78
- rules = {
79
- 'type' => 'structure',
80
- 'members' => {},
81
- }
82
- end
83
- @rules['output'] = rules
84
- end
85
-
86
- def normalize_inputs rules
87
- return rules unless @options[:type].match(/rest/)
88
-
89
- xml = @options[:type].match(/xml/)
90
- payload = false
91
- wrapper = false
92
-
93
- if rules['members'].any?{|name,rule| rule['payload'] }
94
-
95
- # exactly one member has the payload trait
96
- payload, rule = rules['members'].find{|name,rule| rule['payload'] }
97
- rule.delete('payload')
98
-
99
- #if rule['type'] == 'structure'
100
- # wrapper = payload
101
- # payload = [payload]
102
- #end
103
-
104
- else
105
-
106
- # no members marked themselves as the payload, collect everything
107
- # without a location
108
- payload = rules['members'].inject([]) do |list,(name,rule)|
109
- list << name if !rule['location']
110
- list
111
- end
112
-
113
- if payload.empty?
114
- payload = false
115
- elsif xml
116
- wrapper = @rules['input']['shape_name']
117
- end
118
-
119
- end
120
-
121
- rules = { 'wrapper' => wrapper }.merge(rules) if wrapper
122
- rules = { 'payload' => payload }.merge(rules) if payload
123
- rules
124
-
125
- end
126
-
127
- def move_up_outputs output
128
- move_up = nil
129
- (output['members'] || {}).each_pair do |member_name, rules|
130
- if rules['payload'] and rules['type'] == 'structure'
131
- rules.delete('payload')
132
- move_up = member_name
133
- end
134
- end
135
-
136
- if move_up
137
- output['members'].merge!(output['members'].delete(move_up)['members'])
138
- end
139
- end
140
-
141
- def cache_payload rules
142
- (rules['members'] || {}).each_pair do |member_name, rule|
143
- rules['payload'] = member_name if rule['payload'] || rule['streaming']
144
- rule.delete('payload')
145
- end
146
- end
147
-
148
- end
149
- end
150
- end
@@ -1,235 +0,0 @@
1
- # Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License"). You
4
- # may not use this file except in compliance with the License. A copy of
5
- # the License is located at
6
- #
7
- # http://aws.amazon.com/apache2.0/
8
- #
9
- # or in the "license" file accompanying this file. This file is
10
- # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
- # ANY KIND, either express or implied. See the License for the specific
12
- # language governing permissions and limitations under the License.
13
-
14
- require_relative './inflector'
15
-
16
- module Seahorse
17
- class ApiTranslator
18
-
19
- # @private
20
- class Shape
21
-
22
- include Inflector
23
-
24
- def initialize rules, options = {}
25
- @options = options
26
- @rules = {}
27
- @rules['name'] = options['name'] if options.key?('name')
28
- set_type(rules.delete('type'))
29
- rules.each_pair do |method,arg|
30
- send("set_#{method}", *[arg])
31
- end
32
- end
33
-
34
- def rules
35
- if @rules['type'] != 'blob'
36
- @rules
37
- elsif @rules['payload'] or @rules['streaming']
38
- @rules.merge('type' => 'binary')
39
- else
40
- @rules.merge('type' => 'base64')
41
- end
42
- end
43
-
44
- def xmlname
45
- if @rules['flattened']
46
- (@rules['members'] || {})['name'] || @xmlname
47
- else
48
- @xmlname
49
- end
50
- end
51
-
52
- protected
53
-
54
- def set_timestamp_format format
55
- @rules['format'] = format
56
- end
57
-
58
- def set_type name
59
- types = {
60
- 'structure' => 'structure',
61
- 'list' => 'list',
62
- 'map' => 'map',
63
- 'boolean' => 'boolean',
64
- 'timestamp' => 'timestamp',
65
- 'character' => 'string',
66
- 'double' => 'float',
67
- 'float' => 'float',
68
- 'integer' => 'integer',
69
- 'long' => 'integer',
70
- 'short' => 'integer',
71
- 'string' => 'string',
72
- 'blob' => 'blob',
73
- 'biginteger' => 'integer',
74
- 'bigdecimal' => 'float',
75
- }
76
- if name == 'string'
77
- # Purposefully omitting type when string (to reduce size of the api
78
- # configuration). The parsers use string as the default when
79
- # 'type' is omitted.
80
- #@rules['type'] = 'string'
81
- elsif type = types[name]
82
- @rules['type'] = type
83
- else
84
- raise "unhandled shape type: #{name}"
85
- end
86
- end
87
-
88
- def set_members members
89
- case @rules['type']
90
- when 'structure'
91
- @rules['members'] = {}
92
- members.each_pair do |member_name,member_rules|
93
-
94
- member_shape = new_shape(member_rules)
95
-
96
- member_key = inflect(member_name, @options[:inflect_member_names])
97
- member_rules = member_shape.rules
98
-
99
- if member_name != member_key
100
- member_rules = { 'name' => member_name }.merge(member_rules)
101
- end
102
-
103
- if swap_names?(member_shape)
104
- member_rules['name'] = member_key
105
- member_key = member_shape.xmlname
106
- end
107
-
108
- @rules['members'][member_key] = member_rules
109
-
110
- end
111
- when 'list'
112
- @rules['members'] = new_shape(members).rules
113
- when 'map'
114
- @rules['members'] = new_shape(members).rules
115
- else
116
- raise "unhandled complex shape `#{@rules['type']}'"
117
- end
118
- @rules.delete('members') if @rules['members'].empty?
119
- end
120
-
121
- def set_keys rules
122
- shape = new_shape(rules)
123
- @rules['keys'] = shape.rules
124
- @rules.delete('keys') if @rules['keys'].empty?
125
- end
126
-
127
- def set_xmlname name
128
- @xmlname = name
129
- @rules['name'] = name
130
- end
131
-
132
- def set_location location
133
- @rules['location'] = (location == 'http_status' ? 'status' : location)
134
- end
135
-
136
- def set_location_name header_name
137
- @rules['name'] = header_name
138
- end
139
-
140
- def set_payload state
141
- @rules['payload'] = true if state
142
- end
143
-
144
- def set_flattened state
145
- @rules['flattened'] = true if state
146
- end
147
-
148
- def set_streaming state
149
- @rules['streaming'] = true if state
150
- end
151
-
152
- def set_xmlnamespace ns
153
- @rules['xmlns'] = ns
154
- end
155
-
156
- def set_xmlattribute state
157
- @rules['attribute'] = true if state
158
- end
159
-
160
- def set_documentation docs
161
- @rules['documentation'] = docs if @options[:documentation]
162
- end
163
-
164
- def set_enum values
165
- @rules['enum'] = values if @options[:documentation]
166
- end
167
-
168
- def set_wrapper state
169
- @rules['wrapper'] = true if state
170
- end
171
-
172
- # we purposefully drop these, not useful unless you want to create
173
- # static classes
174
- def set_shape_name *args; end
175
- def set_box *args; end
176
-
177
- # @param [Hash] rules
178
- # @option options [String] :name The name this shape has as a structure member.
179
- def new_shape rules
180
- self.class.new(rules, @options)
181
- end
182
-
183
- end
184
-
185
- # @private
186
- class InputShape < Shape
187
-
188
- def set_required *args
189
- @rules['required'] = true;
190
- end
191
-
192
- def set_member_order order
193
- @rules['order'] = order
194
- end
195
-
196
- def set_min_length min
197
- @rules['min_length'] = min if @options[:documentation]
198
- end
199
-
200
- def set_max_length max
201
- @rules['max_length'] = max if @options[:documentation]
202
- end
203
-
204
- def set_pattern pattern
205
- @rules['pattern'] = pattern if @options[:documentation]
206
- end
207
-
208
- def swap_names? shape
209
- false
210
- end
211
-
212
- end
213
-
214
- # @private
215
- class OutputShape < Shape
216
-
217
- # these traits are ignored for output shapes
218
- def set_required *args; end
219
- def set_member_order *args; end
220
- def set_min_length *args; end
221
- def set_max_length *args; end
222
- def set_pattern *args; end
223
-
224
- def swap_names? shape
225
- if @options[:documentation]
226
- false
227
- else
228
- !!(%w(query rest-xml).include?(@options[:type]) and shape.xmlname)
229
- end
230
- end
231
-
232
- end
233
-
234
- end
235
- end
@@ -1,87 +0,0 @@
1
- require_relative './param_validator'
2
-
3
- module Seahorse
4
- module Controller
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- respond_to :json, :xml
9
-
10
- rescue_from Exception, :with => :render_error
11
-
12
- wrap_parameters false
13
-
14
- before_filter do
15
- @params = params
16
- @params = operation.input.from_input(params, false)
17
- @params.update(operation.input.from_input(map_headers, false))
18
-
19
- begin
20
- input_rules = operation.to_hash['input']
21
- %w(action controller format).each {|v| params.delete(v) }
22
- validator = Seahorse::ParamValidator.new(input_rules)
23
- validator.validate!(params)
24
- rescue ArgumentError => error
25
- if request.headers['HTTP_USER_AGENT'] =~ /sdk|cli/
26
- service_error(error, 'ValidationError')
27
- else
28
- raise(error)
29
- end
30
- end
31
-
32
- @params = operation.input.from_input(@params)
33
- @params = params.permit(*operation.input.to_strong_params)
34
-
35
- true
36
- end
37
- end
38
-
39
- private
40
-
41
- def render_error(exception)
42
- service_error(exception, exception.class.name)
43
- end
44
-
45
- def params
46
- @params || super
47
- end
48
-
49
- def respond_with(model, opts = {})
50
- opts[:location] = nil
51
- if opts[:error]
52
- opts[:status] = opts[:error]
53
- super
54
- else
55
- super(operation.output.to_output(model), opts)
56
- end
57
- end
58
-
59
- def operation
60
- return @operation if @operation
61
- @operation = api_model.operation_from_action(action_name)
62
- end
63
-
64
- def api_model
65
- return @api_model if @api_model
66
- @api_model = ('Api::' + controller_name.singularize.camelcase).constantize
67
- end
68
-
69
- def service_error(error, code = 'ServiceError', status = 400)
70
- respond_with({ code: code, message: error.message }, error: status)
71
- end
72
-
73
- def map_headers
74
- return @map_headers if @map_headers
75
- @map_headers = {}
76
- return @map_headers unless operation.input.default_type == 'structure'
77
- operation.input.members.each do |name, member|
78
- if member.header
79
- hdr_name = member.header == true ? name : member.header
80
- hdr_name = "HTTP_" + hdr_name.upcase.gsub('-', '_')
81
- @map_headers[name] = request.headers[hdr_name]
82
- end
83
- end
84
- @map_headers
85
- end
86
- end
87
- end
@@ -1,82 +0,0 @@
1
- module Seahorse
2
- module Model
3
- @@apis ||= {}
4
-
5
- class << self
6
- def apis; @@apis end
7
-
8
- def add_all_routes(router)
9
- Dir.glob("#{Rails.root}/app/models/api/*.rb").each {|f| load f }
10
- @@apis.values.each {|api| api.add_routes(router) }
11
- end
12
- end
13
-
14
- extend ActiveSupport::Concern
15
-
16
- included do
17
- @@apis[name.underscore.gsub(/_api$|^api\//, '')] = self
18
- end
19
-
20
- module ClassMethods
21
- attr_reader :operations
22
-
23
- def model_name
24
- name.underscore.gsub(/_api$|^api\//, '')
25
- end
26
-
27
- def add_routes(router)
28
- Seahorse::Router.new(self).add_routes(router)
29
- end
30
-
31
- def desc(text)
32
- @desc = text
33
- end
34
-
35
- def operation(name, &block)
36
- name, action = *operation_name_and_action(name)
37
- @actions ||= {}
38
- @operations ||= {}
39
- @operations[name] = Operation.new(self, name, action, &block)
40
- @operations[name].documentation = @desc
41
- @actions[action] = @operations[name]
42
- @desc = nil
43
- end
44
-
45
- def operation_from_action(action)
46
- @actions ||= {}
47
- @actions[action]
48
- end
49
-
50
- def type(name, &block)
51
- supertype = 'structure'
52
- name, supertype = *name.map {|k,v| [k, v] }.flatten if Hash === name
53
- ShapeBuilder.type(name, supertype, &block)
54
- end
55
-
56
- def to_hash
57
- ops = @operations.inject({}) do |hash, (name, operation)|
58
- hash[name.camelcase(:lower)] = operation.to_hash
59
- hash
60
- end
61
- {'operations' => ops}
62
- end
63
-
64
- private
65
-
66
- def operation_name_and_action(name)
67
- if Hash === name
68
- name.to_a.first.map(&:to_s).reverse
69
- else
70
- case name.to_s
71
- when 'index', 'list'
72
- ["list_#{model_name.pluralize}", 'index']
73
- when 'show'
74
- ["get_#{model_name}", name.to_s]
75
- else
76
- ["#{name}_#{model_name}", name.to_s]
77
- end
78
- end
79
- end
80
- end
81
- end
82
- end
@@ -1,66 +0,0 @@
1
- module Seahorse
2
- class Operation
3
- attr_reader :name, :verb, :action
4
- attr_accessor :documentation
5
-
6
- def initialize(controller, name, action = nil, &block)
7
- @name = name.to_s
8
- @action = action.to_s
9
- @controller = controller
10
- url_prefix = "/" + controller.model_name.pluralize
11
- url_extra = nil
12
-
13
- case action.to_s
14
- when 'index'
15
- @verb = 'get'
16
- when 'show'
17
- @verb = 'get'
18
- url_extra = ':id'
19
- when 'destroy', 'delete'
20
- @verb = 'delete'
21
- url_extra = ':id'
22
- when 'create'
23
- @verb = 'post'
24
- when 'update'
25
- @verb = 'put'
26
- else
27
- @verb = 'get'
28
- url_extra = name.to_s
29
- end
30
- @url = url_prefix + (url_extra ? "/#{url_extra}" : "")
31
-
32
- instance_eval(&block)
33
- end
34
-
35
- def verb(verb = nil)
36
- verb ? (@verb = verb) : @verb
37
- end
38
-
39
- def url(url = nil)
40
- url ? (@url = url) : @url
41
- end
42
-
43
- def input(type = nil, &block)
44
- @input ||= ShapeBuilder.type_class_for(type || 'structure').new
45
- type || block ? ShapeBuilder.new(@input).build(&block) : @input
46
- end
47
-
48
- def output(type = nil, &block)
49
- @output ||= ShapeBuilder.type_class_for(type || 'structure').new
50
- type || block ? ShapeBuilder.new(@output).build(&block) : @output
51
- end
52
-
53
- def to_hash
54
- {
55
- 'name' => name.camelcase,
56
- 'http' => {
57
- 'uri' => url.gsub(/:(\w+)/, '{\1}'),
58
- 'method' => verb.upcase
59
- },
60
- 'input' => input.to_hash,
61
- 'output' => output.to_hash,
62
- 'documentation' => documentation
63
- }
64
- end
65
- end
66
- end