functions_framework 0.3.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,22 +16,59 @@ module FunctionsFramework
16
16
  ##
17
17
  # Representation of a function.
18
18
  #
19
- # A function has a name, a type, and a code definition.
19
+ # A function has a name, a type, and an implementation.
20
+ #
21
+ # The implementation in general is an object that responds to the `call`
22
+ # method. For a function of type `:http`, the `call` method takes a single
23
+ # `Rack::Request` argument and returns one of various HTTP response types.
24
+ # See {FunctionsFramework::Registry.add_http}. For a function of type
25
+ # `:cloud_event`, the `call` method takes a single
26
+ # [CloudEvent](https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event)
27
+ # argument, and does not return a value.
28
+ # See {FunctionsFramework::Registry.add_cloud_event}.
29
+ #
30
+ # If a callable object is provided directly, its `call` method is invoked for
31
+ # every function execution. Note that this means it may be called multiple
32
+ # times concurrently in separate threads.
33
+ #
34
+ # Alternately, the implementation may be provided as a class that should be
35
+ # instantiated to produce a callable object. If a class is provided, it should
36
+ # either subclass {FunctionsFramework::Function::CallBase} or respond to the
37
+ # same constructor interface, i.e. accepting arbitrary keyword arguments. A
38
+ # separate callable object will be instantiated from this class for every
39
+ # function invocation, so each instance will be used for only one invocation.
40
+ #
41
+ # Finally, an implementation can be provided as a block. If a block is
42
+ # provided, it will be recast as a `call` method in an anonymous subclass of
43
+ # {FunctionsFramework::Function::CallBase}. Thus, providing a block is really
44
+ # just syntactic sugar for providing a class. (This means, for example, that
45
+ # the `return` keyword will work within the block because it is treated as a
46
+ # method.)
20
47
  #
21
48
  class Function
22
49
  ##
23
50
  # Create a new function definition.
24
51
  #
25
52
  # @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
53
+ # @param type [Symbol] The type of function. Valid types are `:http` and
54
+ # `:cloud_event`.
55
+ # @param callable [Class,#call] A callable object or class.
56
+ # @param block [Proc] The function code as a block.
29
57
  #
30
- def initialize name, type, &block
58
+ def initialize name, type, callable = nil, &block
31
59
  @name = name
32
60
  @type = type
33
- @execution_context_class = Class.new do
34
- define_method :call, &block
61
+ @callable = @callable_class = nil
62
+ if callable.respond_to? :call
63
+ @callable = callable
64
+ elsif callable.is_a? ::Class
65
+ @callable_class = callable
66
+ elsif block_given?
67
+ @callable_class = ::Class.new CallBase do
68
+ define_method :call, &block
69
+ end
70
+ else
71
+ raise ::ArgumentError, "No callable given for function"
35
72
  end
36
73
  end
37
74
 
@@ -46,26 +83,48 @@ module FunctionsFramework
46
83
  attr_reader :type
47
84
 
48
85
  ##
49
- # Call the function. You must pass an argument appropriate to the type
50
- # of function.
86
+ # Get a callable for performing a function invocation. This will either
87
+ # return the singleton callable object, or instantiate a new callable from
88
+ # the configured class.
51
89
  #
52
- # * A `:http` type function takes a `Rack::Request` argument, and returns
53
- # a Rack response type. See {FunctionsFramework::Registry.add_http}.
54
- # * A `:cloud_event` type function takes a
55
- # {FunctionsFramework::CloudEvents::Event} argument, and does not
56
- # return a value. See {FunctionsFramework::Registry.add_cloud_event}.
90
+ # @param logger [::Logger] The logger for use by function executions. This
91
+ # may or may not be used by the callable.
92
+ # @return [#call]
57
93
  #
58
- # @param argument [Rack::Request,FunctionsFramework::CloudEvents::Event]
59
- # @return [Object]
94
+ def new_call logger: nil
95
+ return @callable unless @callable.nil?
96
+ logger ||= FunctionsFramework.logger
97
+ @callable_class.new logger: logger, function_name: name, function_type: type
98
+ end
99
+
100
+ ##
101
+ # A base class for a callable object that provides calling context.
60
102
  #
