launchdarkly-server-sdk 6.4.0 → 7.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +102 -56
  3. data/lib/ldclient-rb/context.rb +487 -0
  4. data/lib/ldclient-rb/evaluation_detail.rb +20 -20
  5. data/lib/ldclient-rb/events.rb +77 -132
  6. data/lib/ldclient-rb/flags_state.rb +4 -4
  7. data/lib/ldclient-rb/impl/big_segments.rb +17 -17
  8. data/lib/ldclient-rb/impl/context.rb +96 -0
  9. data/lib/ldclient-rb/impl/context_filter.rb +145 -0
  10. data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
  11. data/lib/ldclient-rb/impl/evaluator.rb +379 -131
  12. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
  13. data/lib/ldclient-rb/impl/evaluator_helpers.rb +28 -31
  14. data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
  15. data/lib/ldclient-rb/impl/event_sender.rb +6 -6
  16. data/lib/ldclient-rb/impl/event_summarizer.rb +12 -7
  17. data/lib/ldclient-rb/impl/event_types.rb +18 -30
  18. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +7 -7
  19. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +29 -29
  20. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
  21. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +92 -12
  22. data/lib/ldclient-rb/impl/model/clause.rb +39 -0
  23. data/lib/ldclient-rb/impl/model/feature_flag.rb +213 -0
  24. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +8 -121
  25. data/lib/ldclient-rb/impl/model/segment.rb +126 -0
  26. data/lib/ldclient-rb/impl/model/serialization.rb +52 -12
  27. data/lib/ldclient-rb/impl/repeating_task.rb +1 -1
  28. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
  29. data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
  30. data/lib/ldclient-rb/impl/util.rb +2 -2
  31. data/lib/ldclient-rb/in_memory_store.rb +2 -2
  32. data/lib/ldclient-rb/integrations/consul.rb +1 -1
  33. data/lib/ldclient-rb/integrations/dynamodb.rb +1 -1
  34. data/lib/ldclient-rb/integrations/file_data.rb +3 -3
  35. data/lib/ldclient-rb/integrations/redis.rb +4 -4
  36. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +218 -62
  37. data/lib/ldclient-rb/integrations/test_data.rb +16 -12
  38. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +9 -9
  39. data/lib/ldclient-rb/interfaces.rb +14 -14
  40. data/lib/ldclient-rb/ldclient.rb +94 -144
  41. data/lib/ldclient-rb/memoized_value.rb +1 -1
  42. data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
  43. data/lib/ldclient-rb/polling.rb +2 -2
  44. data/lib/ldclient-rb/reference.rb +274 -0
  45. data/lib/ldclient-rb/requestor.rb +5 -5
  46. data/lib/ldclient-rb/stream.rb +7 -8
  47. data/lib/ldclient-rb/util.rb +4 -19
  48. data/lib/ldclient-rb/version.rb +1 -1
  49. data/lib/ldclient-rb.rb +2 -3
  50. metadata +34 -17
  51. data/lib/ldclient-rb/file_data_source.rb +0 -23
  52. data/lib/ldclient-rb/newrelic.rb +0 -17
  53. data/lib/ldclient-rb/redis_store.rb +0 -88
  54. data/lib/ldclient-rb/user_filter.rb +0 -52
@@ -2,7 +2,7 @@ require "ldclient-rb/impl/evaluator_helpers"
2
2
 
3
3
  module LaunchDarkly
4
4
  module Impl
5
- module DataModelPreprocessing
5
+ module Model
6
6
  #
7
7
  # Container for a precomputed result that includes a specific variation index and value, an
8
8
  # evaluation reason, and optionally an alternate evaluation reason that corresponds to the
@@ -18,7 +18,7 @@ module LaunchDarkly
18
18
 
19
19
  # @param in_experiment [Boolean] indicates whether we want the result to include
20
20
  # "inExperiment: true" in the reason or not
21
- # @return [EvaluationDetail]
21
+ # @return [LaunchDarkly::EvaluationDetail]
22
22
  def get_result(in_experiment = false)
23
23
  in_experiment ? @in_experiment_result : @regular_result
24
24
  end
@@ -35,135 +35,22 @@ module LaunchDarkly
35
35
  # @param index [Integer] the variation index
36
36
  # @param in_experiment [Boolean] indicates whether we want the result to include
37
37
  # "inExperiment: true" in the reason or not
