From ffc59f8de2b6927f203a74f2a44e1b143a22a2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sch=C3=B6nlaub?= Date: Mon, 4 Sep 2023 22:43:51 -0600 Subject: [PATCH 1/3] chore: add type signatures and type checker for CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Schönlaub --- .github/workflows/main.yml | 11 +++ Gemfile.lock | 68 ------------------- lib/openfeature/sdk/metadata.rb | 2 +- openfeature-sdk.gemspec | 1 + sig/openfeature/sdk.rbs | 4 +- sig/openfeature/sdk/_hook.rbs | 31 +++++++++ sig/openfeature/sdk/api.rbs | 22 ++++++ sig/openfeature/sdk/client.rbs | 17 +++++ sig/openfeature/sdk/configuration.rbs | 19 ++++++ sig/openfeature/sdk/metadata.rbs | 12 ++++ .../sdk/provider/no_op_provider.rbs | 32 +++++++++ 11 files changed, 148 insertions(+), 71 deletions(-) delete mode 100644 Gemfile.lock create mode 100644 sig/openfeature/sdk/_hook.rbs create mode 100644 sig/openfeature/sdk/api.rbs create mode 100644 sig/openfeature/sdk/client.rbs create mode 100644 sig/openfeature/sdk/configuration.rbs create mode 100644 sig/openfeature/sdk/metadata.rbs create mode 100644 sig/openfeature/sdk/provider/no_op_provider.rbs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2dd98508..353543b9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,6 +43,17 @@ jobs: - run: bundle install - name: Rubocop run: bundle exec rubocop --color + steep: + runs-on: ubuntu-latest + name: Steep + steps: + - uses: actions/checkout@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2 + - run: bundle install + - name: Steep + run: bundle exec steep check # check the status of other jobs, so we can have a single job dependency for branch protection # https://github.com/community/community/discussions/4324#discussioncomment-3477871 status: diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 5817217a..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,68 +0,0 @@ -PATH - remote: . - specs: - openfeature-sdk (0.1.0) - -GEM - remote: https://rubygems.org/ - specs: - ast (2.4.2) - concurrent-ruby (1.2.2) - diff-lcs (1.5.0) - json (2.6.2) - markly (0.7.0) - parallel (1.22.1) - parser (3.1.2.1) - ast (~> 2.4.1) - rainbow (3.1.1) - rake (13.0.6) - regexp_parser (2.6.0) - rexml (3.2.5) - rspec (3.12.0) - rspec-core (~> 3.12.0) - rspec-expectations (~> 3.12.0) - rspec-mocks (~> 3.12.0) - rspec-core (3.12.0) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-mocks (3.12.0) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-support (3.12.0) - rubocop (1.37.1) - json (~> 2.3) - parallel (~> 1.10) - parser (>= 3.1.2.1) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.23.0, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.23.0) - parser (>= 3.1.1.0) - ruby-progressbar (1.11.0) - unicode-display_width (2.3.0) - -PLATFORMS - arm64-darwin-21 - arm64-darwin-22 - x64-mingw-ucrt - x64-mingw32 - x86_64-darwin-19 - x86_64-darwin-21 - x86_64-darwin-22 - x86_64-linux - -DEPENDENCIES - concurrent-ruby - markly - openfeature-sdk! - rake (~> 13.0) - rspec (~> 3.12.0) - rubocop (~> 1.37.1) - -BUNDLED WITH - 2.3.25 diff --git a/lib/openfeature/sdk/metadata.rb b/lib/openfeature/sdk/metadata.rb index 411ae1d5..e9bf2423 100644 --- a/lib/openfeature/sdk/metadata.rb +++ b/lib/openfeature/sdk/metadata.rb @@ -26,7 +26,7 @@ def initialize(name:, version: nil) end def ==(other) - raise ArgumentError("Expected comparison to be between Metadata object") unless other.is_a?(Metadata) + raise ArgumentError, "Expected comparison to be between Metadata object" unless other.is_a?(Metadata) @name == other.name && @version == other.version end diff --git a/openfeature-sdk.gemspec b/openfeature-sdk.gemspec index f507b227..3f38eecf 100644 --- a/openfeature-sdk.gemspec +++ b/openfeature-sdk.gemspec @@ -35,4 +35,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rake", "~> 13.0" spec.add_development_dependency "rspec", "~> 3.12.0" spec.add_development_dependency "rubocop", "~> 1.37.1" + spec.add_development_dependency "steep", "~> 1.5.0" end diff --git a/sig/openfeature/sdk.rbs b/sig/openfeature/sdk.rbs index e058802f..863cd7ba 100644 --- a/sig/openfeature/sdk.rbs +++ b/sig/openfeature/sdk.rbs @@ -1,5 +1,5 @@ -module Openfeature - module Sdk +module OpenFeature + module SDK VERSION: String # See the writing guide of rbs: https://github.com/ruby/rbs#guides end diff --git a/sig/openfeature/sdk/_hook.rbs b/sig/openfeature/sdk/_hook.rbs new file mode 100644 index 00000000..f82584c8 --- /dev/null +++ b/sig/openfeature/sdk/_hook.rbs @@ -0,0 +1,31 @@ +type flagValue = bool | Numeric | String | Hash[String, untyped] +type flagValueType = :bool | :integer | :float | :string | :object +type evaluationContext = { targeting_key: String? } +type evaluationDetails = { flag_key: String, flag_value?: flagValue } + +type hookContext[T] = { + flag_key: String, + flag_value_type: flagValueType, + evaluation_context: evaluationContext, + default_value: T, + } + +type hookHints = Hash[String, flagValue] + +interface _BeforeHook + def before: (evaluationContext, ?hookHints) -> (evaluationContext | void) +end + +interface _AfterHook[T] + def after: (hookContext[T], evaluationDetails, ?hookHints) -> void +end + +interface _ErrorHook[T] + def error: (hookContext[T], Exception, ?hookHints) -> void +end + +interface _FinallyHook[T] + def finally: (hookContext[T], ?hookHints) -> void +end + +type hook = _BeforeHook | _AfterHook[flagValue] | _ErrorHook[flagValue] | _FinallyHook[flagValue] diff --git a/sig/openfeature/sdk/api.rbs b/sig/openfeature/sdk/api.rbs new file mode 100644 index 00000000..61bf5037 --- /dev/null +++ b/sig/openfeature/sdk/api.rbs @@ -0,0 +1,22 @@ +module OpenFeature + module SDK + + interface _Configuration + def context: () -> void + end + + class API + include _Configuration + extend Forwardable + + attr_reader configuration: Configuration + + def build_client: -> Client + + def configure: () { (Configuration) -> void } -> void + + # Singleton's RBS doesn't quite work + def self.instance: () -> instance + end + end +end diff --git a/sig/openfeature/sdk/client.rbs b/sig/openfeature/sdk/client.rbs new file mode 100644 index 00000000..f44c9983 --- /dev/null +++ b/sig/openfeature/sdk/client.rbs @@ -0,0 +1,17 @@ +module OpenFeature + module SDK + class Client + RESULT_TYPE: Array[Symbol] + SUFFIXES: Array[Symbol] + + @context: evaluationContext + @hooks: Array[hook] + + attr_accessor hooks: Array[hook] + attr_reader metadata: Metadata? + attr_reader provider: untyped + + def initialize: (provider: untyped , client_options: untyped, context: untyped) -> void + end + end +end diff --git a/sig/openfeature/sdk/configuration.rbs b/sig/openfeature/sdk/configuration.rbs new file mode 100644 index 00000000..dc5578c1 --- /dev/null +++ b/sig/openfeature/sdk/configuration.rbs @@ -0,0 +1,19 @@ + +module Concurrent + class Array[T] < ::Array[T] + def initialize: (?::Array[T]) -> void + end +end + +module OpenFeature + module SDK + class Configuration + extend Forwardable + + attr_accessor context: evaluationContext + attr_accessor hooks: [hook] + attr_accessor metadata: Metadata + attr_accessor provider: untyped + end + end +end diff --git a/sig/openfeature/sdk/metadata.rbs b/sig/openfeature/sdk/metadata.rbs new file mode 100644 index 00000000..afe46df6 --- /dev/null +++ b/sig/openfeature/sdk/metadata.rbs @@ -0,0 +1,12 @@ +module OpenFeature + module SDK + class Metadata + attr_reader name: String + attr_reader version: String? + + def initialize: (name: String, ?version: String?) -> void + + def ==: (untyped other) -> untyped + end + end +end diff --git a/sig/openfeature/sdk/provider/no_op_provider.rbs b/sig/openfeature/sdk/provider/no_op_provider.rbs new file mode 100644 index 00000000..ccd6b938 --- /dev/null +++ b/sig/openfeature/sdk/provider/no_op_provider.rbs @@ -0,0 +1,32 @@ +module OpenFeature + module SDK + module Provider + class NoOpProvider + REASON_NO_OP: String + NAME: String + + class ResolutionDetails[T] < ::Struct[T] + attr_reader value(): T + attr_reader reason(): untyped + attr_reader variant(): untyped + attr_reader error_code(): untyped + attr_reader error_message(): untyped + end + + attr_reader metadata: Metadata + + def fetch_boolean_value: (flag_key: String, default_value: bool?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[bool] + + def fetch_string_value: (flag_key: String, default_value: String?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[String] + + def fetch_number_value: (flag_key: String, default_value: Numeric?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[Numeric] + + def fetch_object_value: (flag_key: String, default_value: Hash[untyped, untyped]?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[Hash[untyped, untyped]] + + private + + def no_op:(default_value: flagValue) -> ResolutionDetails[flagValue] + end + end + end +end From c50b1849673c3672b6cf2d067f46a6babfcb24df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sch=C3=B6nlaub?= Date: Fri, 8 Sep 2023 13:51:19 -0600 Subject: [PATCH 2/3] chore: add steepfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Schönlaub --- Steepfile | 10 ++++++++++ sig/openfeature/sdk/provider/no_op_provider.rbs | 16 +++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 Steepfile diff --git a/Steepfile b/Steepfile new file mode 100644 index 00000000..4c720955 --- /dev/null +++ b/Steepfile @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +target :lib do + signature "sig" + check "lib" + library "pathname" + library "forwardable" + library "singleton" + library "uri" +end diff --git a/sig/openfeature/sdk/provider/no_op_provider.rbs b/sig/openfeature/sdk/provider/no_op_provider.rbs index ccd6b938..91f8fd21 100644 --- a/sig/openfeature/sdk/provider/no_op_provider.rbs +++ b/sig/openfeature/sdk/provider/no_op_provider.rbs @@ -4,8 +4,9 @@ module OpenFeature class NoOpProvider REASON_NO_OP: String NAME: String - class ResolutionDetails[T] < ::Struct[T] + def initialize : (value: T, reason: String) -> void + attr_reader value(): T attr_reader reason(): untyped attr_reader variant(): untyped @@ -15,17 +16,14 @@ module OpenFeature attr_reader metadata: Metadata - def fetch_boolean_value: (flag_key: String, default_value: bool?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[bool] - - def fetch_string_value: (flag_key: String, default_value: String?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[String] - - def fetch_number_value: (flag_key: String, default_value: Numeric?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[Numeric] + def fetch_boolean_value: (flag_key: String, default_value: bool, ?evaluation_context: evaluationContext?) -> ResolutionDetails[bool] - def fetch_object_value: (flag_key: String, default_value: Hash[untyped, untyped]?, ?evaluation_context: evaluationContext?) -> ResolutionDetails[Hash[untyped, untyped]] + def fetch_string_value: (flag_key: String, default_value: String, ?evaluation_context: evaluationContext?) -> ResolutionDetails[String] - private + def fetch_number_value: (flag_key: String, default_value: Numeric, ?evaluation_context: evaluationContext?) -> ResolutionDetails[Numeric] - def no_op:(default_value: flagValue) -> ResolutionDetails[flagValue] + def fetch_object_value: (flag_key: String, default_value: Hash[String|Symbol, untyped], ?evaluation_context: evaluationContext?) -> ResolutionDetails[Hash[String|Symbol, untyped]] + def no_op: [X] (X) -> ResolutionDetails[X] end end end From c969c4011175ce51af09470256de0ee6344d4f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Sch=C3=B6nlaub?= Date: Sun, 10 Sep 2023 11:03:57 -0600 Subject: [PATCH 3/3] chore: re-add Gemfile.lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Schönlaub --- Gemfile.lock | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..69a1bd5f --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,112 @@ +PATH + remote: . + specs: + openfeature-sdk (0.1.0) + +GEM + remote: https://rubygems.org/ + specs: + activesupport (7.0.8) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + ast (2.4.2) + concurrent-ruby (1.2.2) + csv (3.2.7) + diff-lcs (1.5.0) + ffi (1.15.5) + ffi (1.15.5-x64-mingw-ucrt) + ffi (1.15.5-x64-mingw32) + fileutils (1.7.1) + i18n (1.14.1) + concurrent-ruby (~> 1.0) + json (2.6.2) + language_server-protocol (3.17.0.3) + listen (3.8.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.5.3) + markly (0.7.0) + minitest (5.20.0) + parallel (1.22.1) + parser (3.1.2.1) + ast (~> 2.4.1) + rainbow (3.1.1) + rake (13.0.6) + rb-fsevent (0.11.2) + rb-inotify (0.10.1) + ffi (~> 1.0) + rbs (3.2.1) + regexp_parser (2.6.0) + rexml (3.2.5) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.0) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-support (3.12.0) + rubocop (1.37.1) + json (~> 2.3) + parallel (~> 1.10) + parser (>= 3.1.2.1) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.23.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.23.0) + parser (>= 3.1.1.0) + ruby-progressbar (1.11.0) + securerandom (0.2.2) + steep (1.5.3) + activesupport (>= 5.1) + concurrent-ruby (>= 1.1.10) + csv (>= 3.0.9) + fileutils (>= 1.1.0) + json (>= 2.1.0) + language_server-protocol (>= 3.15, < 4.0) + listen (~> 3.0) + logger (>= 1.3.0) + parser (>= 3.1) + rainbow (>= 2.2.2, < 4.0) + rbs (>= 3.1.0) + securerandom (>= 0.1) + strscan (>= 1.0.0) + terminal-table (>= 2, < 4) + strscan (3.0.6) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (2.3.0) + +PLATFORMS + arm64-darwin-21 + arm64-darwin-22 + x64-mingw-ucrt + x64-mingw32 + x86_64-darwin-19 + x86_64-darwin-21 + x86_64-darwin-22 + x86_64-linux + +DEPENDENCIES + concurrent-ruby + markly + openfeature-sdk! + rake (~> 13.0) + rspec (~> 3.12.0) + rubocop (~> 1.37.1) + steep (~> 1.5.0) + +BUNDLED WITH + 2.3.25