61
- def call argument
62
- execution_context = @execution_context_class.new
63
- case type
64
- when :event
65
- execution_context.call argument.data, argument
66
- else
67
- execution_context.call argument
103
+ # An object of this class is `self` while a function block is running.
104
+ #
105
+ class CallBase
106
+ ##
107
+ # Create a callable object with the given context.
108
+ #
109
+ # @param context [keywords] A set of context arguments. See {#context} for
110
+ # a list of keys that will generally be passed in. However,
111
+ # implementations should be prepared to accept any abritrary keys.
112
+ #
113
+ def initialize **context
114
+ @context = context
68
115
  end
116
+
117
+ ##
118
+ # A keyed hash of context information. Common context keys include:
119
+ #
120
+ # * **:logger** (`Logger`) A logger for use by this function call.
121
+ # * **:function_name** (`String`) The name of the running function.
122
+ # * **:function_type** (`Symbol`) The type of the running function,
123
+ # either `:http` or `:cloud_event`.
124
+ #
125
+ # @return [Hash]
126
+ #
127
+ attr_reader :context
69
128
  end
70
129
  end
71
130
  end
@@ -23,19 +23,17 @@ module FunctionsFramework
23
23
  # Decode an event from the given Rack environment hash.
24
24
  #
25
25
  # @param env [Hash] The Rack environment
26
- # @return [FunctionsFramework::CloudEvents::Event] if the request could
27
- # be converted
26
+ # @return [::CloudEvents::Event] if the request could be converted
28
27
  # @return [nil] if the event format was not recognized.
29
28
  #
30
29
  def decode_rack_env env
31
- content_type = CloudEvents::ContentType.new env["CONTENT_TYPE"]
32
- return nil unless content_type.media_type == "application" && content_type.subtype_prefix == "json"
30
+ content_type = ::CloudEvents::ContentType.new env["CONTENT_TYPE"]
31
+ return nil unless content_type.media_type == "application" && content_type.subtype_base == "json"
33
32
  input = read_input_json env["rack.input"], content_type.charset
34
33
  return nil unless input
35
- raw_context = input["context"] || input
36
- context = normalized_context raw_context
34
+ context = normalized_context input
37
35
  return nil unless context
38
- construct_cloud_event context, input["data"]
36
+ construct_cloud_event context, input["data"], content_type.charset
39
37
  end
40
38
 
41
39
  private
@@ -50,27 +48,27 @@ module FunctionsFramework
50
48
  nil
51
49
  end
52
50
 
53
- def normalized_context raw_context
54
- id = raw_context["eventId"]
55
- return nil unless id
56
- timestamp = raw_context["timestamp"]
57
- return nil unless timestamp
58
- type = raw_context["eventType"]
59
- return nil unless type
60
- service, resource = analyze_resource raw_context["resource"], type
61
- return nil unless service && resource
51
+ def normalized_context input
52
+ raw_context = input["context"]
53
+ id = raw_context&.[]("eventId") || input["eventId"]
54
+ timestamp = raw_context&.[]("timestamp") || input["timestamp"]
55
+ type = raw_context&.[]("eventType") || input["eventType"]
56
+ service, resource = analyze_resource raw_context&.[]("resource") || input["resource"]
57
+ service ||= service_from_type type
58
+ return nil unless id && timestamp && type && service && resource
62
59
  { id: id, timestamp: timestamp, type: type, service: service, resource: resource }
63
60
  end
64
61
 
65
- def analyze_resource raw_resource, type
62
+ def analyze_resource raw_resource
63
+ service = resource = nil
66
64
  case raw_resource
67
65
  when ::Hash
68
- [raw_resource["service"], raw_resource["name"]]
66
+ service = raw_resource["service"]
67
+ resource = raw_resource["name"]
69
68
  when ::String
70
- [service_from_type(type), raw_resource]
71
- else
72
- [nil, nil]
69
+ resource = raw_resource
73
70
  end
71
+ [service, resource]
74
72
  end
75
73
 
76
74
  def service_from_type type
@@ -80,19 +78,20 @@ module FunctionsFramework
80
78
  nil
81
79
  end
82
80
 
83
- def construct_cloud_event context, data
81
+ def construct_cloud_event context, data, charset
84
82
  source, subject = convert_source context[:service], context[:resource]
85
83
  type = LEGACY_TYPE_TO_CE_TYPE[context[:type]]
86
84
  return nil unless type && source
87
85
  ce_data = convert_data context[:service], data