38
+ # @return [LaunchDarkly::EvaluationDetail]
38
39
  def for_variation(index, in_experiment)
39
40
  if index < 0 || index >= @factories.length
40
41
  EvaluationDetail.new(nil, nil, EvaluationReason.error(EvaluationReason::ERROR_MALFORMED_FLAG))
41
42
  else
42
43
  @factories[index].get_result(in_experiment)
43
44
  end
44
- end
45
- end
46
-
47
- # Base class for all of the preprocessed data classes we embed in our data model. Using this class
48
- # ensures that none of its properties will be included in JSON representations. It also overrides
49
- # == to say that it is always equal with another instance of the same class; equality tests on
50
- # this class are only ever done in test code, and we want the contents of these classes to be
51
- # ignored in test code unless we are looking at specific attributes.
52
- class PreprocessedDataBase
53
- def as_json(*)
54
- nil
55
- end
56
-
57
- def to_json(*a)
58
- "null"
59
- end
60
-
61
- def ==(other)
62
- other.class == self.class
63
- end
64
- end
65
-
66
- class FlagPreprocessed < PreprocessedDataBase
67
- def initialize(off_result, fallthrough_factory)
68
- @off_result = off_result
69
- @fallthrough_factory = fallthrough_factory
70
- end
71
-
72
- # @return [EvalResultsForSingleVariation]
73
- attr_reader :off_result
74
- # @return [EvalResultFactoryMultiVariations]
75
- attr_reader :fallthrough_factory
76
- end
77
-
78
- class PrerequisitePreprocessed < PreprocessedDataBase
79
- def initialize(failed_result)
80
- @failed_result = failed_result
81
- end
82
-
83
- # @return [EvalResultsForSingleVariation]
84
- attr_reader :failed_result
85
- end
86
-
87
- class TargetPreprocessed < PreprocessedDataBase
88
- def initialize(match_result)
89
- @match_result = match_result
90
45
  end
91
-
92
- # @return [EvalResultsForSingleVariation]
93
- attr_reader :match_result
94
- end
95
-
96
- class FlagRulePreprocessed < PreprocessedDataBase
97
- def initialize(all_match_results)
98
- @all_match_results = all_match_results
99
- end
100
-
101
- # @return [EvalResultsForSingleVariation]
102
- attr_reader :all_match_results
103
46
  end
104
47
 
105
48
  class Preprocessor
106
- def initialize(logger = nil)
107
- @logger = logger
108
- end
109
-
110
- def preprocess_item!(kind, item)
111
- if kind.eql? FEATURES
112
- preprocess_flag!(item)
113
- elsif kind.eql? SEGMENTS
114
- preprocess_segment!(item)
115
- end
116
- end
117
-
118
- def preprocess_all_items!(kind, items_map)
119
- return items_map if !items_map
120
- items_map.each do |key, item|
121
- preprocess_item!(kind, item)
122
- end
123
- end
124
-
125
- def preprocess_flag!(flag)
126
- flag[:_preprocessed] = FlagPreprocessed.new(
127
- EvaluatorHelpers.off_result(flag),
128
- precompute_multi_variation_results(flag, EvaluationReason::fallthrough(false), EvaluationReason::fallthrough(true))
129
- )
130
- (flag[:prerequisites] || []).each do |prereq|
131
- preprocess_prerequisite!(prereq, flag)
132
- end
133
- (flag[:targets] || []).each do |target|
134
- preprocess_target!(target, flag)
135
- end
136
- rules = flag[:rules]
137
- (rules || []).each_index do |index|
138
- preprocess_flag_rule!(rules[index], index, flag)
139
- end
140
- end
141
-
142
- def preprocess_segment!(segment)
143
- # nothing to do for segments currently
144
- end
145
-
146
- private def preprocess_prerequisite!(prereq, flag)
147
- prereq[:_preprocessed] = PrerequisitePreprocessed.new(
148
- EvaluatorHelpers.prerequisite_failed_result(prereq, flag, @logger)
149
- )
150
- end
151
-
152
- private def preprocess_target!(target, flag)
153
- target[:_preprocessed] = TargetPreprocessed.new(
154
- EvaluatorHelpers.target_match_result(target, flag, @logger)
155
- )
156
- end
157
-
158
- private def preprocess_flag_rule!(rule, index, flag)
159
- match_reason = EvaluationReason::rule_match(index, rule[:id])
160
- match_reason_in_experiment = EvaluationReason::rule_match(index, rule[:id], true)
161
- rule[:_preprocessed] = FlagRulePreprocessed.new(
162
- precompute_multi_variation_results(flag, match_reason, match_reason_in_experiment)
163
- )
164
- end
165
-
166
- private def precompute_multi_variation_results(flag, regular_reason, in_experiment_reason)
49
+ # @param flag [LaunchDarkly::Impl::Model::FeatureFlag]
50
+ # @param regular_reason [LaunchDarkly::EvaluationReason]
51
+ # @param in_experiment_reason [LaunchDarkly::EvaluationReason]
52
+ # @return [EvalResultFactoryMultiVariations]
53
+ def self.precompute_multi_variation_results(flag, regular_reason, in_experiment_reason)
167
54
  factories = []
