optify-config 0.2.0-arm64-darwin-23 → 0.4.0-arm64-darwin-23

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: 0f56ac9cfd62424015ae1a1219f17a95c607ddc1f707d2695d264ecf6badf635
4
- data.tar.gz: 8a96be88160561676ec121b574950f5e6d5bad12ab02f2e0eb6a8c031e48adaf
3
+ metadata.gz: a854df741a2d742bf02aa203680cb8e009d650c94e6df0bd7cb8e56c884c408d
4
+ data.tar.gz: b77a4cb44c75fb188213b359b22140a26e80540e2795e92d9dd3a26b8faea308
5
5
  SHA512:
6
- metadata.gz: bb1cf2ceb0811c3a1972c5be3e66d1d04fb22fe48352741ebf543ee58a55cc14db6e1de5a4b3f022e58b1508343721e55695aa78efdd632f3dabea0e44c6f83c
7
- data.tar.gz: 16041070d1449b7afa3face9fdf531785d440ec96b1048826517101d0c8c64d8ba7a6024ae69455f6aa12666a6bd8709f4506a9e362a8642425c4ed67715d4ea
6
+ metadata.gz: bcf0e1b405a0c949670f13977586305d8ae4e232a976d0be6449d238c1e5850b67fe84c785f661f821f2ad11f5a6df3800e57b19d2e0313c0bdbe00e6464eab3
7
+ data.tar.gz: 045fc428b2459348d422a8fefaf8a5a5c5d606416a9fbd990fdf44e7e2cb8b1f78bef81d28619b415fa320753fd3555d421c8849712718c537a5fce3a99f6f08
data/lib/optify.rb CHANGED
@@ -2,10 +2,12 @@
2
2
  # typed: strict
3
3
 
4
4
  # The implementation to use directly Ruby and with types declared.
5
- require_relative "optify_ruby/implementation"
6
-
5
+ require_relative 'optify_ruby/implementation'
7
6
 
8
7
  # The implementation in Rust which redefines some methods.
9
8
  # This yields some warnings, but we should redeclare the methods in Ruby to help with type checking anyway.
10
- # Warnings about redefining methods are normal and can be ignored because the implementations in Ruby are not implemented and only exist to help with type checking.
11
- require_relative "optify_ruby/optify_ruby"
9
+ # Warnings about redefining methods are normal and can be ignored
10
+ # because the implementations in Ruby are not implemented and only exist to help with type checking.
11
+ require_relative 'optify_ruby/optify_ruby'
12
+
13
+ require_relative 'optify_ruby/base_config'
@@ -0,0 +1,48 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'sorbet-runtime'
5
+ require 'tapioca'
6
+
7
+ module Optify
8
+ # A base class for classes from configuration files.
9
+ # Classes that derive from this can easily be used with `Optify::OptionsProvider.get_options`
10
+ # because they will have an implementation of `from_hash` that works recursively.
11
+ # This class is a work in progress with minimal error handling
12
+ # and doesn't handle certain cases such as nilable types yet.
13
+ # It may be moved to another gem in the future.
14
+ class BaseConfig
15
+ extend T::Sig
16
+ extend T::Helpers
17
+ abstract!
18
+
19
+ # Create a new instance of the class from a hash.
20
+ #
21
+ # @param hash [Hash] The hash to create the instance from.
22
+ # @return The new instance.
23
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
24
+ def self.from_hash(hash)
25
+ result = new
26
+
27
+ 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)
40
+ end
41
+ end
42
+
43
+ result.instance_variable_set("@#{key}", value)
44
+ end
45
+ result
46
+ end
47
+ end
48
+ 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
@@ -27,11 +33,62 @@ module Optify
27
33
  #
28
34
  # @param key [String] the key to fetch options for.
29
35
  # @param feature_names [Array<String>] The enabled feature names to use to build the options.
30
- # @return [OpenStruct] the options.
31
- sig { params(key: String, feature_names: T::Array[String]).returns(OpenStruct) }
32
- def get_options(key, feature_names)
36
+ # @param config_class [ConfigType] The class of the configuration to return.
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.
39
+ # @return [ConfigType] The options.
40
+ sig do
41
+ type_parameters(:Config)
42
+ .params(
43
+ key: String,
44
+ feature_names: T::Array[String],
45
+ config_class: T::Class[T.type_parameter(:Config)],
46
+ cache_options: T.nilable(CacheOptions)
47
+ )
48
+ .returns(T.type_parameter(:Config))
49
+ end
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
+
33
53
  options_json = get_options_json(key, feature_names)
34
- JSON.parse(options_json, object_class: OpenStruct)
54
+ h = JSON.parse(options_json, object_class: Hash)
55
+ unless config_class.respond_to?(:from_hash)
56
+ raise NotImplementedError,
57
+ "The provided config class must implement `from_hash` as a class method
58
+ in order to be converted."
59
+ end
60
+
61
+ T.unsafe(config_class).from_hash(h)
62
+ end
63
+
64
+ private
65
+
66
+ NOT_FOUND_IN_CACHE_SENTINEL = Object.new
67
+
68
+ sig do
69
+ type_parameters(:Config)
70
+ .params(
71
+ key: String,
72
+ feature_names: T::Array[String],
73
+ config_class: T::Class[T.type_parameter(:Config)],
74
+ _cache_options: CacheOptions
75
+ )
76
+ .returns(T.type_parameter(:Config))
77
+ end
78
+ def get_options_with_cache(key, feature_names, config_class, _cache_options)
79
+ # Cache directly in Ruby instead of Rust because:
80
+ # * Avoid any possible conversion overhead.
81
+ # * Memory management: probably better to do it in Ruby for a Ruby app and avoid memory in Rust.
82
+ # TODO: Handle aliases. Right now, they are only visible in Rust
83
+ # and we don't want the cache in Rust because we won't to avoid any conversion overhead.
84
+ @cache ||= T.let({}, T.nilable(T::Hash[T.untyped, T.untyped]))
85
+ cache_key = [key, feature_names, config_class]
86
+ result = @cache.fetch(cache_key, NOT_FOUND_IN_CACHE_SENTINEL)
87
+ return result unless result.equal?(NOT_FOUND_IN_CACHE_SENTINEL)
88
+
89
+ result = get_options(key, feature_names, config_class)
90
+
91
+ @cache[cache_key] = result
35
92
  end