88
- CloudEvents::Event.new id: context[:id],
89
- source: source,
90
- type: type,
91
- spec_version: "1.0",
92
- data_content_type: "application/json",
93
- data: ce_data,
94
- subject: subject,
95
- time: context[:timestamp]
86
+ content_type = "application/json; charset=#{charset}"
87
+ ::CloudEvents::Event.new id: context[:id],
88
+ source: source,
89
+ type: type,
90
+ spec_version: "1.0",
91
+ data_content_type: content_type,
92
+ data: ce_data,
93
+ subject: subject,
94
+ time: context[:timestamp]
96
95
  end
97
96
 
98
97
  def convert_source service, resource
@@ -75,27 +75,13 @@ module FunctionsFramework
75
75
  self
76
76
  end
77
77
 
78
- ##
79
- # This is an obsolete interface that defines an event function taking two
80
- # arguments (data and context) rather than one.
81
- #
82
- # @deprecated Use {Registry#add_cloud_event} instead.
83
- #
84
- def add_event name, &block
85
- name = name.to_s
86
- synchronize do
87
- raise ::ArgumentError, "Function already defined: #{name}" if @functions.key? name
88
- @functions[name] = Function.new name, :event, &block
89
- end
90
- self
91
- end
92
-
93
78
  ##
94
79
  # Add a CloudEvent function to the registry.
95
80
  #
96
81
  # You must provide a name for the function, and a block that implemets the
97
82
  # function. The block should take _one_ argument: the event object of type
98
- # {FunctionsFramework::CloudEvents::Event}. Any return value is ignored.
83
+ # [`CloudEvents::Event`](https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event).
84
+ # Any return value is ignored.
99
85
  #
100
86
  # @param name [String] The function name
101
87
  # @param block [Proc] The function code as a proc
@@ -47,7 +47,7 @@ module FunctionsFramework
47
47
  case function.type
48
48
  when :http
49
49
  HttpApp.new function, @config
50
- when :event, :cloud_event
50
+ when :cloud_event
51
51
  EventApp.new function, @config
52
52
  else
53
53
  raise "Unrecognized function type: #{function.type}"
@@ -149,8 +149,12 @@ module FunctionsFramework
149
149
  ::Signal.trap "SIGINT" do
150
150
  Server.signal_enqueue "SIGINT", @config.logger, @server
151
151
  end
152
- ::Signal.trap "SIGHUP" do
153
- Server.signal_enqueue "SIGHUP", @config.logger, @server
152
+ begin
153
+ ::Signal.trap "SIGHUP" do
154
+ Server.signal_enqueue "SIGHUP", @config.logger, @server
155
+ end
156
+ rescue ::ArgumentError # rubocop:disable Lint/HandleExceptions
157
+ # Not available on all systems
154
158
  end
155
159
  @signals_installed = true
156
160
  end
@@ -340,7 +344,7 @@ module FunctionsFramework
340
344
  string_response response, "text/plain", 200
341
345
  when ::Hash
342
346
  string_response ::JSON.dump(response), "application/json", 200
343
- when CloudEvents::CloudEventsError
347
+ when ::CloudEvents::CloudEventsError
344
348
  cloud_events_error_response response
345
349
  when ::StandardError
346
350
  error_response "#{response.class}: #{response.message}\n#{response.backtrace}\n"
@@ -384,10 +388,11 @@ module FunctionsFramework
384
388
  return notfound_response if excluded_path? env
385
389
  response =
386
390
  begin
387
- logger = env["rack.logger"] = @config.logger
391
+ logger = env["rack.logger"] ||= @config.logger
388
392
  request = ::Rack::Request.new env
389
393
  logger.info "FunctionsFramework: Handling HTTP #{request.request_method} request"
390
- @function.call request
394
+ calling_context = @function.new_call logger: logger
395
+ calling_context.call request
391
396
  rescue ::StandardError => e
392
397
  e
393
398
  end
@@ -400,21 +405,21 @@ module FunctionsFramework
400
405
  def initialize function, config
401
406
  super config
402
407
  @function = function
403
- @cloud_events = CloudEvents::HttpBinding.default
408
+ @cloud_events = ::CloudEvents::HttpBinding.default
404
409
  @legacy_events = LegacyEventConverter.new
405
410
  end
406
411
 
407
412
  def call env
408
413
  return notfound_response if excluded_path? env
409
- logger = env["rack.logger"] = @config.logger
414
+ logger = env["rack.logger"] ||= @config.logger
410
415
  event = decode_event env
