momento 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.
@@ -0,0 +1,80 @@
1
+ require 'grpc'
2
+ require 'momento/cacheclient_pb'
3
+
4
+ module Momento
5
+ # Responses specific to get.
6
+ class GetResponse < Response
7
+ class << self
8
+ # Build a Momento::GetResponse from a block of code
9
+ # which returns a Momento::ControlClient::GetResponse.
10
+ #
11
+ # @return [Momento::GetResponse]
12
+ # @raise [StandardError] when the exception is not recognized.
13
+ # @raise [TypeError] when the response is not recognized.
14
+ def from_block
15
+ response = yield
16
+ rescue GRPC::BadStatus => e
17
+ Error.new(grpc_exception: e)
18
+ else
19
+ from_response(response)
20
+ end
21
+
22
+ private
23
+
24
+ def from_response(response)
25
+ raise TypeError unless response.is_a?(Momento::CacheClient::GetResponse)
26
+
27
+ case response.result
28
+ when :Hit
29
+ Hit.new(grpc_response: response)
30
+ when :Miss
31
+ Miss.new
32
+ else
33
+ raise "Unknown get result: #{response.result}"
34
+ end
35
+ end
36
+ end
37
+
38
+ def hit?
39
+ false
40
+ end
41
+
42
+ def miss?
43
+ false
44
+ end
45
+
46
+ # Successfully got an item from the cache.
47
+ class Hit < GetResponse
48
+ # rubocop:disable Lint/MissingSuper
49
+ def initialize(grpc_response:)
50
+ @grpc_response = grpc_response
51
+ end
52
+ # rubocop:enable Lint/MissingSuper
53
+
54
+ def hit?
55
+ true
56
+ end
57
+
58
+ # @return [String] the value from the cache
59
+ def value
60
+ @grpc_response.cache_body
61
+ end
62
+
63
+ def to_s
64
+ value
65
+ end
66
+ end
67
+
68
+ # The key had no value stored in the cache.
69
+ class Miss < GetResponse
70
+ def miss?
71
+ true
72
+ end
73
+ end
74
+
75
+ # There was a problem getting the value from the cache.
76
+ class Error < GetResponse
77
+ include Momento::Response::Error
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,53 @@
1
+ require 'grpc'
2
+ require 'momento/controlclient_pb'
3
+
4
+ module Momento
5
+ # Responses specific to list_caches.
6
+ class ListCachesResponse < Response
7
+ # Build a Momento::ListCachesResponse from a block of code
8
+ # which returns a Momento::ControlClient::ListCachesResponse.
9
+ #
10
+ # @return [Momento::ListCachesResponse]
11
+ # @raise [StandardError] when the exception is not recognized.
12
+ # @raise [TypeError] when the response is not recognized.
13
+ def self.from_block
14
+ response = yield
15
+ rescue GRPC::BadStatus => e
16
+ Error.new(grpc_exception: e)
17
+ else
18
+ raise TypeError unless response.is_a?(Momento::ControlClient::ListCachesResponse)
19
+
20
+ return Success.new(grpc_response: response)
21
+ end
22
+
23
+ def success?
24
+ false
25
+ end
26
+
27
+ # A Momento resposne with a page of caches.
28
+ class Success < ListCachesResponse
29
+ # rubocop:disable Lint/MissingSuper
30
+ def initialize(grpc_response:)
31
+ @grpc_response = grpc_response
32
+ end
33
+ # rubocop:enable Lint/MissingSuper
34
+
35
+ def success?
36
+ true
37
+ end
38
+
39
+ def cache_names
40
+ @grpc_response.cache.map(&:cache_name)
41
+ end
42
+
43
+ def next_token
44
+ @grpc_response.next_token
45
+ end
46
+ end
47
+
48
+ # There was an error listing the caches.
49
+ class Error < ListCachesResponse
50
+ include ::Momento::Response::Error
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,16 @@
1
+ module Momento
2
+ class Response
3
+ # A module for responses which contain errors.
4
+ module Error
5
+ attr_accessor :grpc_exception
6
+
7
+ def initialize(grpc_exception:)
8
+ @grpc_exception = grpc_exception
9
+ end
10
+
11
+ def error?
12
+ true
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ require 'grpc'
2
+ require_relative 'response/error'
3
+ require_relative 'create_cache_response'
4
+ require_relative 'delete_response'
5
+ require_relative 'delete_cache_response'
6
+ require_relative 'get_response'
7
+ require_relative 'list_caches_response'
8
+ require_relative 'set_response'
9
+
10
+ module Momento
11
+ # A superclass for all Momento responses.
12
+ class Response
13
+ def error?
14
+ false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ require 'grpc'
2
+ require 'momento/cacheclient_pb'
3
+
4
+ module Momento
5
+ # Responses specific to set.
6
+ class SetResponse < Response
7
+ # Build a Momento::SetResponse from a block of code
8
+ # which returns a Momento::ControlClient::SetResponse.
9
+ #
10
+ # @return [Momento::SetResponse]
11
+ # @raise [StandardError] when the exception is not recognized.
12
+ # @raise [TypeError] when the response is not recognized.
13
+ def self.from_block
14
+ response = yield
15
+ rescue GRPC::BadStatus => e
16
+ Error.new(grpc_exception: e)
17
+ else
18
+ raise TypeError unless response.is_a?(Momento::CacheClient::SetResponse)
19
+
20
+ Success.new
21
+ end
22
+
23
+ def success?
24
+ false
25
+ end
26
+
27
+ # The item was set.
28
+ class Success < SetResponse
29
+ def success?
30
+ true
31
+ end
32
+ end
33
+
34
+ # There was an error setting the item.
35
+ class Error < SetResponse
36
+ include Momento::Response::Error
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,204 @@
1
+ require 'jwt'
2
+ require 'momento/cacheclient_services_pb'
3
+ require 'momento/controlclient_services_pb'
4
+ require 'momento/response'
5
+
6
+ module Momento
7
+ # A simple client for Momento.
8
+ #
9
+ # @example
10
+ # client = Momento::SimpleCacheClient.new(
11
+ # auth_token: jwt,
12
+ # default_ttl: 10_000
13
+ # )
14
+ #
15
+ # response = client.get("my_cache", "key")
16
+ # if response.hit?
17
+ # puts "We got #{response}"
18
+ # elsif response.miss?
19
+ # puts "It's not in the cache"
20
+ # elsif response.error?
21
+ # puts "The front fell off."
22
+ # end
23
+ class SimpleCacheClient
24
+ VERSION = Momento::VERSION
25
+ CACHE_CLIENT_STUB_CLASS = CacheClient::Scs::Stub
26
+ CONTROL_CLIENT_STUB_CLASS = ControlClient::ScsControl::Stub
27
+
28
+ # The default time to live, in milliseconds.
29
+ attr_accessor :default_ttl
30
+
31
+ # @param auth_token [String] the JWT for your Momento account
32
+ # @param default_ttl [Integer]
33
+ def initialize(auth_token:, default_ttl:)
34
+ @auth_token = auth_token
35
+ @default_ttl = default_ttl
36
+ load_endpoints_from_token
37
+ end
38
+
39
+ # Get a value in a cache.
40
+ #
41
+ # Momento only stores bytes; the returned value will be encoded as ASCII-8BIT.
42
+ #
43
+ # @param cache_name [String]
44
+ # @param key [String] must only contain ASCII characters
45
+ # @return [Momento::GetResponse]
46
+ def get(cache_name, key)
47
+ return GetResponse.from_block do
48
+ cache_stub.get(
49
+ CacheClient::GetRequest.new(cache_key: to_bytes(key)),
50
+ metadata: { cache: cache_name }
51
+ )
52
+ end
53
+ end
54
+
55
+ # Set a value in a cache.
56
+ #
57
+ # If ttl is not set, it will use the default_ttl.
58
+ #
59
+ # @param cache_name [String]
60
+ # @param key [String] must only contain ASCII characters
61
+ # @param value [String] the value to cache
62
+ # @param ttl [Integer] time to live, in milliseconds.
63
+ # @return [Momento::SetResponse]
64
+ def set(cache_name, key, value, ttl: default_ttl)
65
+ return SetResponse.from_block do
66
+ req = CacheClient::SetRequest.new(
67
+ cache_key: to_bytes(key),
68
+ cache_body: to_bytes(value),
69
+ ttl_milliseconds: ttl
70
+ )
71
+
72
+ cache_stub.set(req, metadata: { cache: cache_name })
73
+ end
74
+ end
75
+
76
+ # Delete a key in a cache.
77
+ #
78
+ # @param cache_name [String]
79
+ # @param key [String] must only contain ASCII characters
80
+ # @return [Momento::DeleteResponse]
81
+ def delete(cache_name, key)
82
+ return DeleteResponse.from_block do
83
+ cache_stub.delete(
84
+ CacheClient::DeleteRequest.new(cache_key: to_bytes(key)),
85
+ metadata: { cache: cache_name }
86
+ )
87
+ end
88
+ end
89
+
90
+ # Create a new Momento cache.
91
+ #
92
+ # @param name [String] the name of the cache to create.
93
+ # @return [Momento::CreateCacheResponse] the response from Momento.
94
+ def create_cache(name)
95
+ return CreateCacheResponse.from_block do
96
+ control_stub.create_cache(
97
+ ControlClient::CreateCacheRequest.new(cache_name: name)
98
+ )
99
+ end
100
+ end
101
+
102
+ # Delete an existing Momento cache.
103
+ #
104
+ # @param name [String] the name of the cache to delete.
105
+ # @return [Momento::DeleteCacheResponse] the response from Momento.
106
+ def delete_cache(name)
107
+ return DeleteCacheResponse.from_block do
108
+ control_stub.delete_cache(
109
+ ControlClient::DeleteCacheRequest.new(cache_name: name)
110
+ )
111
+ end
112
+ end
113
+
114
+ # List a page of your caches.
115
+ #
116
+ # The next_token indicates which page to fetch.
117
+ # If nil or "" it will fetch the first page. Default is to fetch the first page.
118
+ #
119
+ # @params next_token [String, nil] the token of the page to request
120
+ # @return [Momento::ListCachesResponse]
121
+ def list_caches(next_token: "")
122
+ return ListCachesResponse.from_block do
123
+ control_stub.list_caches(
124
+ ControlClient::ListCachesRequest.new(next_token: next_token)
125
+ )
126
+ end
127
+ end
128
+
129
+ # Lists the names of all your caches.
130
+ #
131
+ # @return [Enumerator::Lazy<String>] the cache names
132
+ # @raise [GRPC::BadStatus]
133
+ # rubocop:disable Metrics/MethodLength
134
+ def caches
135
+ Enumerator.new do |yielder|
136
+ next_token = ""
137
+
138
+ loop do
139
+ response = list_caches(next_token: next_token)
140
+ raise response.grpc_exception if response.is_a? Momento::Response::Error
141
+
142
+ response.cache_names.each do |name|
143
+ yielder << name
144
+ end
145
+
146
+ break if response.next_token == ''
147
+
148
+ next_token = response.next_token
149
+ end
150
+ end.lazy
151
+ end
152
+ # rubocop:enable Metrics/MethodLength
153
+
154
+ private
155
+
156
+ def cache_stub
157
+ @cache_stub ||= CACHE_CLIENT_STUB_CLASS.new(@cache_endpoint, combined_credentials)
158
+ end
159
+
160
+ def control_stub
161
+ @control_stub ||= CONTROL_CLIENT_STUB_CLASS.new(@control_endpoint, combined_credentials)
162
+ end
163
+
164
+ def combined_credentials
165
+ @combined_credentials ||= make_combined_credentials
166
+ end
167
+
168
+ def load_endpoints_from_token
169
+ claim = JWT.decode(@auth_token, nil, false).first
170
+
171
+ @control_endpoint = claim["cp"]
172
+ @cache_endpoint = claim["c"]
173
+ end
174
+
175
+ def make_combined_credentials
176
+ # :nocov:
177
+ auth_proc = proc do
178
+ { authorization: @auth_token, agent: "ruby:#{VERSION}" }
179
+ end
180
+ # :nocov:
181
+
182
+ call_creds = GRPC::Core::CallCredentials.new(auth_proc)
183
+
184
+ return GRPC::Core::ChannelCredentials.new.compose(call_creds)
185
+ end
186
+
187
+ # Ruby uses String for bytes. GRPC wants a String encoded as ASCII.
188
+ # GRPC will re-encode a String, but treats it as characters; GRPC will
189
+ # raise if you pass a String with non-ASCII characters.
190
+ # So we do the re-encoding ourselves in a way that treats the String as
191
+ # bytes and will not raise. The data is not changed.
192
+ #
193
+ # A duplicate String is returned, but since Ruby is copy-on-write it
194
+ # does not copy the data.
195
+ #
196
+ # @param string [String] the string to make safe for GRPC bytes
197
+ # @return [String] a duplicate safe to use as GRPC bytes
198
+ def to_bytes(string)
199
+ # dup in case the value is frozen and to avoid changing the value's encoding
200
+ # for the caller.
201
+ return string.dup.force_encoding(Encoding::ASCII_8BIT)
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Momento
4
+ VERSION = "0.1.0"
5
+ end
data/lib/momento.rb ADDED
@@ -0,0 +1,6 @@
1
+ require_relative 'momento/version'
2
+ require_relative 'momento/simple_cache_client'
3
+
4
+ # Top level namespace for all Momento code.
5
+ module Momento
6
+ end
data/momento.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/momento/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "momento"
7
+ spec.version = Momento::VERSION
8
+ spec.authors = ["Momento"]
9
+ spec.email = ["eng-deveco@momentohq.com"]
10
+
11
+ spec.summary = "Client for Momento Serverless Cache"
12
+ spec.description = "Momento is a fast, simple, pay-as-you-go caching solution."
13
+ spec.homepage = "https://github.com/momentohq/client-sdk-ruby"
14
+ spec.required_ruby_version = ">= 2.7.0"
15
+ spec.license = "Apache-2.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata['rubygems_mfa_required'] = 'true'
19
+ spec.metadata["source_code_uri"] = "https://github.com/momentohq/client-sdk-ruby"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency 'bundler', "~> 2.3"
33
+ spec.add_development_dependency 'factory_bot', "~> 6.2.1"
34
+ spec.add_development_dependency 'faker', "~> 3.0"
35
+ spec.add_development_dependency "rspec", "~> 3.12"
36
+ spec.add_development_dependency "rubocop", "~> 3.18"
37
+ spec.add_development_dependency 'rubocop-performance', '~> 1.15'
38
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6.0'
39
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.15'
40
+ spec.add_development_dependency 'simplecov', '~> 0.21'
41
+
42
+ spec.add_dependency "grpc", '~> 1'
43
+ spec.add_dependency 'jwt', '~> 2'
44
+ end
@@ -0,0 +1,6 @@
1
+ module Momento
2
+ module Client
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,229 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: momento
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Momento
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: factory_bot
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 6.2.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 6.2.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: faker
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.18'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.18'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-performance
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.15'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.15'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.6.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.6.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.15'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.15'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.21'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.21'
139
+ - !ruby/object:Gem::Dependency
140
+ name: grpc
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1'
153
+ - !ruby/object:Gem::Dependency
154
+ name: jwt
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2'
167
+ description: Momento is a fast, simple, pay-as-you-go caching solution.
168
+ email:
169
+ - eng-deveco@momentohq.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".editorconfig"
175
+ - ".rspec"
176
+ - ".rubocop.yml"
177
+ - ".ruby-version"
178
+ - CONTRIBUTING.md
179
+ - Gemfile
180
+ - Gemfile.lock
181
+ - LICENSE.txt
182
+ - README.md
183
+ - Rakefile
184
+ - examples/basic.rb
185
+ - lib/README-generating-pb.txt
186
+ - lib/momento.rb
187
+ - lib/momento/cacheclient_pb.rb
188
+ - lib/momento/cacheclient_services_pb.rb
189
+ - lib/momento/controlclient_pb.rb
190
+ - lib/momento/controlclient_services_pb.rb
191
+ - lib/momento/create_cache_response.rb
192
+ - lib/momento/delete_cache_response.rb
193
+ - lib/momento/delete_response.rb
194
+ - lib/momento/get_response.rb
195
+ - lib/momento/list_caches_response.rb
196
+ - lib/momento/response.rb
197
+ - lib/momento/response/error.rb
198
+ - lib/momento/set_response.rb
199
+ - lib/momento/simple_cache_client.rb
200
+ - lib/momento/version.rb
201
+ - momento.gemspec
202
+ - sig/momento/client.rbs
203
+ homepage: https://github.com/momentohq/client-sdk-ruby
204
+ licenses:
205
+ - Apache-2.0
206
+ metadata:
207
+ homepage_uri: https://github.com/momentohq/client-sdk-ruby
208
+ rubygems_mfa_required: 'true'
209
+ source_code_uri: https://github.com/momentohq/client-sdk-ruby
210
+ post_install_message:
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ version: 2.7.0
219
+ required_rubygems_version: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ requirements: []
225
+ rubygems_version: 3.3.7
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: Client for Momento Serverless Cache
229
+ test_files: []