optify-config 1.18.0 → 1.21.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.
- checksums.yaml +4 -4
- data/ext/optify_ruby/Cargo.toml +5 -4
- data/ext/optify_ruby/src/lib.rs +84 -19
- data/lib/optify_ruby/cache_init_options.rb +41 -0
- data/lib/optify_ruby/implementation.rb +4 -3
- data/lib/optify_ruby/provider_module.rb +52 -17
- data/lib/optify_ruby/watcher_implementation.rb +3 -3
- data/rbi/optify.rbi +63 -13
- data/sig/optify.rbs +29 -9
- metadata +22 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '029bd9d7bb3680eff70b702cfca85a1b8ccf95ad96fde27b1e23a6f635b36c97'
|
|
4
|
+
data.tar.gz: 8cdfa212412ddb927fbfdcda7fa3c2fe658a0529af4c9ade7117bced98cce61f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9bd1a0ba1a66bc6115b9489502b1fda87d66ab22936d0b111a4204392299c7d0120660e04107caa5948c8333841246890dfb6166bb86ec8cc13b47e4ee341aa3
|
|
7
|
+
data.tar.gz: 03d8822a3407b6a3b317c70877244dce3000a2b9b407bce75ec0f0b2c39cf7262a37712cdac9fb8f42ab5a205050e9b49fc728ef89e810ded654da70dd78e0a8
|
data/ext/optify_ruby/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "optify_ruby"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.23.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
description = "optify bindings for Ruby"
|
|
@@ -20,7 +20,8 @@ exclude = [
|
|
|
20
20
|
crate-type = ["cdylib"]
|
|
21
21
|
|
|
22
22
|
[dependencies]
|
|
23
|
-
magnus = "0.8.
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
magnus = "0.8.2"
|
|
24
|
+
# Can't put a relative path here because then others can't install the source gem: https://github.com/juharris/optify/pull/176
|
|
25
|
+
optify = "1.0.0"
|
|
26
|
+
rb-sys = { version = "0.9.124", default-features = false, features = ["ruby-static"] }
|
|
26
27
|
serde_json = "1.0.143"
|
data/ext/optify_ruby/src/lib.rs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
use magnus::{
|
|
1
|
+
use magnus::{
|
|
2
|
+
exception::ExceptionClass, function, method, prelude::*, wrap, Object, RModule, Ruby,
|
|
3
|
+
Value as RbValue,
|
|
4
|
+
};
|
|
2
5
|
use optify::builder::OptionsProviderBuilder;
|
|
3
6
|
use optify::builder::OptionsRegistryBuilder;
|
|
4
7
|
use optify::builder::OptionsWatcherBuilder;
|
|
@@ -13,6 +16,24 @@ use crate::preferences::MutGetOptionsPreferences;
|
|
|
13
16
|
|
|
14
17
|
mod preferences;
|
|
15
18
|
|
|
19
|
+
const UNKNOWN_FEATURE_PATTERN: &str = "is not a known feature.";
|
|
20
|
+
|
|
21
|
+
fn get_unknown_feature_error(ruby: &Ruby) -> Result<ExceptionClass, magnus::Error> {
|
|
22
|
+
let module: RModule = ruby.class_object().const_get("Optify")?;
|
|
23
|
+
module.const_get("UnknownFeatureError")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fn map_feature_error(ruby: &Ruby, error: String) -> magnus::Error {
|
|
27
|
+
if error.contains(UNKNOWN_FEATURE_PATTERN) {
|
|
28
|
+
match get_unknown_feature_error(ruby) {
|
|
29
|
+
Ok(exception_class) => magnus::Error::new(exception_class, error),
|
|
30
|
+
Err(_) => magnus::Error::new(ruby.exception_runtime_error(), error),
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
magnus::Error::new(ruby.exception_runtime_error(), error)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
16
37
|
fn json_value_to_ruby(ruby: &Ruby, value: &serde_json::Value) -> Result<RbValue, magnus::Error> {
|
|
17
38
|
match value {
|
|
18
39
|
serde_json::Value::Null => Ok(ruby.qnil().as_value()),
|
|
@@ -117,7 +138,7 @@ impl WrappedOptionsProvider {
|
|
|
117
138
|
.get_all_options(&feature_names, None, Some(preferences))
|
|
118
139
|
{
|
|
119
140
|
Ok(options) => Ok(options.to_string()),
|
|
120
|
-
Err(e) => Err(
|
|
141
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
121
142
|
}
|
|
122
143
|
}
|
|
123
144
|
|
|
@@ -134,7 +155,7 @@ impl WrappedOptionsProvider {
|
|
|
134
155
|
.get_all_options(&feature_names, None, Some(preferences))
|
|
135
156
|
{
|
|
136
157
|
Ok(options) => json_value_to_ruby(ruby, &options),
|
|
137
|
-
Err(e) => Err(
|
|
158
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
138
159
|
}
|
|
139
160
|
}
|
|
140
161
|
|
|
@@ -147,7 +168,7 @@ impl WrappedOptionsProvider {
|
|
|
147
168
|
.0
|
|
148
169
|
.borrow()
|
|
149
170
|
.get_canonical_feature_name(&feature_name)
|
|
150
|
-
.map_err(|e|
|
|
171
|
+
.map_err(|e| map_feature_error(ruby, e))
|
|
151
172
|
}
|
|
152
173
|
|
|
153
174
|
fn get_canonical_feature_names(
|
|
@@ -159,7 +180,7 @@ impl WrappedOptionsProvider {
|
|
|
159
180
|
.0
|
|
160
181
|
.borrow()
|
|
161
182
|
.get_canonical_feature_names(&feature_names)
|
|
162
|
-
.map_err(|e|
|
|
183
|
+
.map_err(|e| map_feature_error(ruby, e))
|
|
163
184
|
}
|
|
164
185
|
|
|
165
186
|
fn get_feature_metadata_json(&self, canonical_feature_name: String) -> Option<String> {
|
|
@@ -191,7 +212,7 @@ impl WrappedOptionsProvider {
|
|
|
191
212
|
.get_filtered_feature_names(&feature_names, Some(preferences))
|
|
192
213
|
{
|
|
193
214
|
Ok(features) => Ok(features),
|
|
194
|
-
Err(e) => Err(
|
|
215
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
195
216
|
}
|
|
196
217
|
}
|
|
197
218
|
|
|
@@ -208,7 +229,7 @@ impl WrappedOptionsProvider {
|
|
|
208
229
|
.get_options_with_preferences(&key, &feature_names, None, None)
|
|
209
230
|
{
|
|
210
231
|
Ok(options) => Ok(options.to_string()),
|
|
211
|
-
Err(e) => Err(
|
|
232
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
212
233
|
}
|
|
213
234
|
}
|
|
214
235
|
|
|
@@ -227,7 +248,7 @@ impl WrappedOptionsProvider {
|
|
|
227
248
|
Some(preferences),
|
|
228
249
|
) {
|
|
229
250
|
Ok(options) => Ok(options.to_string()),
|
|
230
|
-
Err(e) => Err(
|
|
251
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
231
252
|
}
|
|
232
253
|
}
|
|
233
254
|
|
|
@@ -243,7 +264,7 @@ impl WrappedOptionsProvider {
|
|
|
243
264
|
.get_options_with_preferences(&key, &feature_names, None, None)
|
|
244
265
|
{
|
|
245
266
|
Ok(options) => json_value_to_ruby(ruby, &options),
|
|
246
|
-
Err(e) => Err(
|
|
267
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
247
268
|
}
|
|
248
269
|
}
|
|
249
270
|
|
|
@@ -262,13 +283,30 @@ impl WrappedOptionsProvider {
|
|
|
262
283
|
Some(preferences),
|
|
263
284
|
) {
|
|
264
285
|
Ok(options) => json_value_to_ruby(ruby, &options),
|
|
265
|
-
Err(e) => Err(
|
|
286
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
266
287
|
}
|
|
267
288
|
}
|
|
268
289
|
|
|
269
290
|
fn has_conditions(&self, canonical_feature_name: String) -> bool {
|
|
270
291
|
self.0.borrow().has_conditions(&canonical_feature_name)
|
|
271
292
|
}
|
|
293
|
+
|
|
294
|
+
fn map_feature_names(
|
|
295
|
+
ruby: &Ruby,
|
|
296
|
+
rb_self: &Self,
|
|
297
|
+
feature_names: Vec<String>,
|
|
298
|
+
preferences: &MutGetOptionsPreferences,
|
|
299
|
+
) -> Result<Vec<Option<String>>, magnus::Error> {
|
|
300
|
+
let preferences = &convert_preferences(preferences);
|
|
301
|
+
match rb_self
|
|
302
|
+
.0
|
|
303
|
+
.borrow()
|
|
304
|
+
.map_feature_names(&feature_names, Some(preferences))
|
|
305
|
+
{
|
|
306
|
+
Ok(features) => Ok(features),
|
|
307
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
308
|
+
}
|
|
309
|
+
}
|
|
272
310
|
}
|
|
273
311
|
|
|
274
312
|
#[derive(Clone)]
|
|
@@ -363,7 +401,7 @@ impl WrappedOptionsWatcher {
|
|
|
363
401
|
.get_all_options(&feature_names, None, Some(preferences))
|
|
364
402
|
{
|
|
365
403
|
Ok(options) => Ok(options.to_string()),
|
|
366
|
-
Err(e) => Err(
|
|
404
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
367
405
|
}
|
|
368
406
|
}
|
|
369
407
|
|
|
@@ -380,7 +418,7 @@ impl WrappedOptionsWatcher {
|
|
|
380
418
|
.get_all_options(&feature_names, None, Some(preferences))
|
|
381
419
|
{
|
|
382
420
|
Ok(options) => json_value_to_ruby(ruby, &options),
|
|
383
|
-
Err(e) => Err(
|
|
421
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
384
422
|
}
|
|
385
423
|
}
|
|
386
424
|
|
|
@@ -393,7 +431,7 @@ impl WrappedOptionsWatcher {
|
|
|
393
431
|
.0
|
|
394
432
|
.borrow()
|
|
395
433
|
.get_canonical_feature_name(&feature_name)
|
|
396
|
-
.map_err(|e|
|
|
434
|
+
.map_err(|e| map_feature_error(ruby, e))
|
|
397
435
|
}
|
|
398
436
|
|
|
399
437
|
fn get_canonical_feature_names(
|
|
@@ -405,7 +443,7 @@ impl WrappedOptionsWatcher {
|
|
|
405
443
|
.0
|
|
406
444
|
.borrow()
|
|
407
445
|
.get_canonical_feature_names(&feature_names)
|
|
408
|
-
.map_err(|e|
|
|
446
|
+
.map_err(|e| map_feature_error(ruby, e))
|
|
409
447
|
}
|
|
410
448
|
|
|
411
449
|
fn get_feature_metadata_json(&self, canonical_feature_name: String) -> Option<String> {
|
|
@@ -436,7 +474,7 @@ impl WrappedOptionsWatcher {
|
|
|
436
474
|
.get_filtered_feature_names(&feature_names, Some(preferences))
|
|
437
475
|
{
|
|
438
476
|
Ok(features) => Ok(features),
|
|
439
|
-
Err(e) => Err(
|
|
477
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
440
478
|
}
|
|
441
479
|
}
|
|
442
480
|
|
|
@@ -452,7 +490,7 @@ impl WrappedOptionsWatcher {
|
|
|
452
490
|
.get_options_with_preferences(&key, &feature_names, None, None)
|
|
453
491
|
{
|
|
454
492
|
Ok(options) => Ok(options.to_string()),
|
|
455
|
-
Err(e) => Err(
|
|
493
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
456
494
|
}
|
|
457
495
|
}
|
|
458
496
|
|
|
@@ -471,7 +509,7 @@ impl WrappedOptionsWatcher {
|
|
|
471
509
|
Some(preferences),
|
|
472
510
|
) {
|
|
473
511
|
Ok(options) => Ok(options.to_string()),
|
|
474
|
-
Err(e) => Err(
|
|
512
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
475
513
|
}
|
|
476
514
|
}
|
|
477
515
|
|
|
@@ -487,7 +525,7 @@ impl WrappedOptionsWatcher {
|
|
|
487
525
|
.get_options_with_preferences(&key, &feature_names, None, None)
|
|
488
526
|
{
|
|
489
527
|
Ok(options) => json_value_to_ruby(ruby, &options),
|
|
490
|
-
Err(e) => Err(
|
|
528
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
491
529
|
}
|
|
492
530
|
}
|
|
493
531
|
|
|
@@ -506,7 +544,7 @@ impl WrappedOptionsWatcher {
|
|
|
506
544
|
Some(preferences),
|
|
507
545
|
) {
|
|
508
546
|
Ok(options) => json_value_to_ruby(ruby, &options),
|
|
509
|
-
Err(e) => Err(
|
|
547
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
510
548
|
}
|
|
511
549
|
}
|
|
512
550
|
|
|
@@ -517,6 +555,23 @@ impl WrappedOptionsWatcher {
|
|
|
517
555
|
fn last_modified(&self) -> std::time::SystemTime {
|
|
518
556
|
self.0.borrow().last_modified()
|
|
519
557
|
}
|
|
558
|
+
|
|
559
|
+
fn map_feature_names(
|
|
560
|
+
ruby: &Ruby,
|
|
561
|
+
rb_self: &Self,
|
|
562
|
+
feature_names: Vec<String>,
|
|
563
|
+
preferences: &MutGetOptionsPreferences,
|
|
564
|
+
) -> Result<Vec<Option<String>>, magnus::Error> {
|
|
565
|
+
let preferences = &convert_preferences(preferences);
|
|
566
|
+
match rb_self
|
|
567
|
+
.0
|
|
568
|
+
.borrow()
|
|
569
|
+
.map_feature_names(&feature_names, Some(preferences))
|
|
570
|
+
{
|
|
571
|
+
Ok(features) => Ok(features),
|
|
572
|
+
Err(e) => Err(map_feature_error(ruby, e)),
|
|
573
|
+
}
|
|
574
|
+
}
|
|
520
575
|
}
|
|
521
576
|
|
|
522
577
|
#[derive(Clone)]
|
|
@@ -551,6 +606,8 @@ impl WrappedOptionsWatcherBuilder {
|
|
|
551
606
|
fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
552
607
|
let module = ruby.define_module("Optify")?;
|
|
553
608
|
|
|
609
|
+
module.define_error("UnknownFeatureError", ruby.exception_standard_error())?;
|
|
610
|
+
|
|
554
611
|
let builder_class = module.define_class("OptionsProviderBuilder", ruby.class_object())?;
|
|
555
612
|
|
|
556
613
|
builder_class
|
|
@@ -620,6 +677,10 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
620
677
|
"conditions?",
|
|
621
678
|
method!(WrappedOptionsProvider::has_conditions, 1),
|
|
622
679
|
)?;
|
|
680
|
+
provider_class.define_method(
|
|
681
|
+
"map_feature_names",
|
|
682
|
+
method!(WrappedOptionsProvider::map_feature_names, 2),
|
|
683
|
+
)?;
|
|
623
684
|
|
|
624
685
|
// Private methods for internal use.
|
|
625
686
|
provider_class.define_private_method(
|
|
@@ -759,6 +820,10 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
759
820
|
"last_modified",
|
|
760
821
|
method!(WrappedOptionsWatcher::last_modified, 0),
|
|
761
822
|
)?;
|
|
823
|
+
watcher_class.define_method(
|
|
824
|
+
"map_feature_names",
|
|
825
|
+
method!(WrappedOptionsWatcher::map_feature_names, 2),
|
|
826
|
+
)?;
|
|
762
827
|
|
|
763
828
|
// Private methods for internal use.
|
|
764
829
|
watcher_class.define_private_method(
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Optify
|
|
5
|
+
# The mode for the cache.
|
|
6
|
+
module CacheMode
|
|
7
|
+
# Non-thread-safe LRU cache.
|
|
8
|
+
# Should be faster than `THREAD_SAFE` for single-threaded applications.
|
|
9
|
+
NOT_THREAD_SAFE = :not_thread_safe #: Symbol
|
|
10
|
+
# Thread-safe LRU cache.
|
|
11
|
+
THREAD_SAFE = :thread_safe #: Symbol
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Options for initializing the cache.
|
|
15
|
+
class CacheInitOptions
|
|
16
|
+
#: Integer?
|
|
17
|
+
attr_reader :max_size
|
|
18
|
+
|
|
19
|
+
# A value from `CacheMode`.
|
|
20
|
+
#
|
|
21
|
+
#: Symbol
|
|
22
|
+
attr_reader :mode
|
|
23
|
+
|
|
24
|
+
# Initializes the cache options.
|
|
25
|
+
# Defaults to a non-thread-safe unlimited size cache for backwards compatibility
|
|
26
|
+
# with how this library was originally configured with an unbounded hash as the base.
|
|
27
|
+
# @param mode A value from `CacheMode`.
|
|
28
|
+
#
|
|
29
|
+
#: (
|
|
30
|
+
#| ?max_size: Integer?,
|
|
31
|
+
#| ?mode: Symbol,
|
|
32
|
+
#| ) -> void
|
|
33
|
+
def initialize(
|
|
34
|
+
max_size: nil,
|
|
35
|
+
mode: CacheMode::NOT_THREAD_SAFE
|
|
36
|
+
)
|
|
37
|
+
@max_size = max_size
|
|
38
|
+
@mode = mode
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
require 'sorbet-runtime'
|
|
5
5
|
|
|
6
6
|
require_relative './base_config'
|
|
7
|
+
require_relative './cache_init_options'
|
|
7
8
|
require_relative './options_metadata'
|
|
8
9
|
require_relative './provider_module'
|
|
9
10
|
|
|
@@ -32,9 +33,9 @@ module Optify
|
|
|
32
33
|
|
|
33
34
|
# (Optional) Eagerly initializes the cache.
|
|
34
35
|
# @return [OptionsProvider] `self`.
|
|
35
|
-
#: -> OptionsProvider
|
|
36
|
-
def init
|
|
37
|
-
_init
|
|
36
|
+
#: (?CacheInitOptions?) -> OptionsProvider
|
|
37
|
+
def init(cache_init_options = nil)
|
|
38
|
+
_init(cache_init_options)
|
|
38
39
|
self
|
|
39
40
|
end
|
|
40
41
|
end
|
|
@@ -2,11 +2,47 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'lru_redux'
|
|
5
6
|
require 'sorbet-runtime'
|
|
6
7
|
|
|
7
8
|
module Optify
|
|
8
9
|
# @!visibility private
|
|
9
10
|
module ProviderModule
|
|
11
|
+
#: [T] (LruRedux::Cache | Hash[untyped, untyped], Array[untyped]) { -> T } -> T
|
|
12
|
+
def self._cache_getset(cache, cache_key, &block)
|
|
13
|
+
if cache.is_a? LruRedux::Cache
|
|
14
|
+
cache.getset(cache_key, &block)
|
|
15
|
+
else
|
|
16
|
+
# Plain Hash - use fetch with block and store result
|
|
17
|
+
cache.fetch(cache_key) do
|
|
18
|
+
result = block.call
|
|
19
|
+
cache[cache_key] = result
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#: (CacheInitOptions?) -> ( Hash[Array[untyped], untyped] | LruRedux::Cache)
|
|
25
|
+
def self._create_cache(cache_init_options)
|
|
26
|
+
# Be backwards compatible with the original implementation of this library.
|
|
27
|
+
return {} if cache_init_options.nil?
|
|
28
|
+
|
|
29
|
+
max_size = cache_init_options.max_size
|
|
30
|
+
mode = cache_init_options.mode
|
|
31
|
+
if max_size.nil?
|
|
32
|
+
Kernel.raise ArgumentError, 'Thread-safe cache is not supported when max_size is nil' if mode == CacheMode::THREAD_SAFE
|
|
33
|
+
{}
|
|
34
|
+
else
|
|
35
|
+
case mode
|
|
36
|
+
when CacheMode::THREAD_SAFE
|
|
37
|
+
LruRedux::ThreadSafeCache.new(max_size)
|
|
38
|
+
when CacheMode::NOT_THREAD_SAFE
|
|
39
|
+
LruRedux::Cache.new(max_size)
|
|
40
|
+
else
|
|
41
|
+
Kernel.raise ArgumentError, "Invalid cache mode: #{mode}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
10
46
|
#: (Array[String] feature_names) -> Array[String]
|
|
11
47
|
def get_canonical_feature_names(feature_names)
|
|
12
48
|
# Try to optimize a typical case where there are just a few features.
|
|
@@ -55,7 +91,7 @@ module Optify
|
|
|
55
91
|
# @return The options.
|
|
56
92
|
#: [Config] (String, Array[String], Class[Config], ?CacheOptions?, ?Optify::GetOptionsPreferences?) -> Config
|
|
57
93
|
def _get_options(key, feature_names, config_class, cache_options = nil, preferences = nil)
|
|
58
|
-
return
|
|
94
|
+
return _get_options_with_cache(key, feature_names, config_class, cache_options, preferences) if cache_options
|
|
59
95
|
|
|
60
96
|
unless config_class.respond_to?(:from_hash)
|
|
61
97
|
Kernel.raise NotImplementedError,
|
|
@@ -73,14 +109,8 @@ module Optify
|
|
|
73
109
|
.from_hash(hash)
|
|
74
110
|
end
|
|
75
111
|
|
|
76
|
-
#: -> void
|
|
77
|
-
def _init
|
|
78
|
-
@cache = {} #: Hash[untyped, untyped]?
|
|
79
|
-
@features_with_metadata = nil #: Hash[String, OptionsMetadata]?
|
|
80
|
-
end
|
|
81
|
-
|
|
82
112
|
#: [Config] (String key, Array[String] feature_names, Class[Config] config_class, Optify::CacheOptions _cache_options, ?Optify::GetOptionsPreferences? preferences) -> Config
|
|
83
|
-
def
|
|
113
|
+
def _get_options_with_cache(key, feature_names, config_class, _cache_options, preferences = nil)
|
|
84
114
|
# Cache directly in Ruby instead of Rust because:
|
|
85
115
|
# * Avoid any possible conversion overhead.
|
|
86
116
|
# * Memory management: probably better to do it in Ruby for a Ruby app and avoid memory in Rust.
|
|
@@ -100,22 +130,27 @@ module Optify
|
|
|
100
130
|
# Features are filtered, so we don't need the constraints in the cache key.
|
|
101
131
|
are_configurable_strings_enabled = preferences&.are_configurable_strings_enabled? || false
|
|
102
132
|
cache_key = [key, feature_names, are_configurable_strings_enabled, config_class]
|
|
103
|
-
|
|
104
|
-
|
|
133
|
+
ProviderModule._cache_getset(
|
|
134
|
+
@cache, #: as !nil
|
|
135
|
+
cache_key,
|
|
136
|
+
) do
|
|
105
137
|
# Handle a cache miss.
|
|
106
138
|
|
|
107
139
|
# We can avoid converting the features names because they're already converted from filtering above, if that was desired.
|
|
108
140
|
# We don't need the constraints because we filtered the features above.
|
|
109
141
|
# We already know there are no overrides because we checked above.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
142
|
+
cache_miss_preferences = GetOptionsPreferences.new
|
|
143
|
+
cache_miss_preferences.skip_feature_name_conversion = true
|
|
144
|
+
cache_miss_preferences.enable_configurable_strings if are_configurable_strings_enabled
|
|
113
145
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
@cache #: as !nil
|
|
117
|
-
.[]= cache_key, result
|
|
146
|
+
_get_options(key, feature_names, config_class, nil, cache_miss_preferences)
|
|
118
147
|
end
|
|
119
148
|
end
|
|
149
|
+
|
|
150
|
+
#: (?CacheInitOptions?) -> void
|
|
151
|
+
def _init(cache_init_options = nil)
|
|
152
|
+
@cache = ProviderModule._create_cache(cache_init_options) #: ( Hash[untyped, untyped] | LruRedux::Cache)?
|
|
153
|
+
@features_with_metadata = nil #: Hash[String, OptionsMetadata]?
|
|
154
|
+
end
|
|
120
155
|
end
|
|
121
156
|
end
|
|
@@ -30,9 +30,9 @@ module Optify
|
|
|
30
30
|
|
|
31
31
|
# (Optional) Eagerly initializes the cache.
|
|
32
32
|
# @return [OptionsWatcher] `self`.
|
|
33
|
-
#: -> OptionsWatcher
|
|
34
|
-
def init
|
|
35
|
-
_init
|
|
33
|
+
#: (?CacheInitOptions?) -> OptionsWatcher
|
|
34
|
+
def init(cache_init_options = nil)
|
|
35
|
+
_init(cache_init_options)
|
|
36
36
|
@cache_creation_time = Time.now #: Time?
|
|
37
37
|
self
|
|
38
38
|
end
|
data/rbi/optify.rbi
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
# Tools for working with configurations declared in files.
|
|
5
5
|
module Optify
|
|
6
|
+
# Raised when a feature name is not found in the registry.
|
|
7
|
+
class UnknownFeatureError < StandardError
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
# DEPRECATED: Use `Optify::FromHashable` instead.
|
|
7
11
|
# A base class for classes from configuration files.
|
|
8
12
|
# Classes that derive from this can easily be used with `Optify::OptionsProvider.get_options`
|
|
@@ -19,6 +23,37 @@ module Optify
|
|
|
19
23
|
class CacheOptions < FromHashable
|
|
20
24
|
end
|
|
21
25
|
|
|
26
|
+
# The mode for the cache.
|
|
27
|
+
module CacheMode
|
|
28
|
+
# Non-thread-safe LRU cache.
|
|
29
|
+
# Should be faster than `THREAD_SAFE` for single-threaded applications.
|
|
30
|
+
NOT_THREAD_SAFE = T.let(:not_thread_safe, Symbol)
|
|
31
|
+
# Thread-safe LRU cache.
|
|
32
|
+
THREAD_SAFE = T.let(:thread_safe, Symbol)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Options for initializing the cache.
|
|
36
|
+
class CacheInitOptions
|
|
37
|
+
sig { returns(T.nilable(Integer)) }
|
|
38
|
+
attr_reader :max_size
|
|
39
|
+
|
|
40
|
+
# A value from `CacheMode`.
|
|
41
|
+
sig { returns(Symbol) }
|
|
42
|
+
attr_reader :mode
|
|
43
|
+
|
|
44
|
+
# Initializes the cache options.
|
|
45
|
+
# Defaults to a non-thread-safe unlimited size cache for backwards compatibility
|
|
46
|
+
# with how this library was originally configured with an unbounded hash as the base.
|
|
47
|
+
# @param mode A value from `CacheMode`.
|
|
48
|
+
sig do
|
|
49
|
+
params(
|
|
50
|
+
max_size: T.nilable(Integer),
|
|
51
|
+
mode: Symbol,
|
|
52
|
+
).void
|
|
53
|
+
end
|
|
54
|
+
def initialize(max_size: nil, mode: CacheMode::NOT_THREAD_SAFE); end
|
|
55
|
+
end
|
|
56
|
+
|
|
22
57
|
# Information about a feature.
|
|
23
58
|
class OptionsMetadata < FromHashable
|
|
24
59
|
sig { returns(T.nilable(T::Array[String])) }
|
|
@@ -161,6 +196,15 @@ module Optify
|
|
|
161
196
|
# Some of the methods shown within this module are implemented in Rust
|
|
162
197
|
# and are declared in this common module to avoid duplicate declarations in different classes.
|
|
163
198
|
module ProviderModule
|
|
199
|
+
# @param canonical_feature_name [String] A canonical feature name
|
|
200
|
+
# @return Whether the feature has conditions.
|
|
201
|
+
sig { params(canonical_feature_name: String).returns(T::Boolean) }
|
|
202
|
+
def conditions?(canonical_feature_name); end
|
|
203
|
+
|
|
204
|
+
# @return All of the keys and values for the the features.
|
|
205
|
+
sig { returns(String) }
|
|
206
|
+
def features_with_metadata_json; end
|
|
207
|
+
|
|
164
208
|
# Map an alias or canonical feature name (perhaps derived from a file name) to a canonical feature name.
|
|
165
209
|
# Canonical feature names map to themselves.
|
|
166
210
|
#
|
|
@@ -188,7 +232,7 @@ module Optify
|
|
|
188
232
|
sig do
|
|
189
233
|
params(
|
|
190
234
|
feature_names: T::Array[String],
|
|
191
|
-
preferences: GetOptionsPreferences
|
|
235
|
+
preferences: GetOptionsPreferences,
|
|
192
236
|
)
|
|
193
237
|
.returns(T::Array[String])
|
|
194
238
|
end
|
|
@@ -211,7 +255,7 @@ module Optify
|
|
|
211
255
|
feature_names: T::Array[String],
|
|
212
256
|
config_class: T::Class[T.type_parameter(:Config)],
|
|
213
257
|
cache_options: T.nilable(CacheOptions),
|
|
214
|
-
preferences: T.nilable(Optify::GetOptionsPreferences)
|
|
258
|
+
preferences: T.nilable(Optify::GetOptionsPreferences),
|
|
215
259
|
)
|
|
216
260
|
.returns(T.type_parameter(:Config))
|
|
217
261
|
end
|
|
@@ -257,15 +301,25 @@ module Optify
|
|
|
257
301
|
end
|
|
258
302
|
def get_options_json_with_preferences(key, feature_names, preferences); end
|
|
259
303
|
|
|
260
|
-
# @param canonical_feature_name [String] A canonical feature name
|
|
261
|
-
# @return Whether the feature has conditions.
|
|
262
|
-
sig { params(canonical_feature_name: String).returns(T::Boolean) }
|
|
263
|
-
def conditions?(canonical_feature_name); end
|
|
264
|
-
|
|
265
304
|
# (Optional) Eagerly initializes the cache.
|
|
266
305
|
# @return `self`.
|
|
267
|
-
sig
|
|
268
|
-
|
|
306
|
+
sig do
|
|
307
|
+
params(cache_init_options: T.nilable(CacheInitOptions))
|
|
308
|
+
.returns(T.self_type)
|
|
309
|
+
end
|
|
310
|
+
def init(cache_init_options = nil); end
|
|
311
|
+
|
|
312
|
+
# Filters `feature_names` based on the preferences,
|
|
313
|
+
# such as the `preferences`'s constraints.
|
|
314
|
+
# Returns an array matching the input order where each element is the canonical name if the feature was kept, or nil if it was filtered out.
|
|
315
|
+
sig do
|
|
316
|
+
params(
|
|
317
|
+
feature_names: T::Array[String],
|
|
318
|
+
preferences: GetOptionsPreferences,
|
|
319
|
+
)
|
|
320
|
+
.returns(T::Array[T.nilable(String)])
|
|
321
|
+
end
|
|
322
|
+
def map_feature_names(feature_names, preferences); end
|
|
269
323
|
|
|
270
324
|
private
|
|
271
325
|
|
|
@@ -281,10 +335,6 @@ module Optify
|
|
|
281
335
|
# @return The metadata for the feature.
|
|
282
336
|
sig { params(canonical_feature_name: String).returns(T.nilable(String)) }
|
|
283
337
|
def get_feature_metadata_json(canonical_feature_name); end
|
|
284
|
-
|
|
285
|
-
# @return All of the keys and values for the the features.
|
|
286
|
-
sig { returns(String) }
|
|
287
|
-
def features_with_metadata_json; end
|
|
288
338
|
end
|
|
289
339
|
|
|
290
340
|
# Provides configurations based on keys and enabled feature names.
|
data/sig/optify.rbs
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
module Optify
|
|
3
3
|
end
|
|
4
4
|
|
|
5
|
+
# Raised when a feature name is not found in the registry.
|
|
6
|
+
class Optify::UnknownFeatureError < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
5
9
|
# DEPRECATED: Use `Optify::FromHashable` instead.
|
|
6
10
|
# A base class for classes from configuration files.
|
|
7
11
|
# Classes that derive from this can easily be used with `Optify::OptionsProvider.get_options`
|
|
@@ -17,6 +21,22 @@ end
|
|
|
17
21
|
class Optify::CacheOptions < FromHashable
|
|
18
22
|
end
|
|
19
23
|
|
|
24
|
+
# The mode for the cache.
|
|
25
|
+
module Optify::CacheMode
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Optify::Optify::CacheMode::NOT_THREAD_SAFE: Symbol
|
|
29
|
+
|
|
30
|
+
Optify::Optify::CacheMode::THREAD_SAFE: Symbol
|
|
31
|
+
|
|
32
|
+
# Options for initializing the cache.
|
|
33
|
+
class Optify::CacheInitOptions
|
|
34
|
+
# A value from `CacheMode`.
|
|
35
|
+
def initialize: () -> Integer?
|
|
36
|
+
| () -> Symbol
|
|
37
|
+
| (?max_size: Integer? max_size, ?mode: Symbol mode) -> void
|
|
38
|
+
end
|
|
39
|
+
|
|
20
40
|
# Information about a feature.
|
|
21
41
|
class Optify::OptionsMetadata < FromHashable
|
|
22
42
|
def aliases: () -> ::Array[String]?
|
|
@@ -119,6 +139,13 @@ end
|
|
|
119
139
|
# Some of the methods shown within this module are implemented in Rust
|
|
120
140
|
# and are declared in this common module to avoid duplicate declarations in different classes.
|
|
121
141
|
module Optify::ProviderModule
|
|
142
|
+
# @param canonical_feature_name [String] A canonical feature name
|
|
143
|
+
# @return Whether the feature has conditions.
|
|
144
|
+
def conditions?: (String canonical_feature_name) -> bool
|
|
145
|
+
|
|
146
|
+
# @return All of the keys and values for the the features.
|
|
147
|
+
def features_with_metadata_json: () -> String
|
|
148
|
+
|
|
122
149
|
# Map an alias or canonical feature name (perhaps derived from a file name) to a canonical feature name.
|
|
123
150
|
# Canonical feature names map to themselves.
|
|
124
151
|
#
|
|
@@ -159,13 +186,9 @@ module Optify::ProviderModule
|
|
|
159
186
|
|
|
160
187
|
def get_options_json_with_preferences: (String key, ::Array[String] feature_names, GetOptionsPreferences preferences) -> String
|
|
161
188
|
|
|
162
|
-
|
|
163
|
-
# @return Whether the feature has conditions.
|
|
164
|
-
def conditions?: (String canonical_feature_name) -> bool
|
|
189
|
+
def init: (?CacheInitOptions? cache_init_options) -> self
|
|
165
190
|
|
|
166
|
-
|
|
167
|
-
# @return `self`.
|
|
168
|
-
def init: () -> self
|
|
191
|
+
def map_feature_names: (::Array[String] feature_names, GetOptionsPreferences preferences) -> ::Array[String?]
|
|
169
192
|
|
|
170
193
|
# Map aliases or canonical feature names (perhaps derived from a file names) to the canonical feature names.
|
|
171
194
|
# Canonical feature names map to themselves.
|
|
@@ -177,9 +200,6 @@ module Optify::ProviderModule
|
|
|
177
200
|
|
|
178
201
|
# @return The metadata for the feature.
|
|
179
202
|
def get_feature_metadata_json: (String canonical_feature_name) -> String?
|
|
180
|
-
|
|
181
|
-
# @return All of the keys and values for the the features.
|
|
182
|
-
def features_with_metadata_json: () -> String
|
|
183
203
|
end
|
|
184
204
|
|
|
185
205
|
# Provides configurations based on keys and enabled feature names.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: optify-config
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.21.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin D. Harris
|
|
@@ -15,28 +15,42 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.9.
|
|
18
|
+
version: 0.9.124
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.9.
|
|
25
|
+
version: 0.9.124
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: optify-from_hash
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.2.
|
|
32
|
+
version: 0.2.2
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.2.
|
|
39
|
+
version: 0.2.2
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: sin_lru_redux
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 2.5.2
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 2.5.2
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: sorbet-runtime
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -91,14 +105,14 @@ dependencies:
|
|
|
91
105
|
requirements:
|
|
92
106
|
- - "~>"
|
|
93
107
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: 1.
|
|
108
|
+
version: 1.82.1
|
|
95
109
|
type: :development
|
|
96
110
|
prerelease: false
|
|
97
111
|
version_requirements: !ruby/object:Gem::Requirement
|
|
98
112
|
requirements:
|
|
99
113
|
- - "~>"
|
|
100
114
|
- !ruby/object:Gem::Version
|
|
101
|
-
version: 1.
|
|
115
|
+
version: 1.82.1
|
|
102
116
|
- !ruby/object:Gem::Dependency
|
|
103
117
|
name: rubocop-sorbet
|
|
104
118
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -175,6 +189,7 @@ files:
|
|
|
175
189
|
- ext/optify_ruby/src/preferences.rs
|
|
176
190
|
- lib/optify.rb
|
|
177
191
|
- lib/optify_ruby/base_config.rb
|
|
192
|
+
- lib/optify_ruby/cache_init_options.rb
|
|
178
193
|
- lib/optify_ruby/get_options_preferences.rb
|
|
179
194
|
- lib/optify_ruby/implementation.rb
|
|
180
195
|
- lib/optify_ruby/options_metadata.rb
|