411
416
  response =
412
417
  case event
413
- when CloudEvents::Event
418
+ when ::CloudEvents::Event
414
419
  handle_cloud_event event, logger
415
420
  when ::Array
416
- CloudEvents::HttpContentError.new "Batched CloudEvents are not supported"
417
- when CloudEvents::CloudEventsError
421
+ ::CloudEvents::HttpContentError.new "Batched CloudEvents are not supported"
422
+ when ::CloudEvents::CloudEventsError
418
423
  event
419
424
  else
420
425
  raise "Unexpected event type: #{event.class}"
@@ -427,14 +432,15 @@ module FunctionsFramework
427
432
  def decode_event env
428
433
  @cloud_events.decode_rack_env(env) ||
429
434
  @legacy_events.decode_rack_env(env) ||
430
- raise(CloudEvents::HttpContentError, "Unrecognized event format")
431
- rescue CloudEvents::CloudEventsError => e
435
+ raise(::CloudEvents::HttpContentError, "Unrecognized event format")
436
+ rescue ::CloudEvents::CloudEventsError => e
432
437
  e
433
438
  end
434
439
 
435
440
  def handle_cloud_event event, logger
436
441
  logger.info "FunctionsFramework: Handling CloudEvent"
437
- @function.call event
442
+ calling_context = @function.new_call logger: logger
443
+ calling_context.call event
438
444
  "ok"
439
445
  rescue ::StandardError => e
440
446
  e
@@ -87,7 +87,7 @@ module FunctionsFramework
87
87
  function = ::FunctionsFramework.global_registry[name]
88
88
  case function&.type
89
89
  when :http
90
- Testing.interpret_response { function.call request }
90
+ Testing.interpret_response { function.new_call.call request }
91
91
  when nil
92
92
  raise "Unknown function name #{name}"
93
93
  else
@@ -97,17 +97,17 @@ module FunctionsFramework
97
97
 
98
98
  ##
99
99
  # Call the given event function for testing. The underlying function must
100
- # be of type `:event` or `:cloud_event`.
100
+ # be of type :cloud_event`.
101
101
  #
102
102
  # @param name [String] The name of the function to call
103
- # @param event [FunctionsFramework::CloudEvets::Event] The event to send
103
+ # @param event [::CloudEvents::Event] The event to send
104
104
  # @return [nil]
105
105
  #
106
106
  def call_event name, event
107
107
  function = ::FunctionsFramework.global_registry[name]
108
108
  case function&.type
109
- when :event, :cloud_event
110
- function.call event
109
+ when :cloud_event
110
+ function.new_call.call event
111
111
  nil
112
112
  when nil
113
113
  raise "Unknown function name #{name}"
@@ -174,23 +174,35 @@ module FunctionsFramework
174
174
  # @param source [String,URI] Event source (optional)
175
175
  # @param type [String] Event type (optional)
176
176
  # @param spec_version [String] Spec version (optional)
177
- # @param data_content_type [String,FunctionsFramework::CloudEvents::ContentType]
177
+ # @param data_content_type [String,::CloudEvents::ContentType]
178
178
  # Content type for the data (optional)
179
179
  # @param data_schema [String,URI] Data schema (optional)
180
180
  # @param subject [String] Subject (optional)
181
181
  # @param time [String,DateTime] Event timestamp (optional)
182
- # @return [FunctionsFramework::CloudEvents::Event]
182
+ # @return [::CloudEvents::Event]
183
183
  #
184
184
  def make_cloud_event data,
185
- id: nil, source: nil, type: nil, spec_version: nil,
186
- data_content_type: nil, data_schema: nil, subject: nil, time: nil
185
+ id: nil,
186
+ source: nil,
187
+ type: nil,
188
+ spec_version: nil,
189
+ data_content_type: nil,
190
+ data_schema: nil,
191
+ subject: nil,
192
+ time: nil
187
193
  id ||= "random-id-#{rand 100_000_000}"
188
194
  source ||= "functions-framework-testing"
189
195
  type ||= "com.example.test"
190
196
  spec_version ||= "1.0"
191
- CloudEvents::Event.new id: id, source: source, type: type, spec_version: spec_version,
192
- data_content_type: data_content_type, data_schema: data_schema,
193
- subject: subject, time: time, data: data
197
+ ::CloudEvents::Event.new id: id,
198
+ source: source,
199
+ type: type,
200
+ spec_version: spec_version,
201
+ data_content_type: data_content_type,
202
+ data_schema: data_schema,
203
+ subject: subject,
204
+ time: time,
205
+ data: data
194
206
  end