36
93
  end
37
94
 
@@ -56,4 +113,4 @@ module Optify
56
113
  raise NotImplementedError
57
114
  end
58
115
  end
59
- end
116
+ end
data/rbi/optify.rbi ADDED
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+ # typed: strong
3
+
4
+ # Tools for working with configurations declared in files.
5
+ module Optify
6
+ # A base class for classes from configuration files.
7
+ # Classes that derive from this can easily be used with `Optify::OptionsProvider.get_options`
8
+ # because they will have an implementation of `from_hash` that works recursively.
9
+ # This class is a work in progress with minimal error handling
10
+ # and doesn't handle certain cases such as nilable types yet.
11
+ # It may be moved to another gem in the future.
12
+ class BaseConfig
13
+ abstract!
14
+
15
+ # Create a new instance of the class from a hash.
16
+ #
17
+ # @param hash [Hash] The hash to create the instance from.
18
+ # @return The new instance.
19
+ sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T.attached_class) }
20
+ def self.from_hash(hash); end
21
+ end
22
+
23
+ # Options for caching.
24
+ # Only enabling or disabling caching is supported for now.
25
+ class CacheOptions < BaseConfig
26
+ end
27
+
28
+ # Provides configurations based on keys and enabled feature names.
29
+ class OptionsProvider
30
+ # Fetches options based on the provided key and feature names.
31
+ #
32
+ # @param key [String] the key to fetch options for.
33
+ # @param feature_names [Array<String>] The enabled feature names to use to build the options.
34
+ # @param config_class [ConfigType] The class of the configuration to return.
35
+ # It is recommended to use a class that extends `Optify::BaseConfig` because it implements `from_hash`.
36
+ # @return [ConfigType] The options.
37
+ sig do
38
+ type_parameters(:Config)
39
+ .params(
40
+ key: String,
41
+ feature_names: T::Array[String],
42
+ config_class: T::Class[T.type_parameter(:Config)],
43
+ cache_options: T.nilable(CacheOptions)
44
+ )
45
+ .returns(T.type_parameter(:Config))
46
+ end
47
+ def get_options(key, feature_names, config_class, cache_options = nil); end
48
+
49
+ # Fetches options in JSON format based on the provided key and feature names.
50
+ #
51
+ # @param key [String] the key to fetch options for.
52
+ # @param feature_names [Array<String>] The enabled feature names to use to build the options.
53
+ # @return [String] the options in JSON.
54
+ sig { params(key: String, feature_names: T::Array[String]).returns(String) }
55
+ def get_options_json(key, feature_names); end
56
+ end
57
+
58
+ # A builder for creating an `OptionsProvider` instance.
59
+ class OptionsProviderBuilder
60
+ # Adds a directory to the builder.
61
+ #
62
+ # @param path [String] The path of the directory to add.
63
+ # @return [OptionsProviderBuilder] `self`.
64
+ sig { params(path: String).returns(OptionsProviderBuilder) }
65
+ def add_directory(path); end
66
+
67
+ # @return [OptionsProvider] A newly built `OptionsProvider`.
68
+ sig { returns(OptionsProvider) }
69
+ def build; end
70
+ end
71
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optify-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: arm64-darwin-23
6
6
  authors:
7
7
  - Justin D. Harris
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-03 00:00:00.000000000 Z
11
+ date: 2025-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.5.11796
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: '0'
26
+ version: 0.5.11796
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake-compiler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -42,60 +42,63 @@ dependencies:
42
42
  name: sorbet
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.5.11796
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.5.11796
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: tapioca
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 0.16.8
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 0.16.8
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: test-unit
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 3.6.7
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
83
- description: Simplifies getting the right configuration options for a process using
84
- pre-loaded configurations from files to manage options for experiments or flights.
82
+ version: 3.6.7
83
+ description: |-
84
+ Simplifies getting the right configuration options for a process using pre-loaded configurations
85
+ from files to manage options for experiments or flights.
85
86
  email:
86
87
  executables: []
87
88
  extensions: []
88
89
  extra_rdoc_files: []
89
90
  files:
90
91
  - lib/optify.rb
92
+ - lib/optify_ruby/base_config.rb
91
93
  - lib/optify_ruby/implementation.rb
92
94
  - lib/optify_ruby/optify_ruby.bundle
95
+ - rbi/optify.rbi
93
96
  homepage: https://github.com/juharris/optify
94
97
  licenses:
95
98
  - MIT
96
99
  metadata:
97
- source_code_uri: https://github.com/juharris/optify
98
100
  bug_tracker_uri: https://github.com/juharris/optify/issues
101
+ source_code_uri: https://github.com/juharris/optify
99
102
  post_install_message:
100
103
  rdoc_options: []
101
104
  require_paths: