seahorse 0.1.0 → 1.0.0.pre1

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