optify-config 0.3.1-aarch64-linux → 0.4.1-aarch64-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ca08576e6486f44d10f34b164024a7b1827d9821b45e73a33eb6ff80689cc90
4
- data.tar.gz: 00403717bb667efee520dc03a1a169d0592fc34216802083d2f71fca1158ba72
3
+ metadata.gz: 611e7281161b4cbfb2eda37e7c32426e250e1a87887abc45e816d0de1b813436
4
+ data.tar.gz: 67106b7a8c6a8d60d012bd47e759e3ddf8ee5a1b59ac88884a467cdcf6b9263e
5
5
  SHA512:
6
- metadata.gz: 56f54eb5bcf62da381d6c1397b1858c48228cd270a48a3c33a6c9882fc5f168d3afdbcad163f7069b7a911dbf403188910ce38eaebdf8140e26d5a046f14dd1a
7
- data.tar.gz: 8dfb6107be09d5b942a208be82d9c95bcecd561d41413a722845a939e54bbecde3194dac9803a0542b90e71c1e398e6e8afbbefe7172ea920945cf43ede3fe8d
6
+ metadata.gz: 24b8f1fce24e36953973e0629130413295b41426c686185d03f1e49446eb0fc9679d81ba1e21d07e98870ad2a3930ef5941d9d97ab50fb4b4a10c1ff05523a11
7
+ data.tar.gz: c5fdeb41e5f2fc5aa42dec4fe479c8fec2b9669b46b8851e16bf0b0cd0a4d10046dbf6954bc4d3b215f88485ebed953a91be4ebd093080642f7979e8495b349a
@@ -18,6 +18,7 @@ module Optify
18
18
 
19
19
  # Create a new instance of the class from a hash.
20
20
  #
21
+ # This is a class method that so that it can set members with private setters.
21
22
  # @param hash [Hash] The hash to create the instance from.
22
23
  # @return The new instance.
23
24
  sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
@@ -25,24 +26,66 @@ module Optify
25
26
  result = new
26
27
 
27
28
  hash.each do |key, value|
28
- # TODO: Might need some error handling here, but it should be fine if type signatures are used.
29
- # TODO Handle nilable types.
30
- case value
31
- when Array
32
- sig_return_type = T::Utils.signature_for_method(instance_method(key)).return_type
33
- inner_type = sig_return_type.type.raw_type
34
- value = value.map { |v| inner_type.from_hash(v) } if inner_type.respond_to?(:from_hash)
35
- when Hash
36
- sig_return_type = T::Utils.signature_for_method(instance_method(key)).return_type
37
- if sig_return_type.respond_to?(:raw_type)
38
- type_for_key = sig_return_type.raw_type
39
- value = type_for_key.from_hash(value) if type_for_key.respond_to?(:from_hash)
29
+ sig_return_type = T::Utils.signature_for_method(instance_method(key)).return_type
30
+ value = _convert_value(value, sig_return_type)
31
+ result.instance_variable_set("@#{key}", value)
32
+ end
33
+ result
34
+ end
35
+
36
+ sig { params(value: T.untyped, type: T.untyped).returns(T.untyped) }
37
+ def self._convert_value(value, type)
38
+ case value
39
+ when Array
40
+ type = if type.type.respond_to?(:unwrap_nilable)
41
+ # Handle nilable array.
42
+ type.type.unwrap_nilable
43
+ else
44
+ # Handle array of 1 type.
45
+ type.type
46
+ end
47
+ return value.map { |v| _convert_value(v, type) }
48
+ when Hash
49
+ # Handle nilable hash.
50
+ type = type.unwrap_nilable if type.respond_to?(:unwrap_nilable)
51
+ return _convert_hash(value, type)
52
+ end
53
+
54
+ value
55
+ end
56
+
57
+ sig do
58
+ params(
59
+ hash: T::Hash[T.untyped, T.untyped],
60
+ type: T.untyped
61
+ ).returns(T.untyped)
62
+ end
63
+ def self._convert_hash(hash, type) # rubocop:disable Metrics/PerceivedComplexity
64
+ if type.respond_to?(:raw_type)
65
+ # There is an object for the hash.
66
+ type_for_hash = type.raw_type
67
+ return type_for_hash.from_hash(hash) if type_for_hash.respond_to?(:from_hash)
68
+ elsif type.instance_of?(T::Types::TypedHash)
69
+ # The hash should be a hash, but the values might be objects to convert.
70
+ type_for_values = type.values
71
+
72
+ if type_for_values.respond_to?(:raw_type)
73
+ raw_type_for_values = type_for_values.raw_type
74
+ if raw_type_for_values.respond_to?(:from_hash)
75
+ # Use proper types.
76
+ return hash.transform_values { |v| raw_type_for_values.from_hash(v) }
40
77
  end
