openfeature-sdk-sorbet 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -1
  3. data/.ruby-version +1 -1
  4. data/.tool-versions +1 -1
  5. data/CHANGELOG.md +21 -2
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +55 -49
  8. data/README.md +23 -6
  9. data/lib/open_feature/client.rb +90 -32
  10. data/lib/open_feature/client_metadata.rb +1 -0
  11. data/lib/open_feature/evaluation_context.rb +6 -8
  12. data/lib/open_feature/evaluation_details.rb +2 -2
  13. data/lib/open_feature/hook.rb +41 -1
  14. data/lib/open_feature/hook_context.rb +30 -0
  15. data/lib/open_feature/hooks.rb +22 -0
  16. data/lib/open_feature/multiple_source_provider.rb +28 -12
  17. data/lib/open_feature/no_op_provider.rb +2 -3
  18. data/lib/open_feature/provider.rb +16 -2
  19. data/lib/open_feature/provider_status.rb +13 -0
  20. data/lib/open_feature.rb +9 -2
  21. data/sorbet/rbi/gems/.gitattributes +1 -0
  22. data/sorbet/rbi/gems/{json@2.6.3.rbi → json@2.7.1.rbi} +80 -60
  23. data/sorbet/rbi/gems/language_server-protocol@3.17.0.3.rbi +14237 -0
  24. data/sorbet/rbi/gems/{minitest@5.18.0.rbi → minitest@5.21.2.rbi} +299 -258
  25. data/sorbet/rbi/gems/{parallel@1.23.0.rbi → parallel@1.24.0.rbi} +8 -1
  26. data/sorbet/rbi/gems/{parser@3.2.2.1.rbi → parser@3.3.0.5.rbi} +438 -2219
  27. data/sorbet/rbi/gems/prism@0.19.0.rbi +25199 -0
  28. data/sorbet/rbi/gems/psych@5.1.2.rbi +1731 -0
  29. data/sorbet/rbi/gems/racc@1.7.3.rbi +157 -0
  30. data/sorbet/rbi/gems/{rake@13.0.6.rbi → rake@13.1.0.rbi} +68 -65
  31. data/sorbet/rbi/gems/{rbi@0.0.16.rbi → rbi@0.1.6.rbi} +628 -755
  32. data/sorbet/rbi/gems/{regexp_parser@2.8.0.rbi → regexp_parser@2.9.0.rbi} +203 -180
  33. data/sorbet/rbi/gems/{rexml@3.2.5.rbi → rexml@3.2.6.rbi} +116 -52
  34. data/sorbet/rbi/gems/{rubocop-ast@1.28.1.rbi → rubocop-ast@1.30.0.rbi} +178 -84
  35. data/sorbet/rbi/gems/{rubocop-minitest@0.31.0.rbi → rubocop-minitest@0.34.5.rbi} +280 -232
  36. data/sorbet/rbi/gems/{rubocop-performance@1.17.1.rbi → rubocop-performance@1.20.2.rbi} +397 -172
  37. data/sorbet/rbi/gems/{rubocop-sorbet@0.7.0.rbi → rubocop-sorbet@0.7.6.rbi} +728 -261
  38. data/sorbet/rbi/gems/{rubocop@1.51.0.rbi → rubocop@1.60.2.rbi} +4006 -1936
  39. data/sorbet/rbi/gems/spoom@1.2.1.rbi +17 -56
  40. data/sorbet/rbi/gems/stringio@3.1.0.rbi +8 -0
  41. data/sorbet/rbi/gems/{tapioca@0.11.6.rbi → tapioca@0.12.0.rbi} +783 -578
  42. data/sorbet/rbi/gems/{thor@1.2.2.rbi → thor@1.3.0.rbi} +775 -395
  43. data/sorbet/rbi/gems/yard-sorbet@0.8.1.rbi +1 -1
  44. data/sorbet/rbi/gems/yard@0.9.34.rbi +2 -2
  45. data/sorbet/rbi/gems/{zeitwerk@2.6.8.rbi → zeitwerk@2.6.12.rbi} +78 -67
  46. data/sorbet/tapioca/config.yml +2 -2
  47. data/sorbet/tapioca/require.rb +3 -1
  48. metadata +36 -31
  49. data/openfeature-sdk-sorbet.gemspec +0 -35
  50. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +0 -1083
  51. data/sorbet/rbi/gems/irb@1.6.4.rbi +0 -342
  52. data/sorbet/rbi/gems/unparser@0.6.7.rbi +0 -4524
  53. /data/sorbet/rbi/gems/{io-console@0.6.0.rbi → io-console@0.7.2.rbi} +0 -0
  54. /data/sorbet/rbi/gems/{reline@0.3.3.rbi → reline@0.4.2.rbi} +0 -0
  55. /data/sorbet/rbi/gems/{unicode-display_width@2.4.2.rbi → unicode-display_width@2.5.0.rbi} +0 -0
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module OpenFeature
5
+ # See https://openfeature.dev/specification/sections/hooks#41-hook-context
6
+ # See Requirement 4.1.1, 4.1.3, 4.1.4
7
+ # TODO: Requirement 4.1.2
8
+ class HookContext < T::Struct
9
+ extend T::Generic
10
+ extend T::Sig
11
+
12
+ include T::Struct::ActsAsComparable
13
+
14
+ Value = type_member
15
+ const :flag_key, String
16
+ const :flag_type, String
17
+ const :evaluation_context, EvaluationContext
18
+ const :default_value, Value
19
+ const :client_metadata, ClientMetadata
20
+ const :provider_metadata, ProviderMetadata
21
+
22
+ # Needed as opposed to .with due to https://sorbet.org/docs/tstruct#from_hash-gotchas
23
+ sig { params(new_context: EvaluationContext).returns(HookContext[Value]) }
24
+ def with_new_evaluation_context(new_context)
25
+ OpenFeature::HookContext.new(flag_key:, flag_type:, default_value:,
26
+ evaluation_context: new_context, client_metadata:,
27
+ provider_metadata:)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module OpenFeature
5
+ # Represents full set of hooks with helper methods for filtering and sequencing each subtype
6
+ class Hooks < T::Struct
7
+ extend T::Generic
8
+ extend T::Sig
9
+ const :global, T::Array[Hook], default: []
10
+ const :provider, T::Array[Hook], default: []
11
+ const :client, T::Array[Hook], default: []
12
+ const :invocation, T::Array[Hook], default: []
13
+
14
+ # See Requirement 4.4.2
15
+ # TODO: when there is >1 subtype of hook will need to filter and not simply re-cast
16
+ # ACHTUNG! T.cast is safe for now but will need to be updated after ^
17
+ sig { returns(T::Array[Hook::BeforeHook]) }
18
+ def before
19
+ T.cast(global + client + invocation + provider, T::Array[Hook::BeforeHook])
20
+ end
21
+ end
22
+ end
@@ -7,19 +7,18 @@ module OpenFeature
7
7
  # The providers will be evaluated in that order and the first
