vwo-fme-ruby-sdk 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8f333409ec82d99443663437007b9b0934fe205e07e1cef53d905c911faf7980
4
+ data.tar.gz: 7a866f482484ff481d503a90bca9534bbce6832daf99e81a1791a36d0e41e290
5
+ SHA512:
6
+ metadata.gz: 0db232a732e10984da13efbc1b47a4e9bb72103a9453da6f910e4c76b43f35b507db4fbd556175e8428c10d9dd17c89fc45b8d097435b1e2133b247d3e101686
7
+ data.tar.gz: 80119347d3b874637c6af47aa2ee91bdc2fe095a665c4b63de3d8761466e7e587557ad42c24cae879630a06fff211decec14328441fbf0cbf8175ef23ab389a2
@@ -0,0 +1,24 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module VWO
16
+ module Constants
17
+ HTTPS_PROTOCOL = 'https://'
18
+ BASE_URL = 'dev.visualwebsiteoptimizer.com'
19
+ ENDPOINT_GET_FLAG = '/server-side/getFlag'
20
+ ENDPOINT_TRACK_EVENT = '/server-side/trackEvent'
21
+ ENDPOINT_SET_ATTRIBUTE = '/server-side/setAttribute'
22
+ ENDPOINT_ACCOUNT_SETTINGS = '/server-side/v2-settings'
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module VWO
16
+ class FeatureFlagResponse
17
+ def initialize(is_enabled, variables = [])
18
+ @is_enabled = is_enabled
19
+ @variables = variables
20
+ end
21
+
22
+ # Method to check if the flag is enabled
23
+ def is_enabled
24
+ @is_enabled
25
+ end
26
+
27
+ # Method to get all variables
28
+ def get_variables
29
+ @variables
30
+ end
31
+
32
+ # Method to get a specific variable by key, with a fallback default value
33
+ def get_variable(key, default_value)
34
+ variable = @variables.find { |var| var['key'] == key }
35
+ variable ? variable['value'] : default_value
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'logger'
16
+
17
+ module LoggerHelper
18
+ # Singleton logger instance
19
+ def self.logger
20
+ @logger ||= Logger.new(STDOUT) # You can log to a file like 'application.log'
21
+ @logger.level = Logger::DEBUG # Set the default logging level
22
+ @logger
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'net/http'
16
+ require 'uri'
17
+ require 'json'
18
+
19
+ module VWO
20
+ module Utils
21
+ # The Request class is responsible for sending HTTP GET and POST requests.
22
+ # It uses a base URL that can be set once and then reused for all subsequent requests.
23
+ class Request
24
+ @@base_url = '' # Class variable to store the base URL for requests.
25
+
26
+ # Sets the base URL to be used for making HTTP requests.
27
+ #
28
+ # @param [String] url The base URL to be used for all requests.
29
+ def self.set_base_url(url)
30
+ @@base_url = url
31
+ end
32
+
33
+ # Sends an HTTP GET request to a specific endpoint using the set base URL.
34
+ #
35
+ # @param [String] endpoint The API endpoint to send the GET request to.
36
+ # @return [String, nil] Returns the response body if the request is successful, or nil if it fails.
37
+ def self.send_get_request(endpoint)
38
+ # Combine the base URL and endpoint into a full URI.
39
+ full_url = URI.join(@@base_url, endpoint)
40
+
41
+ # Send the GET request and capture the response.
42
+ response = Net::HTTP.get_response(full_url)
43
+
44
+ # Check if the response was successful (status code 2xx).
45
+ if response.is_a?(Net::HTTPSuccess)
46
+ response.body # Return the response body if successful.
47
+ else
48
+ # Log an error message if the request fails and return nil.
49
+ puts "GET request failed with response code: #{response.code}"
50
+ nil
51
+ end
52
+ end
53
+
54
+ # Sends an HTTP POST request with JSON data to a specific endpoint using the set base URL.
55
+ #
56
+ # @param [String] endpoint The API endpoint to send the POST request to.
57
+ # @param [Hash] data The data to be sent as the POST request body, in JSON format.
58
+ # @return [String, nil] Returns the response body if the request is successful, or nil if it fails.
59
+ def self.send_post_request(endpoint, data)
60
+ # Combine the base URL and endpoint into a full URI.
61
+ full_url = URI.join(@@base_url, endpoint)
62
+
63
+ # Initialize a new HTTP object for the specified host and port.
64
+ http = Net::HTTP.new(full_url.host, full_url.port)
65
+
66
+ # Enable SSL (HTTPS) if the URL scheme is 'https'.
67
+ http.use_ssl = true if full_url.scheme == 'https'
68
+
69
+ # Create a new POST request object, setting the content type to JSON.
70
+ request = Net::HTTP::Post.new(full_url, { 'Content-Type' => 'application/json' })
71
+
72
+ # Convert the data to JSON and set it as the request body.
73
+ request.body = data.to_json
74
+
75
+ # Send the POST request and capture the response.
76
+ response = http.request(request)
77
+
78
+ # Check if the response was successful (status code 2xx).
79
+ if response.is_a?(Net::HTTPSuccess)
80
+ response.body # Return the response body if successful.
81
+ else
82
+ # Log an error message if the request fails and return nil.
83
+ puts "POST request failed with response code: #{response.code}"
84
+ nil
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'constants'
16
+ require_relative 'utils/request' # Include your request utilities
17
+
18
+ module VWO
19
+ class VWOBuilder
20
+ def initialize(options)
21
+ @options = options
22
+ end
23
+
24
+ # Initializes the HTTP client for VWOBuilder
25
+ def init_client
26
+ Utils::Request.set_base_url(@options[:gateway_service_url] || Constants::HTTPS_PROTOCOL + Constants::BASE_URL)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,142 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'json'
16
+ require_relative 'utils/logger_helper'
17
+ require_relative 'constants'
18
+ require_relative 'utils/request'
19
+ require_relative 'utils/feature_flag_response'
20
+
21
+ module VWO
22
+ # VWOClient class provides methods to interact with the VWO feature flag system,
23
+ # including retrieving feature flags, tracking events, and setting attributes.
24
+ class VWOClient
25
+ # Makes the `options` instance variable private and only accessible within the class.
26
+ private attr_reader :options
27
+
28
+ # Initializes a new instance of the VWOClient.
29
+ #
30
+ # @param [Hash] options Configuration options like account_id and sdk_key.
31
+ def initialize(options)
32
+ @options = options
33
+ end
34
+
35
+ # Fetches a feature flag for a given feature_key and context.
36
+ #
37
+ # @param [String] feature_key The unique identifier for the feature flag.
38
+ # @param [Hash] context The context data, which must include a `:id` for user identification.
39
+ #
40
+ # @return [FeatureFlagResponse] Returns a FeatureFlagResponse with the status of the feature flag and any associated variables.
41
+ # Returns `isEnabled: false` and empty variables if any error occurs.
42
+ #
43
+ # @raise [StandardError] Raises an error if `feature_key`, `context`, or `userId` are missing or invalid.
44
+ def get_flag(feature_key, context)
45
+ # Raise an error if the SDK is not initialized with options.
46
+ raise 'VWO is not initialized' if @options.nil?
47
+
48
+ # Validate that feature_key and context are present, and userId is in context.
49
+ raise 'feature_key is required to get the feature flag' if feature_key.nil? || feature_key.empty?
50
+ raise 'context is required to get the feature flag' if context.nil?
51
+ raise 'userId is required for flag evaluation, please provide id in context' if context[:id].nil? || context[:id].empty?
52
+
53
+ # Add the feature key to the context.
54
+ context['featureKey'] = feature_key
55
+
56
+ # Construct the API endpoint for getting the feature flag.
57
+ endpoint = "#{Constants::ENDPOINT_GET_FLAG}?accountId=#{@options[:account_id]}&sdkKey=#{@options[:sdk_key]}"
58
+
59
+ # Send a POST request to retrieve the feature flag.
60
+ response = Utils::Request.send_post_request(endpoint, context)
61
+
62
+ # If a response is received, parse it and return a FeatureFlagResponse.
63
+ if response
64
+ parsed_response = JSON.parse(response)
65
+ return FeatureFlagResponse.new(parsed_response['isEnabled'], parsed_response['variables'])
66
+ else
67
+ # Return a default disabled response if no response was received.
68
+ return FeatureFlagResponse.new(false, [])
69
+ end
70
+ rescue StandardError => e
71
+ # Log the error and return a default FeatureFlagResponse with `isEnabled: false`.
72
+ LoggerHelper.logger.error("Error in get_flag: #{e.message}")
73
+ return FeatureFlagResponse.new(false, [])
74
+ end
75
+
76
+ # Tracks an event for a given event_name and context.
77
+ #
78
+ # @param [String] event_name The name of the event to track.
79
+ # @param [Hash] context The context data, which must include a `:id` for user identification.
80
+ # @param [Hash] event_properties Optional properties related to the event.
81
+ #
82
+ # @return [String, nil] The response from the server, or nil if an error occurred.
83
+ #
84
+ # @raise [StandardError] Raises an error if `event_name`, `context`, or `userId` are missing or invalid.
85
+ def track_event(event_name, context, event_properties = {})
86
+ # Raise an error if the SDK is not initialized with options.
87
+ raise 'VWO is not initialized' if @options.nil?
88
+
89
+ # Validate that event_name and userId in context are present.
90
+ raise 'event_name is required to track the event' if event_name.nil? || event_name.empty?
91
+ raise 'userId is required to track the event, please provide id in context' if context.nil? || context[:id].nil? || context[:id].empty?
92
+
93
+ # Add event details to the context.
94
+ context['eventName'] = event_name
95
+ context['eventProperties'] = event_properties
96
+
97
+ # Construct the API endpoint for tracking the event.
98
+ endpoint = "#{Constants::ENDPOINT_TRACK_EVENT}?accountId=#{@options[:account_id]}&sdkKey=#{@options[:sdk_key]}"
99
+
100
+ # Send a POST request to track the event.
101
+ response = Utils::Request.send_post_request(endpoint, context)
102
+
103
+ # Return the server response.
104
+ response
105
+ rescue StandardError => e
106
+ # Log the error if any occurs during event tracking.
107
+ LoggerHelper.logger.error("Error tracking event: #{e.message}")
108
+ end
109
+
110
+ # Sets an attribute for a given user context.
111
+ #
112
+ # @param [String] attribute_key The key of the attribute to set.
113
+ # @param [String] attribute_value The value of the attribute to set.
114
+ # @param [Hash] context The context data, which must include a `:id` for user identification.
115
+ #
116
+ # @return [String, nil] The response from the server, or nil if an error occurred.
117
+ #
118
+ # @raise [StandardError] Raises an error if `attribute_key`, `attribute_value`, or `userId` are missing or invalid.
119
+ def set_attribute(attribute_key, attribute_value, context)
120
+ # Raise an error if the SDK is not initialized with options.
121
+ raise 'VWO is not initialized' if @options.nil?
122
+
123
+ # Validate that attribute_key, attribute_value, and userId in context are present.
124
+ raise 'attribute_key is required for set_attribute' if attribute_key.nil? || attribute_key.empty?
125
+ raise 'attribute_value is required for set_attribute' if attribute_value.nil?
126
+ raise 'userId is required to set attribute, please provide id in context' if context.nil? || context[:id].nil? || context[:id].empty?
127
+
128
+ # Add the attribute details to the context.
129
+ context['attributeKey'] = attribute_key
130
+ context['attributeValue'] = attribute_value
131
+
132
+ # Construct the API endpoint for setting the attribute.
133
+ endpoint = "#{Constants::ENDPOINT_SET_ATTRIBUTE}?accountId=#{@options[:account_id]}&sdkKey=#{@options[:sdk_key]}"
134
+
135
+ # Send a POST request to set the attribute.
136
+ Utils::Request.send_post_request(endpoint, context)
137
+ rescue StandardError => e
138
+ # Log the error if any occurs during setting the attribute.
139
+ LoggerHelper.logger.error("Error setting attribute: #{e.message}")
140
+ end
141
+ end
142
+ end
data/lib/vwo.rb ADDED
@@ -0,0 +1,56 @@
1
+ # Copyright 2024 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative 'vwo/utils/logger_helper'
16
+ require_relative 'vwo/vwo_client'
17
+ require_relative 'vwo/vwo_builder'
18
+ require_relative 'vwo/constants'
19
+ require_relative 'vwo/utils/request'
20
+
21
+ # The main VWO module
22
+ module VWO
23
+ # Class-level variable to hold the VWO client instance
24
+ @@instance = nil
25
+
26
+ # Initialize the VWO SDK with the given options
27
+ def self.init(options = {})
28
+ raise 'options is required to initialize VWO' unless options.is_a?(Hash)
29
+ raise 'sdk_key is required to initialize VWO' if options[:sdk_key].nil? || options[:sdk_key].empty?
30
+ raise 'account_id is required to initialize VWO' if options[:account_id].nil? || options[:account_id].empty?
31
+ raise 'gateway_service_url is required to initialize VWO' if options[:gateway_service_url].nil? || options[:gateway_service_url].empty?
32
+
33
+ vwo_init_options = {
34
+ sdk_key: options[:sdk_key],
35
+ account_id: options[:account_id],
36
+ gateway_service_url: options[:gateway_service_url]
37
+ }
38
+
39
+ set_instance(vwo_init_options)
40
+ rescue StandardError => e
41
+ LoggerHelper.logger.error("Error initializing VWO: #{e.message}")
42
+ @@instance = VWOClient.new(nil)
43
+ end
44
+
45
+ # Set the VWO instance using VWOBuilder and VWOClient
46
+ def self.set_instance(options)
47
+ vwo_builder = VWOBuilder.new(options)
48
+ vwo_builder.init_client
49
+ @@instance = VWOClient.new(options)
50
+ end
51
+
52
+ # Get the singleton instance of VWO
53
+ def self.instance
54
+ @@instance
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vwo-fme-ruby-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - VWO
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-http
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
27
+ description: A Ruby SDK for Feature Management And Experimentation
28
+ email:
29
+ - dev@wingify.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/vwo.rb
35
+ - lib/vwo/constants.rb
36
+ - lib/vwo/utils/feature_flag_response.rb
37
+ - lib/vwo/utils/logger_helper.rb
38
+ - lib/vwo/utils/request.rb
39
+ - lib/vwo/vwo_builder.rb
40
+ - lib/vwo/vwo_client.rb
41
+ homepage:
42
+ licenses:
43
+ - Apache-2.0
44
+ metadata:
45
+ bug_tracker_uri: https://github.com/wingify/vwo-fme-ruby-sdk/issues
46
+ changelog_uri: https://github.com/wingify/vwo-fme-ruby-sdk/blob/master/CHANGELOG.md
47
+ homepage_uri: https://github.com/wingify/vwo-fme-ruby-sdk
48
+ source_code_uri: https://github.com/wingify/vwo-fme-ruby-sdk
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '2.5'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 3.0.3.1
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: VWO FME Ruby SDK
68
+ test_files: []