195
207
 
196
208
  extend self
@@ -17,5 +17,5 @@ module FunctionsFramework
17
17
  # Version of the Ruby Functions Framework
18
18
  # @return [String]
19
19
  #
20
- VERSION = "0.3.1".freeze
20
+ VERSION = "0.5.2".freeze
21
21
  end
metadata CHANGED
@@ -1,142 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functions_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-27 00:00:00.000000000 Z
11
+ date: 2020-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: puma
14
+ name: cloud_events
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '4.3'
19
+ version: '0.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '4.3'
26
+ version: '0.1'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rack
28
+ name: puma
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.1'
33
+ version: '4.3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.1'
41
- - !ruby/object:Gem::Dependency
42
- name: google-style
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 1.24.0
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 1.24.0
55
- - !ruby/object:Gem::Dependency
56
- name: minitest
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '5.13'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '5.13'
69
- - !ruby/object:Gem::Dependency
70
- name: minitest-focus
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.1'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.1'
83
- - !ruby/object:Gem::Dependency
84
- name: minitest-rg
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '5.2'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '5.2'
97
- - !ruby/object:Gem::Dependency
98
- name: redcarpet
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '3.5'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '3.5'
111
- - !ruby/object:Gem::Dependency
112
- name: toys
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.10.0
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.10.0
40
+ version: '4.3'
125
41
  - !ruby/object:Gem::Dependency
126
- name: yard
42
+ name: rack
127
43
  requirement: !ruby/object:Gem::Requirement
128
44
  requirements:
129
45
  - - "~>"
130
46
  - !ruby/object:Gem::Version
131
- version: 0.9.24
132
- type: :development
47
+ version: '2.1'
48
+ type: :runtime
133
49
  prerelease: false
134
50
  version_requirements: !ruby/object:Gem::Requirement
135
51
  requirements:
136
52
  - - "~>"
137
53
  - !ruby/object:Gem::Version
138
- version: 0.9.24
139
- description: The Functions Framework implementation for Ruby.
54
+ version: '2.1'
55
+ description: The Functions Framework is an open source framework for writing lightweight,
56
+ portable Ruby functions that run in a serverless environment. Functions written
57
+ to this Framework will run Google Cloud Google Cloud Functions, Google Cloud Run,
58
+ or any other Knative-based environment.
140
59
  email:
141
60
  - dazuma@google.com
142
61
  executables:
@@ -158,13 +77,6 @@ files:
158
77
  - docs/writing-functions.md
159
78
  - lib/functions_framework.rb
160
79
  - lib/functions_framework/cli.rb
161
- - lib/functions_framework/cloud_events.rb
162
- - lib/functions_framework/cloud_events/content_type.rb
163
- - lib/functions_framework/cloud_events/errors.rb
164
- - lib/functions_framework/cloud_events/event.rb
165
- - lib/functions_framework/cloud_events/event/v1.rb
166
- - lib/functions_framework/cloud_events/http_binding.rb
167
- - lib/functions_framework/cloud_events/json_format.rb
168
80
  - lib/functions_framework/function.rb
169
81
  - lib/functions_framework/legacy_event_converter.rb
170
82
  - lib/functions_framework/registry.rb
@@ -174,7 +86,11 @@ files:
174
86
  homepage: https://github.com/GoogleCloudPlatform/functions-framework-ruby
175
87
  licenses:
176
88
  - Apache-2.0
177
- metadata: {}
89
+ metadata:
90
+ changelog_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.5.2/file.CHANGELOG.html
91
+ source_code_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby
92
+ bug_tracker_uri: https://github.com/GoogleCloudPlatform/functions-framework-ruby/issues
93
+ documentation_uri: https://googlecloudplatform.github.io/functions-framework-ruby/v0.5.2
178
94
  post_install_message:
179
95
  rdoc_options: []
180
96
  require_paths:
@@ -190,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
106
  - !ruby/object:Gem::Version
191
107
  version: '0'
192
108
  requirements: []
193
- rubygems_version: 3.1.2
109
+ rubygems_version: 3.0.3
194
110
  signing_key:
195
111
  specification_version: 4
196
112
  summary: Functions Framework for Ruby