8
8
  # non-error result will be used. If all sources return an error
9
9
  # then the default value is used.
10
- class MultipleSourceProvider
10
+ class MultipleSourceProvider < Provider
11
11
  extend T::Sig
12
12
 
13
- include Provider
14
-
15
13
  sig { params(providers: T::Array[Provider]).void }
16
14
  def initialize(providers:)
17
15
  @providers = providers
16
+ super(ProviderStatus::NotReady)
18
17
  end
19
18
 
20
19
  sig { override.returns(ProviderMetadata) }
21
20
  def metadata
22
- ProviderMetadata.new(name: "Multiple Sources: #{providers.map(&:metadata).map(&:name).join(", ")}")
21
+ ProviderMetadata.new(name: "Multiple Sources: #{providers.map { |provider| provider.metadata.name }.join(", ")}")
23
22
  end
24
23
 
25
24
  sig { override.returns(T::Array[Hook]) }
@@ -27,6 +26,23 @@ module OpenFeature
27
26
  providers.flat_map(&:hooks)
28
27
  end
29
28
 
29
+ sig { override.params(context: EvaluationContext).void }
30
+ def init(context:)
31
+ providers.each { |provider| provider.init(context:) }
32
+ @status = if providers.all? { |provider| provider.status == ProviderStatus::Ready }
33
+ ProviderStatus::Ready
34
+ else
35
+ ProviderStatus::Error
36
+ end
37
+ rescue StandardError
38
+ @status = ProviderStatus::Error
39
+ end
40
+
41
+ sig { override.void }
42
+ def shutdown
43
+ providers.each(&:shutdown)
44
+ end
45
+
30
46
  sig do
31
47
  override