168
55
  vars = flag[:variations] || []
169
56
  vars.each_index do |index|
@@ -0,0 +1,126 @@
1
+ require "ldclient-rb/impl/model/clause"
2
+ require "ldclient-rb/impl/model/preprocessed_data"
3
+ require "set"
4
+
5
+ # See serialization.rb for implementation notes on the data model classes.
6
+
7
+ module LaunchDarkly
8
+ module Impl
9
+ module Model
10
+ class Segment
11
+ # @param data [Hash]
12
+ # @param logger [Logger|nil]
13
+ def initialize(data, logger = nil)
14
+ raise ArgumentError, "expected hash but got #{data.class}" unless data.is_a?(Hash)
15
+ @data = data
16
+ @key = data[:key]
17
+ @version = data[:version]
18
+ @deleted = !!data[:deleted]
19
+ return if @deleted
20
+ @included = data[:included] || []
21
+ @excluded = data[:excluded] || []
22
+ @included_contexts = (data[:includedContexts] || []).map do |target_data|
23
+ SegmentTarget.new(target_data)
24
+ end
25
+ @excluded_contexts = (data[:excludedContexts] || []).map do |target_data|
26
+ SegmentTarget.new(target_data)
27
+ end
28
+ @rules = (data[:rules] || []).map do |rule_data|
29
+ SegmentRule.new(rule_data, logger)
30
+ end
31
+ @unbounded = !!data[:unbounded]
32
+ @unbounded_context_kind = data[:unboundedContextKind] || LDContext::KIND_DEFAULT
33
+ @generation = data[:generation]
34
+ @salt = data[:salt]
35
+ end
36
+
37
+ # @return [Hash]
38
+ attr_reader :data
39
+ # @return [String]
40
+ attr_reader :key
41
+ # @return [Integer]
42
+ attr_reader :version
43
+ # @return [Boolean]
44
+ attr_reader :deleted
45
+ # @return [Array<String>]
46
+ attr_reader :included
47
+ # @return [Array<String>]
48
+ attr_reader :excluded
49
+ # @return [Array<LaunchDarkly::Impl::Model::SegmentTarget>]
50
+ attr_reader :included_contexts
51
+ # @return [Array<LaunchDarkly::Impl::Model::SegmentTarget>]
52
+ attr_reader :excluded_contexts
53
+ # @return [Array<SegmentRule>]
54
+ attr_reader :rules
55
+ # @return [Boolean]
56
+ attr_reader :unbounded
57
+ # @return [String]
58
+ attr_reader :unbounded_context_kind
59
+ # @return [Integer|nil]
60
+ attr_reader :generation
61
+ # @return [String]
62
+ attr_reader :salt
63
+
64
+ # This method allows us to read properties of the object as if it's just a hash. Currently this is
65
+ # necessary because some data store logic is still written to expect hashes; we can remove it once
66
+ # we migrate entirely to using attributes of the class.
67
+ def [](key)
68
+ @data[key]
69
+ end
70
+
71
+ def ==(other)
72
+ other.is_a?(Segment) && other.data == self.data
73
+ end
74
+
75
+ def as_json(*) # parameter is unused, but may be passed if we're using the json gem
76
+ @data
77
+ end
78
+
79
+ # Same as as_json, but converts the JSON structure into a string.
80
+ def to_json(*a)
81
+ as_json.to_json(a)
82
+ end
83
+ end
84
+
85
+ class SegmentTarget
86
+ def initialize(data)
87
+ @data = data
88
+ @context_kind = data[:contextKind]
89
+ @values = Set.new(data[:values] || [])
90
+ end
91
+
92
+ # @return [Hash]
93
+ attr_reader :data
94
+ # @return [String]
95
+ attr_reader :context_kind
96
+ # @return [Set]
97
+ attr_reader :values
98
+ end
99
+
100
+ class SegmentRule
101
+ def initialize(data, logger)
102
+ @data = data
103
+ @clauses = (data[:clauses] || []).map do |clause_data|
104
+ Clause.new(clause_data, logger)
105
+ end
106
+ @weight = data[:weight]
107
+ @bucket_by = data[:bucketBy]
108
+ @rollout_context_kind = data[:rolloutContextKind]
109
+ end
110
+
111
+ # @return [Hash]
112
+ attr_reader :data
113
+ # @return [Array<LaunchDarkly::Impl::Model::Clause>]
114
+ attr_reader :clauses
115
+ # @return [Integer|nil]
116
+ attr_reader :weight
117
+ # @return [String|nil]
118
+ attr_reader :bucket_by
119
+ # @return [String|nil]
120
+ attr_reader :rollout_context_kind
121
+ end
122
+
123
+ # Clause is defined in its own file because clauses are used by both flags and segments
124
+ end
125
+ end
126
+ end
@@ -1,31 +1,71 @@
1
+ require "ldclient-rb/impl/model/feature_flag"
1
2
  require "ldclient-rb/impl/model/preprocessed_data"
