-
Notifications
You must be signed in to change notification settings - Fork 3
revert: undo config refactor from PR #27 (fixes deadlock) #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,51 +1,92 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "time" | ||
| require "singleton" | ||
| require "forwardable" | ||
| require_relative "context" | ||
| require_relative "audience_matcher" | ||
| require_relative "a_b_smartly_config" | ||
| require_relative "absmartly/version" | ||
| require_relative "default_context_data_provider" | ||
| require_relative "default_context_event_handler" | ||
| require_relative "default_variable_parser" | ||
| require_relative "default_audience_deserializer" | ||
| require_relative "scheduled_thread_pool_executor" | ||
|
|
||
| class ABSmartly | ||
| extend Forwardable | ||
| attr_accessor :context_data_provider, :context_event_handler, | ||
| :variable_parser, :scheduler, :context_event_logger, | ||
| :audience_deserializer, :client | ||
|
|
||
| attr_reader :config | ||
|
|
||
| def_delegators :@config, :context_data_provider, :context_event_handler, :variable_parser, :context_event_logger, | ||
| :audience_deserializer, :client | ||
|
|
||
| def_delegators :@config, :endpoint, :api_key, :application, :environment | ||
| def self.configure_client(&block) | ||
| @@init_http = block | ||
| end | ||
|
|
||
| def self.create(config) | ||
| new(config) | ||
| ABSmartly.new(config) | ||
| end | ||
|
|
||
| def initialize(config) | ||
| config.validate! | ||
| @@init_http = nil | ||
| @context_data_provider = config.context_data_provider | ||
| @context_event_handler = config.context_event_handler | ||
| @context_event_logger = config.context_event_logger | ||
| @variable_parser = config.variable_parser | ||
| @audience_deserializer = config.audience_deserializer | ||
| @scheduler = config.scheduler | ||
|
|
||
| if @context_data_provider.nil? || @context_event_handler.nil? | ||
| @client = config.client | ||
| raise ArgumentError.new("Missing Client instance configuration") if @client.nil? | ||
|
|
||
| if @context_data_provider.nil? | ||
| @context_data_provider = DefaultContextDataProvider.new(@client) | ||
| end | ||
|
|
||
| if @context_event_handler.nil? | ||
| @context_event_handler = DefaultContextEventHandler.new(@client) | ||
| end | ||
| end | ||
|
|
||
| @config = config | ||
| if @variable_parser.nil? | ||
| @variable_parser = DefaultVariableParser.new | ||
| end | ||
|
|
||
| if @audience_deserializer.nil? | ||
| @audience_deserializer = DefaultAudienceDeserializer.new | ||
| end | ||
| if @scheduler.nil? | ||
| @scheduler = ScheduledThreadPoolExecutor.new(1) | ||
| end | ||
| end | ||
|
|
||
| def create_context(context_config) | ||
| Context.create(get_utc_format, context_config, context_data, | ||
| context_data_provider, context_event_handler, context_event_logger, variable_parser, | ||
| AudienceMatcher.new(audience_deserializer)) | ||
| def create_context(config) | ||
| validate_params(config) | ||
| Context.create(get_utc_format, config, @context_data_provider.context_data, | ||
| @context_data_provider, @context_event_handler, @context_event_logger, @variable_parser, | ||
| AudienceMatcher.new(@audience_deserializer)) | ||
| end | ||
|
|
||
| def create_context_with(context_config, data) | ||
| Context.create(get_utc_format, context_config, data, | ||
| context_data_provider, context_event_handler, context_event_logger, variable_parser, | ||
| AudienceMatcher.new(audience_deserializer)) | ||
| def create_context_with(config, data) | ||
| Context.create(get_utc_format, config, data, | ||
| @context_data_provider, @context_event_handler, @context_event_logger, @variable_parser, | ||
| AudienceMatcher.new(@audience_deserializer)) | ||
| end | ||
|
Comment on lines
+66
to
70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing validation in Unlike 🛠️ Suggested fix def create_context_with(config, data)
+ validate_params(config)
Context.create(get_utc_format, config, data,
`@context_data_provider`, `@context_event_handler`, `@context_event_logger`, `@variable_parser`,
AudienceMatcher.new(`@audience_deserializer`))
end🤖 Prompt for AI Agents |
||
|
|
||
| def context_data | ||
| context_data_provider.context_data | ||
| @context_data_provider.context_data | ||
| end | ||
|
|
||
| private | ||
| def get_utc_format | ||
| Time.now.utc.iso8601(3) | ||
| end | ||
|
|
||
| def validate_params(params) | ||
| params.units.each do |key, value| | ||
| unless value.is_a?(String) || value.is_a?(Numeric) | ||
| raise ArgumentError.new("Unit '#{key}' UID is of unsupported type '#{value.class}'. UID must be one of ['string', 'number']") | ||
| end | ||
|
|
||
| if value.to_s.size.zero? | ||
| raise ArgumentError.new("Unit '#{key}' UID length must be >= 1") | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,65 +1,49 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "forwardable" | ||
|
|
||
| require_relative "client" | ||
| require_relative "client_config" | ||
| require_relative "default_context_data_provider" | ||
| require_relative "default_context_event_handler" | ||
| require_relative "default_variable_parser" | ||
| require_relative "default_audience_deserializer" | ||
|
|
||
| class ABSmartlyConfig | ||
| extend Forwardable | ||
|
|
||
| attr_accessor :scheduler | ||
|
|
||
| attr_writer :context_data_provider, :context_event_handler, :audience_deserializer, :variable_parser, :client | ||
|
|
||
| attr_reader :client_config, :context_event_logger | ||
|
|
||
| def_delegators :@client_config, :endpoint, :api_key, :application, :environment | ||
| def_delegators :@client_config, :connect_timeout, :connection_request_timeout, :retry_interval, :max_retries | ||
|
|
||
| attr_accessor :context_data_provider, :context_event_handler, | ||
| :variable_parser, :scheduler, :context_event_logger, | ||
| :client, :audience_deserializer | ||
| def self.create | ||
| new | ||
| ABSmartlyConfig.new | ||
| end | ||
|
|
||
| def initialize | ||
| @client_config = ClientConfig.new | ||
| def context_data_provider=(context_data_provider) | ||
| @context_data_provider = context_data_provider | ||
| self | ||
| end | ||
|
|
||
| def validate! | ||
| raise ArgumentError.new("event logger not configured") if context_event_logger.nil? | ||
| raise ArgumentError.new("failed to initialize client") if client.nil? | ||
| raise ArgumentError.new("failed to initialize context_data_provider") if context_data_provider.nil? | ||
| def context_event_handler=(context_event_handler) | ||
| @context_event_handler = context_event_handler | ||
| self | ||
| end | ||
|
|
||
| def context_event_logger=(context_event_logger) | ||
| if context_event_logger.is_a?(Proc) | ||
| @context_event_logger = ContextEventLoggerCallback.new(context_event_logger) | ||
| else | ||
| @context_event_logger = context_event_logger | ||
| end | ||
| def context_data_provide | ||
| @context_event_handler | ||
| end | ||
|
Comment on lines
+21
to
23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n lib/a_b_smartly_config.rb | head -50Repository: absmartly/ruby-sdk Length of output: 1448 🏁 Script executed: rg -n 'context_data_provide' --type rubyRepository: absmartly/ruby-sdk Length of output: 2005 🏁 Script executed: rg -n 'context_data_provider' --type rubyRepository: absmartly/ruby-sdk Length of output: 1949 Remove dead code method with critical bug. The method 🤖 Prompt for AI Agents |
||
|
|
||
| def variable_parser | ||
| @variable_parser ||= DefaultVariableParser.new | ||
| def variable_parser=(variable_parser) | ||
| @variable_parser = variable_parser | ||
| self | ||
| end | ||
|
|
||
| def audience_deserializer | ||
| @audience_deserializer ||= DefaultAudienceDeserializer.new | ||
| def scheduler=(scheduler) | ||
| @scheduler = scheduler | ||
| self | ||
| end | ||
|
|
||
| def context_data_provider | ||
| @context_data_provider ||= DefaultContextDataProvider.new(client) | ||
| def context_event_logger=(context_event_logger) | ||
| @context_event_logger = context_event_logger | ||
| self | ||
| end | ||
|
|
||
| def context_event_handler | ||
| @context_event_handler ||= DefaultContextEventHandler.new(client) | ||
| def audience_deserializer=(audience_deserializer) | ||
| @audience_deserializer = audience_deserializer | ||
| self | ||
| end | ||
|
|
||
| def client | ||
| @client ||= Client.new(client_config) | ||
| def client=(client) | ||
| @client = client | ||
| self | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,16 +8,16 @@ | |
| require_relative "context_config" | ||
|
|
||
| module Absmartly | ||
| @@init_config = nil | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: rg -n '@@init_config' --type rubyRepository: absmartly/ruby-sdk Length of output: 103 Remove unused class variable This class variable is defined at line 11 but never referenced anywhere in the codebase. Remove it to eliminate dead code. 🤖 Prompt for AI Agents |
||
|
|
||
| class Error < StandardError | ||
| end | ||
|
|
||
| class << self | ||
| MUTEX = Thread::Mutex.new | ||
| attr_accessor :endpoint, :api_key, :application, :environment | ||
|
|
||
| def configure_client | ||
| yield sdk_config | ||
|
|
||
| sdk_config.validate! | ||
| yield self | ||
| end | ||
|
|
||
| def create | ||
|
|
@@ -40,15 +40,24 @@ def context_data | |
| sdk.context_data | ||
| end | ||
|
|
||
| private_constant :MUTEX | ||
|
|
||
| private | ||
| def client_config | ||
| @client_config = ClientConfig.create | ||
| @client_config.endpoint = @endpoint | ||
| @client_config.api_key = @api_key | ||
| @client_config.application = @application | ||
| @client_config.environment = @environment | ||
| @client_config | ||
| end | ||
|
|
||
| def sdk_config | ||
| MUTEX.synchronize { @sdk_config ||= ABSmartlyConfig.create } | ||
| @sdk_config = ABSmartlyConfig.create | ||
| @sdk_config.client = Client.create(client_config) | ||
| @sdk_config | ||
| end | ||
|
|
||
| def sdk | ||
| MUTEX.synchronize { @sdk ||= create } | ||
| @sdk ||= create | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Absmartly | ||
| VERSION = "1.2.1" | ||
| VERSION = "1.2.2" | ||
| end |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,49 +1,80 @@ | ||||||||||||||
| # frozen_string_literal: true | ||||||||||||||
|
|
||||||||||||||
| require "forwardable" | ||||||||||||||
| require_relative "default_http_client" | ||||||||||||||
| require_relative "default_http_client_config" | ||||||||||||||
| require_relative "default_context_data_deserializer" | ||||||||||||||
| require_relative "default_context_event_serializer" | ||||||||||||||
|
|
||||||||||||||
| class Client | ||||||||||||||
| extend Forwardable | ||||||||||||||
| attr_accessor :url, :query, :headers, :http_client, :executor, :deserializer, :serializer | ||||||||||||||
| attr_reader :data_future, :promise, :exception | ||||||||||||||
|
|
||||||||||||||
| attr_accessor :http_client | ||||||||||||||
| attr_reader :config, :data_future, :promise, :exception | ||||||||||||||
|
|
||||||||||||||
| def_delegators :@config, :url, :query, :headers, :deserializer, :serializer | ||||||||||||||
| def_delegator :@http_client, :close | ||||||||||||||
| def_delegator :@promise, :success? | ||||||||||||||
|
|
||||||||||||||
| def self.create(config = nil, http_client = nil) | ||||||||||||||
| new(config, http_client) | ||||||||||||||
| def self.create(config, http_client = nil) | ||||||||||||||
| Client.new(config, http_client || DefaultHttpClient.create(DefaultHttpClientConfig.create)) | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| def initialize(config = nil, http_client = nil) | ||||||||||||||
| @config = config || ClientConfig.new | ||||||||||||||
| @config.validate! | ||||||||||||||
| endpoint = config.endpoint | ||||||||||||||
| raise ArgumentError.new("Missing Endpoint configuration") if endpoint.nil? || endpoint.empty? | ||||||||||||||
|
Comment on lines
16
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Misleading default value for The constructor declares 🐛 Suggested fix: remove misleading default- def initialize(config = nil, http_client = nil)
+ def initialize(config, http_client = nil)
endpoint = config.endpoint🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| api_key = config.api_key | ||||||||||||||
| raise ArgumentError.new("Missing APIKey configuration") if api_key.nil? || api_key.empty? | ||||||||||||||
|
|
||||||||||||||
| application = config.application | ||||||||||||||
| raise ArgumentError.new("Missing Application configuration") if application.nil? || application.empty? | ||||||||||||||
|
|
||||||||||||||
| environment = config.environment | ||||||||||||||
| raise ArgumentError.new("Missing Environment configuration") if environment.nil? || environment.empty? | ||||||||||||||
|
|
||||||||||||||
| @url = "#{endpoint}/context" | ||||||||||||||
| @http_client = http_client | ||||||||||||||
| @deserializer = config.context_data_deserializer | ||||||||||||||
| @serializer = config.context_event_serializer | ||||||||||||||
| @executor = config.executor | ||||||||||||||
|
|
||||||||||||||
| @http_client = http_client || DefaultHttpClient.create(@config.http_client_config) | ||||||||||||||
| @deserializer = DefaultContextDataDeserializer.new if @deserializer.nil? | ||||||||||||||
| @serializer = DefaultContextEventSerializer.new if @serializer.nil? | ||||||||||||||
|
|
||||||||||||||
| @headers = { | ||||||||||||||
| "Content-Type": "application/json", | ||||||||||||||
| "X-API-Key": api_key, | ||||||||||||||
| "X-Application": application, | ||||||||||||||
| "X-Environment": environment, | ||||||||||||||
| "X-Application-Version": "0", | ||||||||||||||
| "X-Agent": "absmartly-ruby-sdk" | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| @query = { | ||||||||||||||
| "application": application, | ||||||||||||||
| "environment": environment | ||||||||||||||
| } | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| def context_data | ||||||||||||||
| @promise = http_client.get(config.url, config.query, config.headers) | ||||||||||||||
| @promise = @http_client.get(@url, @query, @headers) | ||||||||||||||
| unless @promise.success? | ||||||||||||||
| @exception = Exception.new(@promise.body) | ||||||||||||||
| return self | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| content = (@promise.body || {}).to_s | ||||||||||||||
| @data_future = deserializer.deserialize(content, 0, content.size) | ||||||||||||||
| @data_future = @deserializer.deserialize(content, 0, content.size) | ||||||||||||||
| self | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| def publish(event) | ||||||||||||||
| content = serializer.serialize(event) | ||||||||||||||
| response = http_client.put(config.url, nil, config.headers, content) | ||||||||||||||
| content = @serializer.serialize(event) | ||||||||||||||
| response = @http_client.put(@url, nil, @headers, content) | ||||||||||||||
| return Exception.new(response.body) unless response.success? | ||||||||||||||
|
|
||||||||||||||
| response | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| def close | ||||||||||||||
| @http_client.close | ||||||||||||||
| end | ||||||||||||||
|
|
||||||||||||||
| def success? | ||||||||||||||
| @promise.success? | ||||||||||||||
| end | ||||||||||||||
|
Comment on lines
+77
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential The 🛠️ Suggested fix with nil guard def success?
- `@promise.success`?
+ `@promise`&.success? || false
end📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| end | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: absmartly/ruby-sdk
Length of output: 151
Remove unused
@@init_httpclass variable andconfigure_clientmethod.The
@@init_httpclass variable is assigned in theconfigure_clientmethod but is never referenced anywhere in the codebase. It is immediately reset tonilin theinitializemethod and serves no purpose. Remove the dead code to keep the implementation clean.Suggested fix
🤖 Prompt for AI Agents