adadiamonds 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0a6bdae7ac7a99d8a70ee8800eec58b6692a35c63784cad85e75b835398857b6
4
+ data.tar.gz: 47f5cc02e53554e5326781a9645914403b4d47f0b8a464c4896459fccf2b43c1
5
+ SHA512:
6
+ metadata.gz: 669e2711d23848bf585a0a6b3f6f6e26f8f5114e4759b5f7cee63a185164c9731d83f8583b09c6796f630b9de11f69fc4a616bc6bd7a4b2b68c9043b99098a3e
7
+ data.tar.gz: 37e2e2ed149551590cfa04ae8cc62e4d6d8765c3633ae2f05490b111619064134449f640300297024da48bac9e72b1070746d3076d58b87f1a2e2e27ad66a0b2
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - First release: `AdaDiamonds::Client` with one method per endpoint (`diamonds`, `diamond`, `engagement_rings`, `engagement_ring`, `jewelry`, `jewelry_item`, `knowledge_base`, `article`, `showrooms`, `request_consultation`, `create_key`, `batch`, `ask`), generic `get`/`post`, `AdaDiamonds::Error`, and `last_rate_limit`.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ada Diamonds, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # adadiamonds
2
+
3
+ Official Ruby client for the [Ada Diamonds](https://www.adadiamonds.com) API: live lab grown diamond inventory, engagement ring settings, fine jewelry, showrooms, and the diamond buying guides.
4
+
5
+ Standard library only (`net/http`, `json`). Ruby 2.6 or newer.
6
+
7
+ - Documentation: https://www.adadiamonds.com/developers
8
+ - REST reference: https://www.adadiamonds.com/developers/api
9
+ - OpenAPI 3.1: https://www.adadiamonds.com/openapi.json
10
+ - MCP server (for tool use instead of HTTP): https://www.adadiamonds.com/mcp
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ gem install adadiamonds
16
+ ```
17
+
18
+ or in a Gemfile:
19
+
20
+ ```ruby
21
+ gem "adadiamonds"
22
+ ```
23
+
24
+ Reading the catalog needs no account and no API key (120 requests per minute). An API key raises that to 600 and unlocks the write endpoints. Every price is in US dollars.
25
+
26
+ ## Examples
27
+
28
+ ### Search live diamond inventory
29
+
30
+ ```ruby
31
+ require "adadiamonds"
32
+
33
+ client = AdaDiamonds::Client.new # anonymous
34
+ page = client.diamonds(shape: "Oval", min_carat: 1, max_price: 4000, sort: "price_asc")
35
+ page.each do |stone|
36
+ puts [stone["carat"], stone["shape"], stone["price"]].join(" ")
37
+ end
38
+ p client.last_rate_limit # #<struct limit=120, remaining=119, reset=58, policy="...">
39
+ ```
40
+
41
+ ### Quote a complete ring
42
+
43
+ An engagement ring is a setting plus a loose diamond, priced separately. Setting prices never include the center stone.
44
+
45
+ ```ruby
46
+ setting = client.engagement_rings(shape: "Oval", type: "Solitaire", limit: 1).first
47
+ stone = client.diamonds(shape: "Oval", min_carat: 1.5, max_carat: 1.6, sort: "price_asc", limit: 1).first
48
+ puts setting["priceFrom"] + stone["price"] # US dollars
49
+ ```
50
+
51
+ ### Authenticate and write
52
+
53
+ ```ruby
54
+ key = AdaDiamonds::Client.new.create_key("my-agent", env: "sandbox")
55
+ client = AdaDiamonds::Client.new(api_key: key["api_key"]) # 600 requests/min
56
+
57
+ begin
58
+ client.request_consultation(
59
+ { "email" => "test@example.com", "topic" => "engagement_ring" },
60
+ idempotency_key: "consult-42" # a retry cannot create two requests
61
+ )
62
+ rescue AdaDiamonds::Error => e
63
+ puts [e.status, e.code, e.description, e.retry_after].inspect
64
+ end
65
+ ```
66
+
67
+ Sandbox keys (`ada_test_*`) return well-formed responses and contact nobody.
68
+
69
+ ### Ask a question (NLWeb)
70
+
71
+ ```ruby
72
+ answer = client.ask("oval lab diamond engagement ring under $6,000")
73
+ ```
74
+
75
+ ### Anything else
76
+
77
+ Every method maps to one endpoint under `/api/v1`. For endpoints without a helper, `get` and `post` take a path relative to `/api/v1` (or absolute on the site) and return the decoded JSON:
78
+
79
+ ```ruby
80
+ bands = client.get("/jewelry", category: "wedding-bands")
81
+ ```
82
+
83
+ ## Methods
84
+
85
+ | Method | Endpoint |
86
+ | --- | --- |
87
+ | `diamonds`, `diamond` | `GET /api/v1/diamonds`, `GET /api/v1/diamonds/{id}` |
88
+ | `engagement_rings`, `engagement_ring` | `GET /api/v1/engagement-rings`, `.../{slug}` |
89
+ | `jewelry`, `jewelry_item` | `GET /api/v1/jewelry`, `.../{slug}` |
90
+ | `knowledge_base`, `article` | `GET /api/v1/knowledge-base`, `.../{slug}` |
91
+ | `showrooms` | `GET /api/v1/showrooms` |
92
+ | `request_consultation` | `POST /api/v1/consultations` |
93
+ | `create_key` | `POST /api/v1/keys` |
94
+ | `batch` | `POST /api/v1/batch` (up to 20 GETs in one round trip) |
95
+ | `ask` | `GET /ask` (NLWeb) |
96
+
97
+ List methods return an `AdaDiamonds::Page` (`data`, `pagination`, `total`, `has_more?`, and `Enumerable`). Errors are `AdaDiamonds::Error` with `status`, `code`, `description`, `documentation_url`, and `retry_after`. Every response's `RateLimit-*` headers are available from `last_rate_limit`; pace yourself rather than retrying into a 429.
98
+
99
+ ## Etiquette
100
+
101
+ Identify your agent with `AdaDiamonds::Client.new(user_agent: "my-agent/1.0 (+https://example.com)")`. Bulk scraping of the HTML catalog is not permitted; this API and `POST /api/v1/exports` are the supported way to read it. Diamond inventory changes continuously; re-check a stone before quoting it.
102
+
103
+ ## Development
104
+
105
+ ```bash
106
+ bundle install
107
+ bundle exec rake test
108
+ ```
109
+
110
+ ## License
111
+
112
+ MIT. Copyright Ada Diamonds, Inc.
@@ -0,0 +1,295 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdaDiamonds
4
+ # Production host.
5
+ DEFAULT_BASE_URL = "https://www.adadiamonds.com"
6
+ # REST API version this client targets.
7
+ API_VERSION = "v1"
8
+ USER_AGENT = "ada-diamonds-ruby/#{VERSION} (+https://www.adadiamonds.com/developers)"
9
+
10
+ # Site-root endpoints that do not live under /api/v1.
11
+ ROOT_PATHS = ["/ask", "/mcp", "/openapi.json", "/llms.txt"].freeze
12
+
13
+ # A non-2xx response, decoded from the API's JSON error body: a stable
14
+ # machine-readable +code+, a human-readable +description+ that says what to
15
+ # do next, and the HTTP +status+. +documentation_url+ and +retry_after+
16
+ # (seconds) are carried when the API sends them.
17
+ class Error < StandardError
18
+ attr_reader :status, :code, :description, :documentation_url, :retry_after, :body
19
+
20
+ def initialize(status:, code:, description: "", documentation_url: nil, retry_after: 0, body: {})
21
+ @status = status
22
+ @code = code
23
+ @description = description
24
+ @documentation_url = documentation_url
25
+ @retry_after = retry_after
26
+ @body = body
27
+ super(description.empty? ? "#{status} #{code}" : "#{status} #{code}: #{description}")
28
+ end
29
+ end
30
+
31
+ # The RateLimit-* headers from the most recent response. Counters are per
32
+ # 60 second window; treat them as a pacing signal.
33
+ RateLimit = Struct.new(:limit, :remaining, :reset, :policy, keyword_init: true)
34
+
35
+ # One page of a list response: catalog items plus pagination. Items are
36
+ # plain hashes because the catalog schema evolves faster than a client
37
+ # release; the field names match the OpenAPI document exactly.
38
+ class Page
39
+ include Enumerable
40
+
41
+ attr_reader :object, :currency, :data, :pagination
42
+
43
+ def initialize(body)
44
+ body ||= {}
45
+ @object = body["object"]
46
+ @currency = body["currency"]
47
+ @data = body["data"] || []
48
+ @pagination = body["pagination"] || {}
49
+ end
50
+
51
+ def each(&block)
52
+ @data.each(&block)
53
+ end
54
+
55
+ def total
56
+ @pagination["total"]
57
+ end
58
+
59
+ def limit
60
+ @pagination["limit"]
61
+ end
62
+
63
+ def offset
64
+ @pagination["offset"]
65
+ end
66
+
67
+ def has_more?
68
+ @pagination["has_more"] == true
69
+ end
70
+ end
71
+
72
+ # Calls the Ada Diamonds REST API. Every public method maps to exactly one
73
+ # endpoint; anything the client does can be reproduced with curl.
74
+ class Client
75
+ attr_reader :base_url, :api_key, :user_agent, :timeout, :last_rate_limit, :last_headers
76
+
77
+ # +api_key+: an ada_live_* / ada_test_* key or an OAuth access token (nil
78
+ # means anonymous). +base_url+ points at another host (a staging
79
+ # deployment, a proxy). +user_agent+ identifies your agent.
80
+ def initialize(api_key: nil, base_url: DEFAULT_BASE_URL, user_agent: USER_AGENT, timeout: 30)
81
+ @api_key = api_key
82
+ @base_url = base_url.sub(%r{/+\z}, "")
83
+ @user_agent = user_agent
84
+ @timeout = timeout
85
+ @last_rate_limit = nil
86
+ @last_headers = {}
87
+ end
88
+
89
+ # ---------------------------------------------------------------- catalog
90
+
91
+ # Searches available loose lab grown diamonds. Filters: shape, min_carat,
92
+ # max_carat, min_price, max_price, color, clarity, cut, sort (price_asc |
93
+ # price_desc | carat_asc | carat_desc), limit, offset.
94
+ def diamonds(params = {})
95
+ Page.new(get("/diamonds", params))
96
+ end
97
+
98
+ # Fetches one stone by id (the catalog id or grading report number).
99
+ def diamond(id)
100
+ get("/diamonds/#{escape(id)}")
101
+ end
102
+
103
+ # Searches ring settings. Filters: shape, style, type, min_price,
104
+ # max_price, q, limit, offset. Setting prices exclude the center stone.
105
+ def engagement_rings(params = {})
106
+ Page.new(get("/engagement-rings", params))
107
+ end
108
+
109
+ # Fetches one setting by slug.
110
+ def engagement_ring(slug)
111
+ get("/engagement-rings/#{escape(slug)}")
112
+ end
113
+
114
+ # Searches wedding bands, earrings, necklaces, bracelets, and fashion
115
+ # rings. Filters: category, type, shape, min_price, max_price, q, limit, offset.
116
+ def jewelry(params = {})
117
+ Page.new(get("/jewelry", params))
118
+ end
119
+
120
+ # Fetches one jewelry product by slug.
121
+ def jewelry_item(slug)
122
+ get("/jewelry/#{escape(slug)}")
123
+ end
124
+
125
+ # Lists the buying guides and articles. +query+ may be nil.
126
+ def knowledge_base(query = nil, params = {})
127
+ merged = params.dup
128
+ merged[:q] = query if query && !query.empty?
129
+ Page.new(get("/knowledge-base", merged))
130
+ end
131
+
132
+ # Fetches one article by slug, with its body as markdown.
133
+ def article(slug)
134
+ get("/knowledge-base/#{escape(slug)}")
135
+ end
136
+
137
+ # Lists showroom locations, hours, and remote consultation options.
138
+ def showrooms
139
+ get("/showrooms")
140
+ end
141
+
142
+ # ----------------------------------------------------------------- writes
143
+
144
+ # Asks a jeweler to contact the customer. Requires the appointments:write
145
+ # scope (any API key). Sandbox keys return a well-formed response and
146
+ # contact nobody. Pass an +idempotency_key+ so a retried call cannot
147
+ # create two requests.
148
+ def request_consultation(payload, idempotency_key: nil)
149
+ headers = idempotency_key ? { "Idempotency-Key" => idempotency_key } : {}
150
+ request(:post, "/consultations", body: payload, headers: headers)
151
+ end
152
+
153
+ # Issues a self-serve API key. +env+ is "sandbox" or "production". The key
154
+ # is returned once, in the api_key field; only a hash is stored.
155
+ def create_key(name, env: "sandbox")
156
+ post("/keys", { name: name, env: env })
157
+ end
158
+
159
+ # Runs up to 20 GET requests in one round trip via POST /api/v1/batch.
160
+ # Each request is a hash with id, method, path, and an optional query.
161
+ # The response carries one responses entry per request, in order, each
162
+ # with its own id, status, and body.
163
+ def batch(requests)
164
+ post("/batch", { requests: requests })
165
+ end
166
+
167
+ # ------------------------------------------------------------------ nlweb
168
+
169
+ # Sends a natural-language question to the NLWeb /ask endpoint and returns
170
+ # the JSON answer (products and guides with citations).
171
+ def ask(query, params = {})
172
+ get("/ask", params.merge(query: query))
173
+ end
174
+
175
+ # ---------------------------------------------------------------- generic
176
+
177
+ # GET any path relative to /api/v1 ("/diamonds") or absolute on the site
178
+ # ("/ask", "/api/acp/...") and decode the JSON response.
179
+ def get(path, params = {})
180
+ request(:get, path, params: params)
181
+ end
182
+
183
+ # POST a JSON body to any path and decode the JSON response.
184
+ def post(path, body = nil)
185
+ request(:post, path, body: body)
186
+ end
187
+
188
+ # Sends one request. Returns the decoded JSON (nil for an empty body) or
189
+ # raises AdaDiamonds::Error for a non-2xx response.
190
+ def request(method, path, params: {}, body: nil, headers: {})
191
+ uri = URI(resolve(path))
192
+ query = encode_params(params)
193
+ uri.query = [uri.query, query].compact.reject(&:empty?).join("&") unless query.empty?
194
+
195
+ klass = method.to_s.upcase == "POST" ? Net::HTTP::Post : Net::HTTP::Get
196
+ req = klass.new(uri)
197
+ req["Accept"] = "application/json"
198
+ req["User-Agent"] = user_agent
199
+ req["Authorization"] = "Bearer #{api_key}" if api_key && !api_key.empty?
200
+ headers.each { |k, v| req[k] = v }
201
+ if body
202
+ req["Content-Type"] = "application/json"
203
+ req.body = JSON.generate(body)
204
+ end
205
+
206
+ http = Net::HTTP.new(uri.host, uri.port)
207
+ http.use_ssl = uri.scheme == "https"
208
+ http.open_timeout = timeout
209
+ http.read_timeout = timeout
210
+ res = http.request(req)
211
+
212
+ remember(res)
213
+ raw = res.body.to_s
214
+ status = res.code.to_i
215
+ raise decode_error(status, raw, res) unless (200..299).cover?(status)
216
+ return nil if status == 204 || raw.strip.empty?
217
+
218
+ JSON.parse(raw)
219
+ end
220
+
221
+ private
222
+
223
+ def escape(value)
224
+ URI.encode_www_form_component(value.to_s).gsub("+", "%20")
225
+ end
226
+
227
+ def resolve(path)
228
+ path = path.to_s
229
+ return path if path.start_with?("http://", "https://")
230
+
231
+ path = "/#{path}" unless path.start_with?("/")
232
+ bare = path.split("?", 2).first
233
+ return "#{base_url}#{path}" if path.start_with?("/api/") || ROOT_PATHS.include?(bare)
234
+
235
+ "#{base_url}/api/#{API_VERSION}#{path}"
236
+ end
237
+
238
+ # Builds a query string with deterministic key order. Nil and empty-string
239
+ # values are skipped, so a caller can pass optional filters without pruning
240
+ # them first. Arrays are repeated as multiple values of the same key.
241
+ def encode_params(params)
242
+ return "" if params.nil? || params.empty?
243
+
244
+ pairs = []
245
+ params.keys.map(&:to_s).sort.each do |key|
246
+ value = params.fetch(key.to_sym) { params[key] }
247
+ Array(value).each do |item|
248
+ next if item.nil?
249
+
250
+ text = item.to_s
251
+ next if text.empty?
252
+
253
+ pairs << [key, text]
254
+ end
255
+ end
256
+ URI.encode_www_form(pairs)
257
+ end
258
+
259
+ def remember(res)
260
+ @last_headers = res.each_header.to_h
261
+ to_i = ->(name) { res[name].to_s.strip.to_i }
262
+ @last_rate_limit = RateLimit.new(
263
+ limit: to_i.call("RateLimit-Limit"),
264
+ remaining: to_i.call("RateLimit-Remaining"),
265
+ reset: to_i.call("RateLimit-Reset"),
266
+ policy: res["RateLimit-Policy"].to_s
267
+ )
268
+ end
269
+
270
+ def decode_error(status, raw, res)
271
+ code = "http_#{status}"
272
+ description = ""
273
+ documentation_url = nil
274
+ retry_after = 0
275
+ body = {}
276
+ parsed = begin
277
+ raw.empty? ? nil : JSON.parse(raw)
278
+ rescue JSON::ParserError
279
+ nil
280
+ end
281
+ if parsed.is_a?(Hash)
282
+ body = parsed
283
+ code = parsed["error"] if parsed["error"].is_a?(String) && !parsed["error"].empty?
284
+ description = parsed["error_description"] if parsed["error_description"].is_a?(String)
285
+ documentation_url = parsed["documentation_url"] if parsed["documentation_url"].is_a?(String)
286
+ retry_after = parsed["retry_after_seconds"].to_i if parsed["retry_after_seconds"].is_a?(Numeric)
287
+ elsif !raw.empty?
288
+ description = raw[0, 500]
289
+ end
290
+ retry_after = res["Retry-After"].to_s.strip.to_i if retry_after.zero? && res["Retry-After"]
291
+ Error.new(status: status, code: code, description: description, documentation_url: documentation_url,
292
+ retry_after: retry_after, body: body)
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdaDiamonds
4
+ # Client version, sent in the User-Agent header.
5
+ VERSION = "0.1.0"
6
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Official Ruby client for the Ada Diamonds API: live lab grown diamond
4
+ # inventory, engagement ring settings, fine jewelry, showrooms, and the
5
+ # diamond buying guides.
6
+ #
7
+ # Reading the catalog needs no account and no API key (120 requests per
8
+ # minute). An API key or OAuth access token raises the limit to 600 and
9
+ # unlocks the write endpoints. Every price is in US dollars.
10
+ #
11
+ # client = AdaDiamonds::Client.new
12
+ # page = client.diamonds(shape: "Oval", min_carat: 1, max_price: 4000)
13
+ # page.data.each { |stone| puts [stone["carat"], stone["shape"], stone["price"]].join(" ") }
14
+ #
15
+ # Documentation: https://www.adadiamonds.com/developers
16
+ # OpenAPI: https://www.adadiamonds.com/openapi.json
17
+ require "json"
18
+ require "net/http"
19
+ require "uri"
20
+
21
+ require_relative "adadiamonds/version"
22
+ require_relative "adadiamonds/client"
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: adadiamonds
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ada Diamonds
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webrick
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ description: Search live lab grown diamond inventory, engagement ring settings, fine
56
+ jewelry, showrooms, and the diamond buying guides at adadiamonds.com. Standard library
57
+ only; no account or API key needed to read the catalog.
58
+ email:
59
+ - it@adadiamonds.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - CHANGELOG.md
65
+ - LICENSE
66
+ - README.md
67
+ - lib/adadiamonds.rb
68
+ - lib/adadiamonds/client.rb
69
+ - lib/adadiamonds/version.rb
70
+ homepage: https://www.adadiamonds.com/developers
71
+ licenses:
72
+ - MIT
73
+ metadata:
74
+ homepage_uri: https://www.adadiamonds.com/developers
75
+ documentation_uri: https://www.adadiamonds.com/developers/cli
76
+ source_code_uri: https://github.com/adadiamonds/ada-ruby
77
+ changelog_uri: https://github.com/adadiamonds/ada-ruby/blob/main/CHANGELOG.md
78
+ bug_tracker_uri: https://github.com/adadiamonds/ada-ruby/issues
79
+ rubygems_mfa_required: 'true'
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '2.6'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.0.3.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Official Ruby client for the Ada Diamonds API
99
+ test_files: []