3
+ require "ldclient-rb/impl/model/segment"
4
+
5
+ # General implementation notes about the data model classes in LaunchDarkly::Impl::Model--
6
+ #
7
+ # As soon as we receive flag/segment JSON data from LaunchDarkly (or, read it from a database), we
8
+ # transform it into the model classes FeatureFlag, Segment, etc. The constructor of each of these
9
+ # classes takes a hash (the parsed JSON), and transforms it into an internal representation that
10
+ # is more efficient for evaluations.
11
+ #
12
+ # Validation works as follows:
13
+ # - A property value that is of the correct type, but is invalid for other reasons (for example,
14
+ # if a flag rule refers to variation index 5, but there are only 2 variations in the flag), does
15
+ # not prevent the flag from being parsed and stored. It does cause a warning to be logged, if a
16
+ # logger was passed to the constructor.
17
+ # - If a value is completely invalid for the schema, the constructor may throw an
18
+ # exception, causing the whole data set to be rejected. This is consistent with the behavior of
19
+ # the strongly-typed SDKs.
20
+ #
21
+ # Currently, the model classes also retain the original hash of the parsed JSON. This is because
22
+ # we may need to re-serialize them to JSON, and building the JSON on the fly would be very
23
+ # inefficient, so each model class has a to_json method that just returns the same Hash. If we
24
+ # are able in the future to either use a custom streaming serializer, or pass the JSON data
25
+ # straight through from LaunchDarkly to a database instead of re-serializing, we could stop
26
+ # retaining this data.
2
27
 
3
28
  module LaunchDarkly
4
29
  module Impl
5
30
  module Model
6
31
  # Abstraction of deserializing a feature flag or segment that was read from a data store or
7
32
  # received from LaunchDarkly.
8
- def self.deserialize(kind, json, logger = nil)
9
- return nil if json.nil?
10
- item = JSON.parse(json, symbolize_names: true)
11
- DataModelPreprocessing::Preprocessor.new(logger).preprocess_item!(kind, item)
12
- item
33
+ #
34
+ # SDK code outside of Impl::Model should use this method instead of calling the model class
35
+ # constructors directly, so as not to rely on implementation details.
36
+ #
37
+ # @param kind [Hash] normally either FEATURES or SEGMENTS
38
+ # @param input [object] a JSON string or a parsed hash (or a data model object, in which case
39
+ # we'll just return the original object)
40
+ # @param logger [Logger|nil] logs warnings if there are any data validation problems
41
+ # @return [Object] the flag or segment (or, for an unknown data kind, the data as a hash)
42
+ def self.deserialize(kind, input, logger = nil)
43
+ return nil if input.nil?
44
+ return input if !input.is_a?(String) && !input.is_a?(Hash)
45
+ data = input.is_a?(Hash) ? input : JSON.parse(input, symbolize_names: true)
46
+ case kind
47
+ when FEATURES
48
+ FeatureFlag.new(data, logger)
49
+ when SEGMENTS
50
+ Segment.new(data, logger)
51
+ else
52
+ data
53
+ end
13
54
  end