41
78
  end
42
79
 
43
- result.instance_variable_set("@#{key}", value)
80
+ # The values are not recognized objects.
81
+ return hash.transform_values { |v| _convert_value(v, type_for_values) }
44
82
  end
45
- result
83
+
84
+ # Fallback to doing nothing.
85
+ # This can happen if there are is no type information for a key in the hash.
86
+ hash
46
87
  end
88
+
89
+ private_class_method :_convert_hash, :_convert_value
47
90
  end
48
91
  end
@@ -2,12 +2,18 @@
2
2
  # typed: strict
3
3
 
4
4
  require 'json'
5
- require 'ostruct'
6
5
 
7
6
  require 'sorbet-runtime'
8
7
 
8
+ require_relative './base_config'
9
+
9
10
  # Tools for working with configurations declared in files.
10
11
  module Optify
12
+ # Options for caching.
13
+ # Only enabling or disabling caching is supported for now.
14
+ class CacheOptions < BaseConfig
15
+ end
16
+
11
17
  # Provides configurations based on keys and enabled feature names.
12
18
  class OptionsProvider
13
19
  extend T::Sig
@@ -29,24 +35,62 @@ module Optify
29
35
  # @param feature_names [Array<String>] The enabled feature names to use to build the options.
30
36
  # @param config_class [ConfigType] The class of the configuration to return.
31
37
  # It is recommended to use a class that extends `Optify::BaseConfig` because it implements `from_hash`.
38
+ # @param cache_options Set this if caching is desired. Only very simple caching is supported for now.
32
39
  # @return [ConfigType] The options.
33
40
  sig do
34
41
  type_parameters(:Config)
35
42
  .params(
36
43
  key: String,
37
44
  feature_names: T::Array[String],
38
- config_class: T::Class[T.type_parameter(:Config)]
45
+ config_class: T::Class[T.type_parameter(:Config)],
46
+ cache_options: T.nilable(CacheOptions)
39
47
  )
40
48
  .returns(T.type_parameter(:Config))
41
49
  end
42
- def get_options(key, feature_names, config_class)
43
- options_json = get_options_json(key, feature_names)
44
- h = JSON.parse(options_json, object_class: Hash)
50
+ def get_options(key, feature_names, config_class, cache_options = nil)
51
+ return get_options_with_cache(key, feature_names, config_class, cache_options) if cache_options
52
+
45
53
  unless config_class.respond_to?(:from_hash)
46
- raise NotImplementedError, 'The provided config class does not implement to `from_hash`.'
54
+ raise NotImplementedError,
55
+ "The provided config class must implement `from_hash` as a class method
56
+ in order to be converted.
57
+ Recommended: extend `Optify::BaseConfig`."
47
58
  end
48
59
 
