Skip to content
Draft
6 changes: 5 additions & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ jobs:
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.0"
ruby-version: "3.1"
bundler-cache: true
- name: Run RuboCop
run: bundle exec rubocop
- name: Run Steep / RBS Type signature verification
run: |
bundle exec steep check --steepfile=./Steepfile --severity-level=error | ruby -pe 'sub(/^(.+):(\d+):(\d+): (.+)$/, %q{::error file=\1,line=\2,col=\3::\4})'
shell: bash

test:
runs-on: ${{ matrix.os }}-latest
Expand Down
35 changes: 35 additions & 0 deletions Steepfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
D = Steep::Diagnostic

target :lib do
signature "*.rbs"

# NOTE: All client-exposed methods/types should now have type signatures / rbs support
check "lib/unleash/client.rb"
check "lib/unleash/context.rb"
check "lib/unleash/variant.rb"
check "lib/unleash/scheduled_executor.rb"

# TODO: add signatures to the rest
# Mostly internal SDK files.
ignore "lib/unleash/bootstrap"
ignore "lib/unleash/strategy/*.rb"
ignore "lib/unleash/util"

ignore "lib/unleash/constraint.rb"
ignore "lib/unleash/feature_toggle.rb"
ignore "lib/unleash/metrics.rb"
ignore "lib/unleash/metrics_reporter.rb"
ignore "lib/unleash/toggle_fetcher.rb"
ignore "lib/unleash/variant_definition.rb"
ignore "lib/unleash/variant_override.rb"

# library "pathname", "set" # Standard libraries
# library "strong_json" # Gems

# configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
# configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
configure_code_diagnostics do |hash| # You can setup everything yourself
hash[D::Ruby::NoMethod] = :information
hash[D::Ruby::UnsupportedSyntax] = :information
end
end
39 changes: 39 additions & 0 deletions lib/unleash/client.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Unleash
class Client
attr_accessor fetcher_scheduled_executor: ScheduledExecutor

attr_accessor metrics_scheduled_executor: ScheduledExecutor

def initialize: (*untyped opts) -> void

def is_enabled?: (String feature, ?Context? context, ?bool default_value_param) ?{ () -> bool } -> bool

# enabled? is a more ruby idiomatic method name than is_enabled?
alias enabled? is_enabled?

# execute a code block (passed as a parameter), if is_enabled? is true.
def if_enabled: (String feature, ?Context context, ?bool default_value) { (untyped) -> bool } -> (untyped | nil)

def get_variant: (String feature, ?Context context, ?Variant fallback_variant) -> Variant

# safe shutdown: also flush metrics to server and toggles to disk
def shutdown: () -> nil

# quick shutdown: just kill running threads
def shutdown!: () -> nil

private

def info: () -> { appName: String, instanceId: String, sdkVersion: String, strategies: Array[String], started: String, interval: Integer }

def start_toggle_fetcher: () -> nil

def start_metrics: () -> nil

def register: () -> nil

def disabled_variant: () -> Variant

def first_fetch_is_eager: () -> bool
end
end
21 changes: 21 additions & 0 deletions lib/unleash/context.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Unleash
class Context
ATTRS: ::Array[:app_name | :environment | :user_id | :session_id | :remote_address | :current_time]

def initialize: (?::Hash[String, any] params) -> Context

def to_s: () -> ::String

def get_by_name: ((String | Symbol) name) -> any

def include?: ((String | Symbol) name) -> bool

private

# Method to fetch values from hash for two types of keys: string in camelCase and symbol in snake_case
def value_for: ((String | Symbol) key, Hash[String, any] params, ?any? default_value) -> any

# converts CamelCase to snake_case
def underscore: ((String | Symbol) camel_cased_word) -> String
end
end
29 changes: 29 additions & 0 deletions lib/unleash/scheduled_executor.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Unleash
class ScheduledExecutor
attr_accessor name: String

attr_accessor interval: Numeric

attr_accessor max_exceptions: ::Integer

attr_accessor retry_count: ::Integer

attr_accessor thread: (Thread | nil)

attr_accessor immediate_execution: bool

def initialize: (String name, untyped interval, ?::Integer max_exceptions, ?bool immediate_execution) -> void

def run: () ?{ () -> nil } -> nil

def running?: () -> bool

def exit: () -> nil

private

def run_blk: () { () -> nil } -> nil

def exceeded_max_exceptions?: () -> bool
end
end
15 changes: 15 additions & 0 deletions lib/unleash/variant.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Unleash
class Variant
attr_accessor name: String

attr_accessor enabled: bool

attr_accessor payload: String

def initialize: (?::Hash[String, String] params) -> void

def to_s: () -> ::String

def ==: (Variant other) -> bool
end
end
8 changes: 8 additions & 0 deletions unleash-client.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,12 @@ Gem::Specification.new do |spec|

spec.add_development_dependency "simplecov", "~> 0.21.2"
spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"

# NOTE: only require rbs/steep in supported ruby versions. In EOL ruby/jruby, just ignore.
# rubocop:disable Gemspec/RubyVersionGlobalsUsage
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1') && RUBY_ENGINE != 'jruby'
spec.add_development_dependency "rbs", "~> 3.8.1"
spec.add_development_dependency "steep", "~> 1.9.3"
end
# rubocop:enable Gemspec/RubyVersionGlobalsUsage
end
Loading