14
55
 
15
56
  # Abstraction of serializing a feature flag or segment that will be written to a data store.
16
- # Currently we just call to_json.
57
+ # Currently we just call to_json, but SDK code outside of Impl::Model should use this method
58
+ # instead of to_json, so as not to rely on implementation details.
17
59
  def self.serialize(kind, item)
18
60
  item.to_json
19
61
  end
20
62
 
21
63
  # Translates a { flags: ..., segments: ... } object received from LaunchDarkly to the data store format.
22
64
  def self.make_all_store_data(received_data, logger = nil)
23
- preprocessor = DataModelPreprocessing::Preprocessor.new(logger)
24
- flags = received_data[:flags]
25
- preprocessor.preprocess_all_items!(FEATURES, flags)
26
- segments = received_data[:segments]
27
- preprocessor.preprocess_all_items!(SEGMENTS, segments)
28
- { FEATURES => flags, SEGMENTS => segments }
65
+ {
66
+ FEATURES => (received_data[:flags] || {}).transform_values { |data| FeatureFlag.new(data, logger) },
67
+ SEGMENTS => (received_data[:segments] || {}).transform_values { |data| Segment.new(data, logger) },
68
+ }
29
69
  end
30
70
  end
31
71
  end
@@ -19,7 +19,7 @@ module LaunchDarkly
19
19
  if @start_delay
20
20
  sleep(@start_delay)
21
21
  end
22
- while !@stopped.value do
22
+ until @stopped.value do
23
23
  started_at = Time.now
24
24
  begin
25
25
  @task.call
@@ -33,7 +33,7 @@ module LaunchDarkly
33
33
  return input if dependency_fn.nil? || input.empty?
34
34
  remaining_items = input.clone
35
35
  items_out = {}
36
- while !remaining_items.empty?
36
+ until remaining_items.empty?
37
37
  # pick a random item that hasn't been updated yet
38
38
  key, item = remaining_items.first
39
39
  self.add_with_dependencies_first(item, dependency_fn, remaining_items, items_out)
@@ -46,7 +46,7 @@ module LaunchDarkly
46
46
  remaining_items.delete(item_key) # we won't need to visit this item again
47
47
  dependency_fn.call(item).each do |dep_key|
48
48
  dep_item = remaining_items[dep_key.to_sym]
49
- self.add_with_dependencies_first(dep_item, dependency_fn, remaining_items, items_out) if !dep_item.nil?
49
+ self.add_with_dependencies_first(dep_item, dependency_fn, remaining_items, items_out) unless dep_item.nil?
50
50
  end
51
51
  items_out[item_key] = item
52
52
  end
@@ -25,7 +25,7 @@ module LaunchDarkly
25
25
 
26
26
  def dispose_all
27
27
  @lock.synchronize {
28
- @pool.map { |instance| @instance_destructor.call(instance) } if !@instance_destructor.nil?
28
+ @pool.map { |instance| @instance_destructor.call(instance) } unless @instance_destructor.nil?
29
29
  @pool.clear()
30
30
  }
31
31
  end
@@ -1,7 +1,7 @@
1
1
  module LaunchDarkly
2
2
  module Impl
3
3
  module Util
4
- def self.is_bool(aObject)
4
+ def self.bool?(aObject)
5
5
  [true,false].include? aObject
6
6
  end
7
7
 
@@ -56,7 +56,7 @@ module LaunchDarkly
56
56
  return ""
57
57
  end
58
58
 
59
- if value.match(/[^a-zA-Z0-9._-]/)
59
+ if /[^a-zA-Z0-9._-]/.match?(value)
60
60
  logger.warn { "Value of application[#{name}] contained invalid characters and was discarded" }
61
61
  return ""
62
62
  end
@@ -14,13 +14,13 @@ module LaunchDarkly
14
14
  FEATURES = {
15
15
  namespace: "features",
16
16
  priority: 1, # that is, features should be stored after segments
17
- get_dependency_keys: lambda { |flag| (flag[:prerequisites] || []).map { |p| p[:key] } }
17
+ get_dependency_keys: lambda { |flag| (flag[:prerequisites] || []).map { |p| p[:key] } },
18
18
  }.freeze
