functions_framework 0.3.0 → 0.5.1

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.
@@ -1,43 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require "functions_framework/cloud_events/content_type"
16
- require "functions_framework/cloud_events/errors"
17
- require "functions_framework/cloud_events/event"
18
- require "functions_framework/cloud_events/http_binding"
19
- require "functions_framework/cloud_events/json_format"
20
-
21
- module FunctionsFramework
22
- ##
23
- # CloudEvents implementation.
24
- #
25
- # This is a Ruby implementation of the [CloudEvents](https://cloudevents.io)
26
- # [1.0 specification](https://github.com/cloudevents/spec/blob/master/spec.md).
27
- #
28
- module CloudEvents
29
- # @private
30
- SUPPORTED_SPEC_VERSIONS = ["1.0"].freeze
31
-
32
- class << self
33
- ##
34
- # The spec versions supported by this implementation.
35
- #
36
- # @return [Array<String>]
37
- #
38
- def supported_spec_versions
39
- SUPPORTED_SPEC_VERSIONS
40
- end
41
- end
42
- end
43
- end
@@ -1,139 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module FunctionsFramework
16
- module CloudEvents
17
- ##
18
- # A parsed content-type header.
19
- #
20
- # This object represents the information contained in a Content-Type,
21
- # obtained by parsing the header according to RFC 2045.
22
- #
23
- # Case-insensitive fields, such as media_type and subtype, are normalized
24
- # to lower case.
25
- #
26
- class ContentType
27
- ##
28
- # Parse the given header value
29
- #
30
- # @param string [String] Content-Type header value in RFC 2045 format
31
- #
32
- def initialize string
33
- @string = string
34
- # TODO: This handles simple cases but is not RFC-822 compliant.
35
- sections = string.to_s.split ";"
36
- media_type, subtype = sections.shift.split "/"
37
- subtype_prefix, subtype_format = subtype.split "+"
38
- @media_type = media_type.strip.downcase
39
- @subtype = subtype.strip.downcase
40
- @subtype_prefix = subtype_prefix.strip.downcase
41
- @subtype_format = subtype_format&.strip&.downcase
42
- @params = initialize_params sections
43
- @canonical_string = "#{@media_type}/#{@subtype}" +
44
- @params.map { |k, v| "; #{k}=#{v}" }.join
45
- end
46
-
47
- ##
48
- # The original header content string
49
- # @return [String]
50
- #
51
- attr_reader :string
52
- alias to_s string
53
-
54
- ##
55
- # A "canonical" header content string with spacing and capitalization
56
- # normalized.
57
- # @return [String]
58
- #
59
- attr_reader :canonical_string
60
-
61
- ##
62
- # The media type.
63
- # @return [String]
64
- #
65
- attr_reader :media_type
66
-
67
- ##
68
- # The entire content subtype (which could include an extension delimited
69
- # by a plus sign)
70
- # @return [String]
71
- #
72
- attr_reader :subtype
73
-
74
- ##
75
- # The portion of the content subtype before any plus sign.
76
- # @return [String]
77
- #
78
- attr_reader :subtype_prefix
79
-
80
- ##
81
- # The portion of the content subtype after any plus sign, or nil if there
82
- # is no plus sign in the subtype.
83
- # @return [String,nil]
84
- #
85
- attr_reader :subtype_format
86
-
87
- ##
88
- # An array of parameters, each element as a two-element array of the
89
- # parameter name and value.
90
- # @return [Array<Array(String,String)>]
91
- #
92
- attr_reader :params
93
-
94
- ##
95
- # An array of values for the given parameter name
96
- # @param key [String]
97
- # @return [Array<String>]
98
- #
99
- def param_values key
100
- key = key.downcase
101
- @params.inject([]) { |a, (k, v)| key == k ? a << v : a }
102
- end
103
-
104
- ##
105
- # The first value of the "charset" parameter, or nil if there is no
106
- # charset.
107
- # @return [String,nil]
108
- #
109
- def charset
110
- param_values("charset").first
111
- end
112
-
113
- ## @private
114
- def == other
115
- other.is_a?(ContentType) && canonical_string == other.canonical_string
116
- end
117
- alias eql? ==
118
-
119
- ## @private
120
- def hash
121
- canonical_string.hash
122
- end
123
-
124
- private
125
-
126
- def initialize_params sections
127
- params = sections.map do |s|
128
- k, v = s.split "="
129
- [k.strip.downcase, v.strip]
130
- end
131
- params.sort! do |(k1, v1), (k2, v2)|
132
- a = k1 <=> k2
133
- a.zero? ? v1 <=> v2 : a
134
- end
135
- params
136
- end
137
- end
138
- end
139
- end
@@ -1,42 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module FunctionsFramework
16
- module CloudEvents
17
- ##
18
- # Base class for all CloudEvents errors.
19
- #
20
- class CloudEventsError < ::RuntimeError
21
- end
22
-
23
- ##
24
- # Errors indicating unsupported or incorrectly formatted HTTP content or
25
- # headers.
26
- #
27
- class HttpContentError < CloudEventsError
28
- end
29
-
30
- ##
31
- # Errors indicating an unsupported or incorrect spec version.
32
- #
33
- class SpecVersionError < CloudEventsError
34
- end
35
-
36
- ##
37
- # Errors related to CloudEvent attributes.
38
- #
39
- class AttributeError < CloudEventsError
40
- end
41
- end
42
- end
@@ -1,79 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require "date"
16
- require "uri"
17
-
18
- require "functions_framework/cloud_events/event/v1"
19
-
20
- module FunctionsFramework
21
- module CloudEvents
22
- ##
23
- # CloudEvent object.
24
- #
25
- # An Event object represents a complete event, including both its data and
26
- # its context attributes. The following are true of all event objects:
27
- #
28
- # * Event classes are defined within this module. For example, events
29
- # conforming to the CloudEvents 1.0 specification are of type
30
- # {FunctionsFramework::CloudEvents::Event::V1}.
31
- # * All event classes include this module, so you can use
32
- # `is_a? FunctionsFramework::CloudEvents::Event` to test whether an
33
- # object is an event.
34
- # * All event objects are immutable. Data and atribute values can be
35
- # retrieved but not modified. To "modify" an event, make a copy with
36
- # the desired changes. Generally, event classes will provide a helper
37
- # method for this purpose.
38
- # * All event objects have a `spec_version` method that returns the
39
- # version of the CloudEvents spec implemented by that event. (Other
40
- # methods may be different, depending on the spec version.)
41
- #
42
- # To create an event, you may either:
43
- #
44
- # * Construct an instance of the event class directly, for example by
45
- # calling {Event::V1.new} and passing a set of attributes.
46
- # * Call {Event.create} and pass a spec version and a set of attributes.
47
- # This will choose the appropriate event class based on the version.
48
- # * Decode an event from another representation. For example, use
49
- # {CloudEvents::JsonFormat} to decode an event from JSON, or use
50
- # {CloudEvents::HttpBinding} to decode an event from an HTTP request.
51
- #
52
- # See https://github.com/cloudevents/spec/blob/master/spec.md for more
53
- # information about CloudEvents.
54
- #
55
- module Event
56
- class << self
57
- ##
58
- # Create a new cloud event object with the given version. Generally,
59
- # you must also pass additional keyword arguments providing the event's
60
- # data and attributes. For example, if you pass `1.0` as the
61
- # `spec_version`, the remaining keyword arguments will be passed
62
- # through to the {Event::V1.new} constructor.
63
- #
64
- # @param spec_version [String] The required `specversion` field.
65
- # @param kwargs [keywords] Additional parameters for the event.
66
- #
67
- def create spec_version:, **kwargs
68
- case spec_version
69
- when /^1(\.|$)/
70
- V1.new spec_version: spec_version, **kwargs
71
- else
72
- raise SpecVersionError, "Unrecognized specversion: #{spec_version}"
73
- end
74
- end
75
- alias new create
76
- end
77
- end
78
- end
79
- end
@@ -1,363 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require "date"
16
- require "uri"
17
-
18
- module FunctionsFramework
19
- module CloudEvents
20
- module Event
21
- ##
22
- # A CloudEvents V1 data type.
23
- #
24
- # This object a complete CloudEvent, including the event data and its
25
- # context attributes. It supports the standard required and optional
26
- # attributes defined in CloudEvents V1, and arbitrary extension
27
- # attributes. All attribute values can be obtained (in their string form)
28
- # via the {Event::V1#[]} method. Additionally, standard attributes have
29
- # their own accessor methods that may return typed objects (such as
30
- # `DateTime` for the `time` attribute).
31
- #
32
- # This object is immutable. The data and attribute values can be
33
- # retrieved but not modified. To obtain an event with modifications, use
34
- # the {#with} method to create a copy with the desired changes.
35
- #
36
- # See https://github.com/cloudevents/spec/blob/master/spec.md for
37
- # descriptions of the standard attributes.
38
- #
39
- class V1
40
- include Event
41
-
42
- ##
43
- # Create a new cloud event object with the given data and attributes.
44
- #
45
- # Event attributes may be presented as keyword arguments, or as a Hash
46
- # passed in via the `attributes` argument (but not both).
47
- #
48
- # The following standard attributes are supported and exposed as
49
- # attribute methods on the object.
50
- #
51
- # * **:spec_version** (or **:specversion**) [`String`] - _required_ -
52
- # The CloudEvents spec version (i.e. the `specversion` field.)
53
- # * **:id** [`String`] - _required_ - The event `id` field.
54
- # * **:source** [`String`, `URI`] - _required_ - The event `source`
55
- # field.
56
- # * **:type** [`String`] - _required_ - The event `type` field.
57
- # * **:data** [`Object`] - _optional_ - The data associated with the
58
- # event (i.e. the `data` field.)
59
- # * **:data_content_type** (or **:datacontenttype**) [`String`,
60
- # {ContentType}] - _optional_ - The content-type for the data, if
61
- # the data is a string (i.e. the event `datacontenttype` field.)
62
- # * **:data_schema** (or **:dataschema**) [`String`, `URI`] -
63
- # _optional_ - The event `dataschema` field.
64
- # * **:subject** [`String`] - _optional_ - The event `subject` field.
65
- # * **:time** [`String`, `DateTime`, `Time`] - _optional_ - The
66
- # event `time` field.
67
- #
68
- # Any additional attributes are assumed to be extension attributes.
69
- # They are not available as separate methods, but can be accessed via
70
- # the {Event::V1#[]} operator.
71
- #
72
- # @param attributes [Hash] The data and attributes, as a hash.
73
- # @param args [keywords] The data and attributes, as keyword arguments.
74
- #
75
- def initialize attributes: nil, **args # rubocop:disable Metrics/AbcSize
76
- args = keys_to_strings(attributes || args)
77
- @attributes = {}
78
- @spec_version, _unused = interpret_string args, ["specversion", "spec_version"], required: true
79
- raise SpecVersionError, "Unrecognized specversion: #{@spec_version}" unless /^1(\.|$)/ =~ @spec_version
80
- @id, _unused = interpret_string args, ["id"], required: true
81
- @source, @source_string = interpret_uri args, ["source"], required: true
82
- @type, _unused = interpret_string args, ["type"], required: true
83
- @data, _unused = interpret_value args, ["data"], allow_nil: true
84
- @data_content_type, @data_content_type_string =
85
- interpret_content_type args, ["datacontenttype", "data_content_type"]
86
- @data_schema, @data_schema_string = interpret_uri args, ["dataschema", "data_schema"]
87
- @subject, _unused = interpret_string args, ["subject"]
88
- @time, @time_string = interpret_date_time args, ["time"]
89
- @attributes.merge! args
90
- end
91
-
92
- ##
93
- # Create and return a copy of this event with the given changes. See
94
- # the constructor for the parameters that can be passed. In general,
95
- # you can pass a new value for any attribute, or pass `nil` to remove
96
- # an optional attribute.
97
- #
98
- # @param changes [keywords] See {#initialize} for a list of arguments.
99
- # @return [FunctionFramework::CloudEvents::Event]
100
- #
101
- def with **changes
102
- attributes = @attributes.merge keys_to_strings changes
103
- V1.new attributes: attributes
104
- end
105
-
106
- ##
107
- # Return the value of the given named attribute. Both standard and
108
- # extension attributes are supported.
109
- #
110
- # Attribute names must be given as defined in the standard CloudEvents
111
- # specification. For example `specversion` rather than `spec_version`.
112
- #
113
- # Results are given in their "raw" form, generally a string. This may
114
- # be different from what is returned from corresponding attribute
115
- # methods. For example:
116
- #
117
- # event["time"] # => String rfc3339 representation
118
- # event.time # => DateTime object
119
- # event.time_string # => String rfc3339 representation
120
- #
121
- # @param key [String,Symbol] The attribute name.
122
- # @return [String,nil]
123
- #
124
- def [] key
125
- @attributes[key.to_s]
126
- end
127
-
128
- ##
129
- # Return a hash representation of this event.
130
- #
131
- # @return [Hash]
132
- #
133
- def to_h
134
- @attributes.dup
135
- end
136
-
137
- ##
138
- # The `id` field. Required.
139
- #
140
- # @return [String]
141
- #
142
- attr_reader :id
143
-
144
- ##
145
- # The `source` field as a `URI` object. Required.
146
- #
147
- # @return [URI]
148
- #
149
- attr_reader :source
150
-
151
- ##
152
- # The string representation of the `source` field. Required.
153
- #
154
- # @return [String]
155
- #
156
- attr_reader :source_string
157
-
158
- ##
159
- # The `type` field. Required.
160
- #
161
- # @return [String]
162
- #
163
- attr_reader :type
164
-
165
- ##
166
- # The `specversion` field. Required.
167
- #
168
- # @return [String]
169
- #
170
- attr_reader :spec_version
171
- alias specversion spec_version
172
-
173
- ##
174
- # The event-specific data, or `nil` if there is no data.
175
- #
176
- # Data may be one of the following types:
177
- # * Binary data, represented by a `String` using the `ASCII-8BIT`
178
- # encoding.
179
- # * A string in some other encoding such as `UTF-8` or `US-ASCII`.
180
- # * Any JSON data type, such as String, boolean, Integer, Array, or
181
- # Hash
182
- #
183
- # @return [Object]
184
- #
185
- attr_reader :data
186
-
187
- ##
188
- # The optional `datacontenttype` field as a
189
- # {FunctionsFramework::CloudEvents::ContentType} object, or `nil` if
190
- # the field is absent.
191
- #
192
- # @return [FunctionsFramework::CloudEvents::ContentType,nil]
193
- #
194
- attr_reader :data_content_type
195
- alias datacontenttype data_content_type
196
-
197
- ##
198
- # The string representation of the optional `datacontenttype` field, or
199
- # `nil` if the field is absent.
200
- #
201
- # @return [String,nil]
202
- #
203
- attr_reader :data_content_type_string
204
- alias datacontenttype_string data_content_type_string
205
-
206
- ##
207
- # The optional `dataschema` field as a `URI` object, or `nil` if the
208
- # field is absent.
209
- #
210
- # @return [URI,nil]
211
- #
212
- attr_reader :data_schema
213
- alias dataschema data_schema
214
-
215
- ##
216
- # The string representation of the optional `dataschema` field, or
217
- # `nil` if the field is absent.
218
- #
219
- # @return [String,nil]
220
- #
221
- attr_reader :data_schema_string
222
- alias dataschema_string data_schema_string
223
-
224
- ##
225
- # The optional `subject` field, or `nil` if the field is absent.
226
- #
227
- # @return [String,nil]
228
- #
229
- attr_reader :subject
230
-
231
- ##
232
- # The optional `time` field as a `DateTime` object, or `nil` if the
233
- # field is absent.
234
- #
235
- # @return [DateTime,nil]
236
- #
237
- attr_reader :time
238
-
239
- ##
240
- # The rfc3339 string representation of the optional `time` field, or
241
- # `nil` if the field is absent.
242
- #
243
- # @return [String,nil]
244
- #
245
- attr_reader :time_string
246
-
247
- ## @private
248
- def == other
249
- other.is_a?(V1) && @attributes == other.instance_variable_get(:@attributes)
250
- end
251
- alias eql? ==
252
-
253
- ## @private
254
- def hash
255
- @hash ||= @attributes.hash
256
- end
257
-
258
- private
259
-
260
- def keys_to_strings hash
261
- result = {}
262
- hash.each do |key, val|
263
- result[key.to_s] = val
264
- end
265
- result
266
- end
267
-
268
- def interpret_string args, keys, required: false
269
- interpret_value args, keys, required: required do |value|
270
- case value
271
- when ::String
272
- raise AttributeError, "The #{keys.last} field cannot be empty" if value.empty?
273
- [value, value]
274
- else
275
- raise AttributeError, "Illegal type for #{keys.last}:" \
276
- " String expected but #{value.class} found"
277
- end
278
- end
279
- end
280
-
281
- def interpret_uri args, keys, required: false
282
- interpret_value args, keys, required: required do |value|
283
- case value
284
- when ::String
285
- raise AttributeError, "The #{keys.last} field cannot be empty" if value.empty?
286
- begin
287
- [::URI.parse(value), value]
288
- rescue ::URI::InvalidURIError => e
289
- raise AttributeError, "Illegal format for #{keys.last}: #{e.message}"
290
- end
291
- when ::URI::Generic
292
- [value, value.to_s]
293
- else
294
- raise AttributeError, "Illegal type for #{keys.last}:" \
295
- " String or URI expected but #{value.class} found"
296
- end
297
- end
298
- end
299
-
300
- def interpret_date_time args, keys, required: false
301
- interpret_value args, keys, required: required do |value|
302
- case value
303
- when ::String
304
- begin
305
- [::DateTime.rfc3339(value), value]
306
- rescue ::Date::Error => e
307
- raise AttributeError, "Illegal format for #{keys.last}: #{e.message}"
308
- end
309
- when ::DateTime
310
- [value, value.rfc3339]
311
- when ::Time
312
- value = value.to_datetime
313
- [value, value.rfc3339]
314
- else
315
- raise AttributeError, "Illegal type for #{keys.last}:" \
316
- " String, Time, or DateTime expected but #{value.class} found"
317
- end
318
- end
319
- end
320
-
321
- def interpret_content_type args, keys, required: false
322
- interpret_value args, keys, required: required do |value|
323
- case value
324
- when ::String
325
- raise AttributeError, "The #{keys.last} field cannot be empty" if value.empty?
326
- [ContentType.new(value), value]
327
- when ContentType
328
- [value, value.to_s]
329
- else
330
- raise AttributeError, "Illegal type for #{keys.last}:" \
331
- " String, or ContentType expected but #{value.class} found"
332
- end
333
- end
334
- end
335
-
336
- def interpret_value args, keys, required: false, allow_nil: false
337
- value = nil
338
- found = false
339
- keys.each do |key|
340
- key_present = args.key? key
341
- val = args.delete key
342
- if allow_nil && key_present || !allow_nil && !val.nil?
343
- value = val
344
- found = true
345
- end
346
- end
347
- if found
348
- if block_given?
349
- converted, raw = yield value
350
- else
351
- converted = raw = value
352
- end
353
- @attributes[keys.first] = raw
354
- [converted, raw]
355
- else
356
- raise AttributeError, "The #{keys.last} field is required" if required
357
- [nil, nil]
358
- end
359
- end
360
- end
361
- end
362
- end
363
- end