32
48
  .params(
@@ -37,8 +53,8 @@ module OpenFeature
37
53
  .returns(ResolutionDetails[T::Boolean])
38
54
  end
39
55
  def resolve_boolean_value(flag_key:, default_value:, context: nil)
40
- resolve_from_sources(default_value: default_value) do |provider|
41
- provider.resolve_boolean_value(flag_key: flag_key, default_value: default_value, context: context)
56
+ resolve_from_sources(default_value:) do |provider|
57
+ provider.resolve_boolean_value(flag_key:, default_value:, context:)
42
58
  end
43
59
  end
44
60
 
@@ -52,8 +68,8 @@ module OpenFeature
52
68
  .returns(ResolutionDetails[Numeric])
53
69
  end
54
70
  def resolve_number_value(flag_key:, default_value:, context: nil)
55
- resolve_from_sources(default_value: default_value) do |provider|
56
- provider.resolve_number_value(flag_key: flag_key, default_value: default_value, context: context)
71
+ resolve_from_sources(default_value:) do |provider|
72
+ provider.resolve_number_value(flag_key:, default_value:, context:)
57
73
  end
58
74
  end
59
75
 
@@ -67,8 +83,8 @@ module OpenFeature
67
83
  .returns(ResolutionDetails[Structure])
68
84
  end
69
85
  def resolve_structure_value(flag_key:, default_value:, context: nil)
70
- resolve_from_sources(default_value: default_value) do |provider|
71
- provider.resolve_structure_value(flag_key: flag_key, default_value: default_value, context: context)
86
+ resolve_from_sources(default_value:) do |provider|
87
+ provider.resolve_structure_value(flag_key:, default_value:, context:)
72
88
  end
73
89
  end
74
90
 
@@ -82,8 +98,8 @@ module OpenFeature
82
98
  .returns(ResolutionDetails[String])
83
99
  end
84
100
  def resolve_string_value(flag_key:, default_value:, context: nil)
85
- resolve_from_sources(default_value: default_value) do |provider|
86
- provider.resolve_string_value(flag_key: flag_key, default_value: default_value, context: context)
101
+ resolve_from_sources(default_value:) do |provider|
102
+ provider.resolve_string_value(flag_key:, default_value:, context:)
87
103
  end
88
104
  end
89
105
 
@@ -5,11 +5,9 @@ module OpenFeature
5
5
  # Default provider when initializing OpenFeature.
6
6
  # Always returns the default value given.
7
7
  # This will result in a TypeError if the given default value does not have the correct type.
8
- class NoOpProvider
8
+ class NoOpProvider < Provider
9
9
  extend T::Sig
10
10
 
11
- include Provider
12
-
13
11
  sig { override.returns(ProviderMetadata) }
14
12
  attr_reader :metadata
15
13
 
@@ -20,6 +18,7 @@ module OpenFeature
20
18
  def initialize
21
19
  @metadata = T.let(ProviderMetadata.new(name: "No Op Provider"), ProviderMetadata)
22
20
  @hooks = T.let([], T::Array[Hook])
21
+ super()
23
22
  end
24
23
 
25
24
  sig do
@@ -3,10 +3,21 @@
3
3
 
4
4
  module OpenFeature
5
5
  # Interface that providers must implement.
6
- module Provider
6
+ class Provider
7
7
  extend T::Sig
8
8
  extend T::Helpers
9
- interface!
9
+ abstract!
10
+
11
+ sig { returns(ProviderStatus) }
12
+ attr_reader :status
13
+
14
+ sig { params(status: ProviderStatus).void }
15
+ def initialize(status = ProviderStatus::Ready)
16
+ @status = status
17
+ end
18
+
19
+ sig { overridable.params(context: EvaluationContext).void }
20
+ def init(context:); end
10
21
 
11
22
  sig { abstract.returns(ProviderMetadata) }
12
23
  def metadata; end
@@ -14,6 +25,9 @@ module OpenFeature
14
25
  sig { abstract.returns(T::Array[Hook]) }
15
26
  def hooks; end
16
27
 
28
+ sig { overridable.void }
29
+ def shutdown; end
30
+
17
31
  sig do
18
32
  abstract
19
33
  .params(
@@ -0,0 +1,13 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module OpenFeature
5
+ # Indicates what state a provider is in
6
+ class ProviderStatus < T::Enum
7
+ enums do
8
+ NotReady = new
9
+ Ready = new
10
+ Error = new
11
+ end
12
+ end
13
+ end
data/lib/open_feature.rb CHANGED
@@ -19,6 +19,8 @@ module OpenFeature
19
19
 
20
20
  sig { params(provider: Provider).void }
21
21
  def set_provider(provider) # rubocop:disable Naming/AccessorMethodName
22
+ configuration.provider.shutdown
23
+ provider.init(context: configuration.evaluation_context || EvaluationContext.new)
22
24
  configuration.provider = provider
23
25
  end
24
26
 
@@ -42,12 +44,17 @@ module OpenFeature
42
44
  def create_client(name: nil, evaluation_context: nil, hooks: nil)
43
45
  Client.new(
44
46
  provider: configuration.provider,
45
- name: name,
46
- evaluation_context: evaluation_context,
47
+ name:,
48
+ evaluation_context:,
47
49
  hooks: Array(hooks)
48
50
  )
49
51
  end
50
52
 
53
+ sig { void }
54
+ def shutdown
55
+ configuration.provider.shutdown
56
+ end
57
+
51
58
  sig { returns(Configuration) }
52
59
  def configuration
53
60
  Configuration.instance
@@ -0,0 +1 @@
1
+ **/*.rbi linguist-generated=true