functions_framework 0.0.0 → 0.1.0
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.
- checksums.yaml +4 -4
- data/.yardopts +0 -1
- data/CHANGELOG.md +3 -0
- data/README.md +202 -2
- data/bin/functions-framework +19 -0
- data/lib/functions_framework/cli.rb +113 -0
- data/lib/functions_framework/cloud_events/binary_content.rb +59 -0
- data/lib/functions_framework/cloud_events/content_type.rb +139 -0
- data/lib/functions_framework/cloud_events/event.rb +277 -0
- data/lib/functions_framework/cloud_events/json_structure.rb +88 -0
- data/lib/functions_framework/cloud_events.rb +143 -0
- data/lib/functions_framework/function.rb +75 -0
- data/lib/functions_framework/registry.rb +137 -0
- data/lib/functions_framework/server.rb +423 -0
- data/lib/functions_framework/testing.rb +244 -0
- data/lib/functions_framework/version.rb +1 -1
- data/lib/functions_framework.rb +217 -1
- metadata +15 -4
- data/CONTRIBUTING.md +0 -32
@@ -0,0 +1,277 @@
|
|
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
|
+
##
|
21
|
+
# A cloud event data type.
|
22
|
+
#
|
23
|
+
# This object represents both the event data and the context attributes.
|
24
|
+
# It is immutable. The data and attribute values can be retrieved but not
|
25
|
+
# modified. To obtain an event with modifications, use the {#with} method
|
26
|
+
# to create a copy with the desired changes.
|
27
|
+
#
|
28
|
+
# See https://github.com/cloudevents/spec/blob/master/spec.md for
|
29
|
+
# descriptions of the various attributes.
|
30
|
+
#
|
31
|
+
class Event
|
32
|
+
##
|
33
|
+
# Create a new cloud event object with the given data and attributes.
|
34
|
+
#
|
35
|
+
# @param id [String] The required `id` field
|
36
|
+
# @param source [String,URI] The required `source` field
|
37
|
+
# @param type [String] The required `type` field
|
38
|
+
# @param spec_version [String] The required `specversion` field
|
39
|
+
# @param data [String,Boolean,Integer,Array,Hash] The optional `data`
|
40
|
+
# field
|
41
|
+
# @param data_content_type [String,FunctionsFramework::CloudEvents::ContentType]
|
42
|
+
# The optional `datacontenttype` field
|
43
|
+
# @param data_schema [String,URI] The optional `dataschema` field
|
44
|
+
# @param subject [String] The optional `subject` field
|
45
|
+
# @param time [String,DateTime] The optional `time` field
|
46
|
+
#
|
47
|
+
def initialize \
|
48
|
+
id:,
|
49
|
+
source:,
|
50
|
+
type:,
|
51
|
+
spec_version:,
|
52
|
+
data: nil,
|
53
|
+
data_content_type: nil,
|
54
|
+
data_schema: nil,
|
55
|
+
subject: nil,
|
56
|
+
time: nil
|
57
|
+
@id = interpret_string "id", id, true
|
58
|
+
@source, @source_string = interpret_uri "source", source, true
|
59
|
+
@type = interpret_string "type", type, true
|
60
|
+
@spec_version = interpret_string "spec_version", spec_version, true
|
61
|
+
@data = data
|
62
|
+
@data_content_type, @data_content_type_string =
|
63
|
+
interpret_content_type "data_content_type", data_content_type
|
64
|
+
@data_schema, @data_schema_string = interpret_uri "data_schema", data_schema
|
65
|
+
@subject = interpret_string "subject", subject
|
66
|
+
@time, @time_string = interpret_date_time "time", time
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Create and return a copy of this event with the given changes. See the
|
71
|
+
# constructor for the parameters that can be passed.
|
72
|
+
#
|
73
|
+
# @param changes [keywords] See {#initialize} for a list of arguments.
|
74
|
+
# @return [FunctionFramework::CloudEvents::Event]
|
75
|
+
#
|
76
|
+
def with **changes
|
77
|
+
params = {
|
78
|
+
id: id,
|
79
|
+
source: source,
|
80
|
+
type: type,
|
81
|
+
spec_version: spec_version,
|
82
|
+
data: data,
|
83
|
+
data_content_type: data_content_type,
|
84
|
+
data_schema: data_schema,
|
85
|
+
subject: subject,
|
86
|
+
time: time
|
87
|
+
}
|
88
|
+
params.merge! changes
|
89
|
+
Event.new(**params)
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# The `id` field
|
94
|
+
# @return [String]
|
95
|
+
#
|
96
|
+
attr_reader :id
|
97
|
+
|
98
|
+
##
|
99
|
+
# The `source` field as a `URI` object
|
100
|
+
# @return [URI]
|
101
|
+
#
|
102
|
+
attr_reader :source
|
103
|
+
|
104
|
+
##
|
105
|
+
# The string representation of the `source` field
|
106
|
+
# @return [String]
|
107
|
+
#
|
108
|
+
attr_reader :source_string
|
109
|
+
|
110
|
+
##
|
111
|
+
# The `type` field
|
112
|
+
# @return [String]
|
113
|
+
#
|
114
|
+
attr_reader :type
|
115
|
+
|
116
|
+
##
|
117
|
+
# The `specversion` field
|
118
|
+
# @return [String]
|
119
|
+
#
|
120
|
+
attr_reader :spec_version
|
121
|
+
alias specversion spec_version
|
122
|
+
|
123
|
+
##
|
124
|
+
# The event-specific data, or `nil` if there is no data.
|
125
|
+
#
|
126
|
+
# Data may be one of the following types:
|
127
|
+
# * Binary data, represented by a `String` using `ASCII-8BIT` encoding
|
128
|
+
# * A string in some other encoding such as `UTF-8` or `US-ASCII`
|
129
|
+
# * Any JSON data type, such as String, boolean, Integer, Array, or Hash
|
130
|
+
#
|
131
|
+
# @return [Object]
|
132
|
+
#
|
133
|
+
attr_reader :data
|
134
|
+
|
135
|
+
##
|
136
|
+
# The optional `datacontenttype` field as a
|
137
|
+
# {FunctionsFramework::CloudEvents::ContentType} object, or `nil` if the
|
138
|
+
# field is absent
|
139
|
+
#
|
140
|
+
# @return [FunctionsFramework::CloudEvents::ContentType,nil]
|
141
|
+
#
|
142
|
+
attr_reader :data_content_type
|
143
|
+
alias datacontenttype data_content_type
|
144
|
+
|
145
|
+
##
|
146
|
+
# The string representation of the optional `datacontenttype` field, or
|
147
|
+
# `nil` if the field is absent
|
148
|
+
#
|
149
|
+
# @return [String,nil]
|
150
|
+
#
|
151
|
+
attr_reader :data_content_type_string
|
152
|
+
alias datacontenttype_string data_content_type_string
|
153
|
+
|
154
|
+
##
|
155
|
+
# The optional `dataschema` field as a `URI` object, or `nil` if the
|
156
|
+
# field is absent
|
157
|
+
#
|
158
|
+
# @return [URI,nil]
|
159
|
+
#
|
160
|
+
attr_reader :data_schema
|
161
|
+
alias dataschema data_schema
|
162
|
+
|
163
|
+
##
|
164
|
+
# The string representation of the optional `dataschema` field, or `nil`
|
165
|
+
# if the field is absent
|
166
|
+
#
|
167
|
+
# @return [String,nil]
|
168
|
+
#
|
169
|
+
attr_reader :data_schema_string
|
170
|
+
alias dataschema_string data_schema_string
|
171
|
+
|
172
|
+
##
|
173
|
+
# The optional `subject` field, or `nil` if the field is absent
|
174
|
+
#
|
175
|
+
# @return [String,nil]
|
176
|
+
#
|
177
|
+
attr_reader :subject
|
178
|
+
|
179
|
+
##
|
180
|
+
# The optional `time` field as a `DateTime` object, or `nil` if the field
|
181
|
+
# is absent
|
182
|
+
#
|
183
|
+
# @return [DateTime,nil]
|
184
|
+
#
|
185
|
+
attr_reader :time
|
186
|
+
|
187
|
+
##
|
188
|
+
# The string representation of the optional `time` field, or `nil` if the
|
189
|
+
# field is absent
|
190
|
+
#
|
191
|
+
# @return [String,nil]
|
192
|
+
#
|
193
|
+
attr_reader :time_string
|
194
|
+
|
195
|
+
## @private
|
196
|
+
def == other
|
197
|
+
other.is_a?(ContentType) &&
|
198
|
+
id == other.id &&
|
199
|
+
source == other.source &&
|
200
|
+
type == other.type &&
|
201
|
+
spec_version == other.spec_version &&
|
202
|
+
data_content_type == other.data_content_type &&
|
203
|
+
data_schema == other.data_schema &&
|
204
|
+
subject == other.subject &&
|
205
|
+
time == other.time &&
|
206
|
+
data == other.data
|
207
|
+
end
|
208
|
+
alias eql? ==
|
209
|
+
|
210
|
+
## @private
|
211
|
+
def hash
|
212
|
+
@hash ||=
|
213
|
+
[id, source, type, spec_version, data_content_type, data_schema, subject, time, data].hash
|
214
|
+
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
def interpret_string name, input, required = false
|
219
|
+
case input
|
220
|
+
when ::String
|
221
|
+
raise ::ArgumentError, "The #{name} field cannot be empty" if input.empty?
|
222
|
+
input
|
223
|
+
when nil
|
224
|
+
raise ::ArgumentError, "The #{name} field is required" if required
|
225
|
+
nil
|
226
|
+
else
|
227
|
+
raise ::ArgumentError, "Illegal type for #{name} field: #{input.inspect}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def interpret_uri name, input, required = false
|
232
|
+
case input
|
233
|
+
when ::String
|
234
|
+
raise ::ArgumentError, "The #{name} field cannot be empty" if input.empty?
|
235
|
+
[::URI.parse(input), input]
|
236
|
+
when ::URI::Generic
|
237
|
+
[input, input.to_s]
|
238
|
+
when nil
|
239
|
+
raise ::ArgumentError, "The #{name} field is required" if required
|
240
|
+
[nil, nil]
|
241
|
+
else
|
242
|
+
raise ::ArgumentError, "Illegal type for #{name} field: #{input.inspect}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def interpret_date_time name, input, required = false
|
247
|
+
case input
|
248
|
+
when ::String
|
249
|
+
raise ::ArgumentError, "The #{name} field cannot be empty" if input.empty?
|
250
|
+
[::DateTime.rfc3339(input), input]
|
251
|
+
when ::DateTime
|
252
|
+
[input, input.rfc3339]
|
253
|
+
when nil
|
254
|
+
raise ::ArgumentError, "The #{name} field is required" if required
|
255
|
+
[nil, nil]
|
256
|
+
else
|
257
|
+
raise ::ArgumentError, "Illegal type for #{name} field: #{input.inspect}"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def interpret_content_type name, input, required = false
|
262
|
+
case input
|
263
|
+
when ::String
|
264
|
+
raise ::ArgumentError, "The #{name} field cannot be empty" if input.empty?
|
265
|
+
[ContentType.new(input), input]
|
266
|
+
when ContentType
|
267
|
+
[input, input.to_s]
|
268
|
+
when nil
|
269
|
+
raise ::ArgumentError, "The #{name} field is required" if required
|
270
|
+
[nil, nil]
|
271
|
+
else
|
272
|
+
raise ::ArgumentError, "Illegal type for #{name} field: #{input.inspect}"
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,88 @@
|
|
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 "base64"
|
16
|
+
require "json"
|
17
|
+
|
18
|
+
module FunctionsFramework
|
19
|
+
module CloudEvents
|
20
|
+
##
|
21
|
+
# A content handler for the JSON structure and JSON batch format.
|
22
|
+
# See https://github.com/cloudevents/spec/blob/master/json-format.md
|
23
|
+
#
|
24
|
+
module JsonStructure
|
25
|
+
class << self
|
26
|
+
##
|
27
|
+
# Decode an event from the given input string
|
28
|
+
#
|
29
|
+
# @param input [IO] An IO-like object providing a JSON-formatted string
|
30
|
+
# @param content_type [FunctionsFramework::CloudEvents::ContentType]
|
31
|
+
# the content type
|
32
|
+
# @return [FunctionsFramework::CloudEvents::Event]
|
33
|
+
#
|
34
|
+
def decode_structured_content input, content_type
|
35
|
+
input = input.read if input.respond_to? :read
|
36
|
+
charset = content_type.charset
|
37
|
+
input = input.encode charset if charset
|
38
|
+
structure = ::JSON.parse input
|
39
|
+
decode_hash_structure structure
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Decode a batch of events from the given input string
|
44
|
+
#
|
45
|
+
# @param input [IO] An IO-like object providing a JSON-formatted string
|
46
|
+
# @param content_type [FunctionsFramework::CloudEvents::ContentType]
|
47
|
+
# the content type
|
48
|
+
# @return [Array<FunctionsFramework::CloudEvents::Event>]
|
49
|
+
#
|
50
|
+
def decode_batched_content input, content_type
|
51
|
+
input = input.read if input.respond_to? :read
|
52
|
+
charset = content_type.charset
|
53
|
+
input = input.encode charset if charset
|
54
|
+
structure_array = Array(::JSON.parse(input))
|
55
|
+
structure_array.map { |structure| decode_hash_structure structure }
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Decode a single event from a hash data structure with keys and types
|
60
|
+
# conforming to the JSON event format
|
61
|
+
#
|
62
|
+
# @param structure [Hash] Input hash
|
63
|
+
# @return [FunctionsFramework::CloudEvents::Event]
|
64
|
+
#
|
65
|
+
def decode_hash_structure structure
|
66
|
+
data =
|
67
|
+
if structure.key? "data_base64"
|
68
|
+
::Base64.decode64 structure["data_base64"]
|
69
|
+
else
|
70
|
+
structure["data"]
|
71
|
+
end
|
72
|
+
spec_version = structure["specversion"]
|
73
|
+
raise "Unrecognized specversion: #{spec_version}" unless spec_version == "1.0"
|
74
|
+
Event.new \
|
75
|
+
id: structure["id"],
|
76
|
+
source: structure["source"],
|
77
|
+
type: structure["type"],
|
78
|
+
spec_version: spec_version,
|
79
|
+
data: data,
|
80
|
+
data_content_type: structure["datacontenttype"],
|
81
|
+
data_schema: structure["dataschema"],
|
82
|
+
subject: structure["subject"],
|
83
|
+
time: structure["time"]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,143 @@
|
|
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/binary_content"
|
16
|
+
require "functions_framework/cloud_events/content_type"
|
17
|
+
require "functions_framework/cloud_events/event"
|
18
|
+
|
19
|
+
module FunctionsFramework
|
20
|
+
##
|
21
|
+
# CloudEvents implementation.
|
22
|
+
#
|
23
|
+
# This is a Ruby implementation of the [CloudEvents](https://cloudevents.io)
|
24
|
+
# [1.0 specification](https://github.com/cloudevents/spec/blob/master/spec.md).
|
25
|
+
# It provides for unmarshaling of events from Rack environment data from
|
26
|
+
# binary (i.e. header-based) format, as well as structured (body-based) and
|
27
|
+
# batch formats. A standard JSON structure parser is included. It is also
|
28
|
+
# possible to register handlers for other formats.
|
29
|
+
#
|
30
|
+
# TODO: Unmarshaling of events is implemented, but marshaling is not.
|
31
|
+
#
|
32
|
+
module CloudEvents
|
33
|
+
@structured_formats = {}
|
34
|
+
@batched_formats = {}
|
35
|
+
|
36
|
+
class << self
|
37
|
+
##
|
38
|
+
# Register a handler for the given structured format.
|
39
|
+
# The handler object must respond to the method
|
40
|
+
# `#decode_structured_content`. See
|
41
|
+
# {FunctionsFramework::CloudEvents::JsonStructure} for an example.
|
42
|
+
#
|
43
|
+
# @param format [String] The subtype format that should be handled by
|
44
|
+
# this handler
|
45
|
+
# @param handler [#decode_structured_content] The handler object
|
46
|
+
# @return [self]
|
47
|
+
#
|
48
|
+
def register_structured_format format, handler
|
49
|
+
handlers = @structured_formats[format.to_s.strip.downcase] ||= []
|
50
|
+
handlers << handler unless handlers.include? handler
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Register a handler for the given batched format.
|
56
|
+
# The handler object must respond to the method
|
57
|
+
# `#decode_batched_content`. See
|
58
|
+
# {FunctionsFramework::CloudEvents::JsonStructure} for an example.
|
59
|
+
#
|
60
|
+
# @param format [String] The subtype format that should be handled by
|
61
|
+
# this handler
|
62
|
+
# @param handler [#decode_batched_content] The handler object
|
63
|
+
# @return [self]
|
64
|
+
#
|
65
|
+
def register_batched_format format, handler
|
66
|
+
handlers = @batched_formats[format.to_s.strip.downcase] ||= []
|
67
|
+
handlers << handler unless handlers.include? handler
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Decode an event from the given Rack environment hash. Following the
|
73
|
+
# CloudEvents spec, this chooses a handler based on the Content-Type of
|
74
|
+
# the request.
|
75
|
+
#
|
76
|
+
# @param env [Hash] The Rack environment
|
77
|
+
# @return [FunctionsFramework::CloudEvents::Event] if the request
|
78
|
+
# includes a single structured or binary event
|
79
|
+
# @return [Array<FunctionsFramework::CloudEvents::Event>] if the request
|
80
|
+
# includes a batch of structured events
|
81
|
+
#
|
82
|
+
def decode_rack_env env
|
83
|
+
content_type_header = env["CONTENT_TYPE"]
|
84
|
+
raise "Missing content-type header" unless content_type_header
|
85
|
+
content_type = ContentType.new content_type_header
|
86
|
+
if content_type.media_type == "application"
|
87
|
+
case content_type.subtype_prefix
|
88
|
+
when "cloudevents"
|
89
|
+
return decode_structured_content env["rack.input"], content_type
|
90
|
+
when "cloudevents-batch"
|
91
|
+
return decode_batched_content env["rack.input"], content_type
|
92
|
+
end
|
93
|
+
end
|
94
|
+
BinaryContent.decode_rack_env env, content_type
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Decode a single event from the given content data. This should be
|
99
|
+
# passed the request body, if the Content-Type is of the form
|
100
|
+
# `application/cloudevents+format`.
|
101
|
+
#
|
102
|
+
# @param input [IO] An IO-like object providing the content
|
103
|
+
# @param content_type [FunctionsFramework::CloudEvents::ContentType] the
|
104
|
+
# content type
|
105
|
+
# @return [FunctionsFramework::CloudEvents::Event]
|
106
|
+
#
|
107
|
+
def decode_structured_content input, content_type
|
108
|
+
handlers = @structured_formats[content_type.subtype_format] || []
|
109
|
+
handlers.reverse_each do |handler|
|
110
|
+
event = handler.decode_structured_content input, content_type
|
111
|
+
return event if event
|
112
|
+
end
|
113
|
+
raise "Unknown cloudevents format: #{content_type.subtype_format.inspect}"
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Decode a batch of events from the given content data. This should be
|
118
|
+
# passed the request body, if the Content-Type is of the form
|
119
|
+
# `application/cloudevents-batch+format`.
|
120
|
+
#
|
121
|
+
# @param input [IO] An IO-like object providing the content
|
122
|
+
# @param content_type [FunctionsFramework::CloudEvents::ContentType] the
|
123
|
+
# content type
|
124
|
+
# @return [Array<FunctionsFramework::CloudEvents::Event>]
|
125
|
+
#
|
126
|
+
def decode_batched_content input, content_type
|
127
|
+
handlers = @batched_formats[content_type.subtype_format] || []
|
128
|
+
handlers.reverse_each do |handler|
|
129
|
+
events = handler.decode_batched_content input, content_type
|
130
|
+
return events if events
|
131
|
+
end
|
132
|
+
raise "Unknown cloudevents batch format: #{content_type.subtype_format.inspect}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
require "functions_framework/cloud_events/json_structure"
|
139
|
+
|
140
|
+
FunctionsFramework::CloudEvents.register_structured_format \
|
141
|
+
"json", FunctionsFramework::CloudEvents::JsonStructure
|
142
|
+
FunctionsFramework::CloudEvents.register_batched_format \
|
143
|
+
"json", FunctionsFramework::CloudEvents::JsonStructure
|
@@ -0,0 +1,75 @@
|
|
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
|
+
##
|
17
|
+
# Representation of a function.
|
18
|
+
#
|
19
|
+
# A function has a name, a type, and a code definition.
|
20
|
+
#
|
21
|
+
class Function
|
22
|
+
##
|
23
|
+
# Create a new function definition.
|
24
|
+
#
|
25
|
+
# @param name [String] The function name
|
26
|
+
# @param type [Symbol] The type of function. Valid types are
|
27
|
+
# `:http`, `:event`, and `:cloud_event`.
|
28
|
+
# @param block [Proc] The function code as a proc
|
29
|
+
#
|
30
|
+
def initialize name, type, &block
|
31
|
+
@name = name
|
32
|
+
@type = type
|
33
|
+
@block = block
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# @return [String] The function name
|
38
|
+
#
|
39
|
+
attr_reader :name
|
40
|
+
|
41
|
+
##
|
42
|
+
# @return [Symbol] The function type
|
43
|
+
#
|
44
|
+
attr_reader :type
|
45
|
+
|
46
|
+
##
|
47
|
+
# @return [Proc] The function code as a proc
|
48
|
+
#
|
49
|
+
attr_reader :block
|
50
|
+
|
51
|
+
##
|
52
|
+
# Call the function. You must pass an argument appropriate to the type
|
53
|
+
# of function.
|
54
|
+
#
|
55
|
+
# * A `:http` type function takes a `Rack::Request` argument, and returns
|
56
|
+
# a Rack response type. See {FunctionsFramework::Registry.add_http}.
|
57
|
+
# * A `:event` or `:cloud_event` type function takes a
|
58
|
+
# {FunctionsFramework::CloudEvents::Event} argument, and does not
|
59
|
+
# return a value. See {FunctionsFramework::Registry.add_cloud_event}.
|
60
|
+
# Note that for an `:event` type function, the passed event argument is
|
61
|
+
# split into two arguments when passed to the underlying block.
|
62
|
+
#
|
63
|
+
# @param argument [Rack::Request,FunctionsFramework::CloudEvents::Event]
|
64
|
+
# @return [Object]
|
65
|
+
#
|
66
|
+
def call argument
|
67
|
+
case type
|
68
|
+
when :event
|
69
|
+
block.call argument.data, argument
|
70
|
+
else
|
71
|
+
block.call argument
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|