19
19
 
20
20
  # @private
21
21
  SEGMENTS = {
22
22
  namespace: "segments",
23
- priority: 0
23
+ priority: 0,
24
24
  }.freeze
25
25
 
26
26
  #
@@ -38,7 +38,7 @@ module LaunchDarkly
38
38
  #
39
39
  def self.new_feature_store(opts = {})
40
40
  core = LaunchDarkly::Impl::Integrations::Consul::ConsulFeatureStoreCore.new(opts)
41
- return LaunchDarkly::Integrations::Util::CachingStoreWrapper.new(core, opts)
41
+ LaunchDarkly::Integrations::Util::CachingStoreWrapper.new(core, opts)
42
42
  end
43
43
  end
44
44
  end
@@ -54,7 +54,7 @@ module LaunchDarkly
54
54
  #
55
55
  # Creates a DynamoDB-backed Big Segment store.
56
56
  #
57
- # Big Segments are a specific type of user segments. For more information, read the LaunchDarkly
57
+ # Big Segments are a specific type of segments. For more information, read the LaunchDarkly
58
58
  # documentation: https://docs.launchdarkly.com/home/users/big-segments
59
59
  #
60
60
  # To use this method, you must first install one of the AWS SDK gems: either `aws-sdk-dynamodb`, or
@@ -25,7 +25,7 @@ module LaunchDarkly
25
25
  #
26
26
  # - `flags`: Feature flag definitions.
27
27
  # - `flagValues`: Simplified feature flags that contain only a value.
28
- # - `segments`: User segment definitions.
28
+ # - `segments`: Context segment definitions.
29
29
  #
30
30
  # The format of the data in `flags` and `segments` is defined by the LaunchDarkly application
31
31
  # and is subject to change. Rather than trying to construct these objects yourself, it is simpler
@@ -78,7 +78,7 @@ module LaunchDarkly
78
78
  # same flag key or segment key more than once, either in a single file or across multiple files.
79
79
  #
80
80
  # If the data source encounters any error in any file-- malformed content, a missing file, or a
81
- # duplicate key-- it will not load flags from any of the files.
81
+ # duplicate key-- it will not load flags from any of the files.
82
82
  #
83
83
  module FileData
84
84
  #
@@ -100,7 +100,7 @@ module LaunchDarkly
100
100
  # @return an object that can be stored in {Config#data_source}
101
101
  #
102
102
  def self.data_source(options={})
103
- return lambda { |sdk_key, config|
103
+ lambda { |sdk_key, config|
104
104
  Impl::Integrations::FileDataSourceImpl.new(config.feature_store, config.logger, options) }
105
105
  end
106
106
  end
@@ -1,4 +1,4 @@
1
- require "ldclient-rb/redis_store" # eventually we will just refer to impl/integrations/redis_impl directly
1
+ require "ldclient-rb/impl/integrations/redis_impl"
2
2
 
3
3
  module LaunchDarkly
4
4
  module Integrations
@@ -59,13 +59,13 @@ module LaunchDarkly
59
59
  # @return [LaunchDarkly::Interfaces::FeatureStore] a feature store object
60
60
  #
61
61
  def self.new_feature_store(opts = {})
62
- return RedisFeatureStore.new(opts)
62
+ LaunchDarkly::Impl::Integrations::Redis::RedisFeatureStore.new(opts)
63
63
  end
64
64
 
65
65
  #
66
66
  # Creates a Redis-backed Big Segment store.
67
67
  #
68
- # Big Segments are a specific type of user segments. For more information, read the LaunchDarkly
68
+ # Big Segments are a specific type of segments. For more information, read the LaunchDarkly
69
69
  # documentation: https://docs.launchdarkly.com/home/users/big-segments
70
70
  #
71
71
  # To use this method, you must first have the `redis` and `connection-pool` gems installed. Then,
@@ -91,7 +91,7 @@ module LaunchDarkly
91
91
  # @return [LaunchDarkly::Interfaces::BigSegmentStore] a Big Segment store object
92
92
  #
93
93
  def self.new_big_segment_store(opts)
94
- return LaunchDarkly::Impl::Integrations::Redis::RedisBigSegmentStore.new(opts)
94
+ LaunchDarkly::Impl::Integrations::Redis::RedisBigSegmentStore.new(opts)
95
95
  end
96
96
  end
97
97
  end