49
- T.unsafe(config_class).from_hash(h)
60
+ options_json = get_options_json(key, feature_names)
61
+ hash = JSON.parse(options_json)
62
+ T.unsafe(config_class).from_hash(hash)
63
+ end
64
+
65
+ private
66
+
67
+ NOT_FOUND_IN_CACHE_SENTINEL = Object.new
68
+
69
+ sig do
70
+ type_parameters(:Config)
71
+ .params(
72
+ key: String,
73
+ feature_names: T::Array[String],
74
+ config_class: T::Class[T.type_parameter(:Config)],
75
+ _cache_options: CacheOptions
76
+ )
77
+ .returns(T.type_parameter(:Config))
78
+ end
79
+ def get_options_with_cache(key, feature_names, config_class, _cache_options)
80
+ # Cache directly in Ruby instead of Rust because:
81
+ # * Avoid any possible conversion overhead.
82
+ # * Memory management: probably better to do it in Ruby for a Ruby app and avoid memory in Rust.
83
+ # TODO: Consider aliases when caching. Right now, they are only visible in Rust
84
+ # and we don't want the cache in Rust because we won't to avoid any conversion overhead.
85
+ @cache ||= T.let({}, T.nilable(T::Hash[T.untyped, T.untyped]))
86
+ cache_key = [key, feature_names, config_class]
87
+ result = @cache.fetch(cache_key, NOT_FOUND_IN_CACHE_SENTINEL)
88
+ return result unless result.equal?(NOT_FOUND_IN_CACHE_SENTINEL)
89
+
90
+ result = get_options(key, feature_names, config_class)
91
+ T.unsafe(result).freeze if T.unsafe(result).respond_to?(:freeze)
92
+
93
+ @cache[cache_key] = result
50
94
  end
51
95
  end
52
96
 
data/rbi/optify.rbi CHANGED
@@ -14,12 +14,18 @@ module Optify
14
14
 
15
15
  # Create a new instance of the class from a hash.
16
16
  #
17
+ # This is a class method that so that it can set members with private setters.
17
18
  # @param hash [Hash] The hash to create the instance from.
18
19
  # @return The new instance.
19
20
  sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
20
21
  def self.from_hash(hash); end
21
22
  end
22
23
 
24
+ # Options for caching.
25
+ # Only enabling or disabling caching is supported for now.
26
+ class CacheOptions < BaseConfig
27
+ end
28
+
23
29
  # Provides configurations based on keys and enabled feature names.
24
30
  class OptionsProvider
25
31
  # Fetches options based on the provided key and feature names.
@@ -28,17 +34,19 @@ module Optify
28
34
  # @param feature_names [Array<String>] The enabled feature names to use to build the options.
29
35
  # @param config_class [ConfigType] The class of the configuration to return.
30
36
  # It is recommended to use a class that extends `Optify::BaseConfig` because it implements `from_hash`.
37
+ # @param cache_options Set this if caching is desired. Only very simple caching is supported for now.
31
38
  # @return [ConfigType] The options.
32
39
  sig do
33
40
  type_parameters(:Config)
34
41
  .params(
35
42
  key: String,
36
43
  feature_names: T::Array[String],
37
- config_class: T::Class[T.type_parameter(:Config)]
44
+ config_class: T::Class[T.type_parameter(:Config)],
45
+ cache_options: T.nilable(CacheOptions)
38
46
  )
39
47
  .returns(T.type_parameter(:Config))
40
48
  end
41
- def get_options(key, feature_names, config_class); end
49
+ def get_options(key, feature_names, config_class, cache_options = nil); end
42
50
 
43
51
  # Fetches options in JSON format based on the provided key and feature names.
44
52
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optify-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.1
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Justin D. Harris
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-07 00:00:00.000000000 Z
11
+ date: 2025-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -89,9 +89,9 @@ extensions: []
89
89
  extra_rdoc_files: []
90
90
  files:
91
91
  - lib/optify.rb
92
+ - lib/optify_ruby/3.0/optify_ruby.so
92
93
  - lib/optify_ruby/base_config.rb
93
94
  - lib/optify_ruby/implementation.rb
94
- - lib/optify_ruby/optify_ruby.so
95
95
  - rbi/optify.rbi
96
96
  homepage: https://github.com/juharris/optify
97
97
  licenses:
@@ -107,10 +107,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '3.4'
110
+ version: '3.0'
111
111
  - - "<"
112
112
  - !ruby/object:Gem::Version
113
- version: 3.5.dev
113
+ version: 3.1.dev
114
114
  required_rubygems_version: !ruby/object:Gem::Requirement
115
115
  requirements:
116
116
  - - ">="