ldclient-rb 5.4.3 → 5.5.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +33 -6
  3. data/CHANGELOG.md +19 -0
  4. data/CONTRIBUTING.md +0 -12
  5. data/Gemfile.lock +22 -3
  6. data/README.md +41 -35
  7. data/ldclient-rb.gemspec +4 -3
  8. data/lib/ldclient-rb.rb +9 -1
  9. data/lib/ldclient-rb/cache_store.rb +1 -0
  10. data/lib/ldclient-rb/config.rb +201 -90
  11. data/lib/ldclient-rb/evaluation.rb +56 -8
  12. data/lib/ldclient-rb/event_summarizer.rb +3 -0
  13. data/lib/ldclient-rb/events.rb +16 -0
  14. data/lib/ldclient-rb/expiring_cache.rb +1 -0
  15. data/lib/ldclient-rb/file_data_source.rb +18 -13
  16. data/lib/ldclient-rb/flags_state.rb +3 -2
  17. data/lib/ldclient-rb/impl.rb +13 -0
  18. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +158 -0
  19. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +228 -0
  20. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +155 -0
  21. data/lib/ldclient-rb/impl/store_client_wrapper.rb +47 -0
  22. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +55 -0
  23. data/lib/ldclient-rb/in_memory_store.rb +15 -4
  24. data/lib/ldclient-rb/integrations.rb +55 -0
  25. data/lib/ldclient-rb/integrations/consul.rb +38 -0
  26. data/lib/ldclient-rb/integrations/dynamodb.rb +47 -0
  27. data/lib/ldclient-rb/integrations/redis.rb +55 -0
  28. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +230 -0
  29. data/lib/ldclient-rb/interfaces.rb +153 -0
  30. data/lib/ldclient-rb/ldclient.rb +135 -77
  31. data/lib/ldclient-rb/memoized_value.rb +2 -0
  32. data/lib/ldclient-rb/newrelic.rb +1 -0
  33. data/lib/ldclient-rb/non_blocking_thread_pool.rb +3 -3
  34. data/lib/ldclient-rb/polling.rb +1 -0
  35. data/lib/ldclient-rb/redis_store.rb +24 -190
  36. data/lib/ldclient-rb/requestor.rb +3 -2
  37. data/lib/ldclient-rb/simple_lru_cache.rb +1 -0
  38. data/lib/ldclient-rb/stream.rb +22 -10
  39. data/lib/ldclient-rb/user_filter.rb +1 -0
  40. data/lib/ldclient-rb/util.rb +1 -0
  41. data/lib/ldclient-rb/version.rb +1 -1
  42. data/scripts/gendocs.sh +12 -0
  43. data/spec/feature_store_spec_base.rb +173 -72
  44. data/spec/file_data_source_spec.rb +2 -2
  45. data/spec/http_util.rb +103 -0
  46. data/spec/in_memory_feature_store_spec.rb +1 -1
  47. data/spec/integrations/consul_feature_store_spec.rb +41 -0
  48. data/spec/integrations/dynamodb_feature_store_spec.rb +104 -0
  49. data/spec/integrations/store_wrapper_spec.rb +276 -0
  50. data/spec/ldclient_spec.rb +83 -4
  51. data/spec/redis_feature_store_spec.rb +25 -16
  52. data/spec/requestor_spec.rb +44 -38
  53. data/spec/stream_spec.rb +18 -18
  54. metadata +55 -33
  55. data/lib/sse_client.rb +0 -4
  56. data/lib/sse_client/backoff.rb +0 -38
  57. data/lib/sse_client/sse_client.rb +0 -171
  58. data/lib/sse_client/sse_events.rb +0 -67
  59. data/lib/sse_client/streaming_http.rb +0 -199
  60. data/spec/sse_client/sse_client_spec.rb +0 -177
  61. data/spec/sse_client/sse_events_spec.rb +0 -100
  62. data/spec/sse_client/sse_shared.rb +0 -82
  63. data/spec/sse_client/streaming_http_spec.rb +0 -263
@@ -0,0 +1,153 @@
1
+
2
+ module LaunchDarkly
3
+ #
4
+ # Mixins that define the required methods of various pluggable components used by the client.
5
+ #
6
+ module Interfaces
7
+ #
8
+ # Mixin that defines the required methods of a feature store implementation. The LaunchDarkly
9
+ # client uses the feature store to persist feature flags and related objects received from
10
+ # the LaunchDarkly service. Implementations must support concurrent access and updates.
11
+ # For more about how feature stores can be used, see:
12
+ # [Using a persistent feature store](https://docs.launchdarkly.com/v2.0/docs/using-a-persistent-feature-store).
13
+ #
14
+ # An entity that can be stored in a feature store is a hash that can be converted to and from
15
+ # JSON, and that has at a minimum the following properties: `:key`, a string that is unique
16
+ # among entities of the same kind; `:version`, an integer that is higher for newer data;
17
+ # `:deleted`, a boolean (optional, defaults to false) that if true means this is a
18
+ # placeholder for a deleted entity.
19
+ #
20
+ # To represent the different kinds of objects that can be stored, such as feature flags and
21
+ # segments, the SDK will provide a "kind" object; this is a hash with a single property,
22
+ # `:namespace`, which is a short string unique to that kind. This string can be used as a
23
+ # collection name or a key prefix.
24
+ #
25
+ # The default implementation is {LaunchDarkly::InMemoryFeatureStore}. Several implementations
26
+ # that use databases can be found in {LaunchDarkly::Integrations}. If you want to write a new
27
+ # implementation, see {LaunchDarkly::Integrations::Util} for tools that can make this task
28
+ # simpler.
29
+ #
30
+ module FeatureStore
31
+ #
32
+ # Initializes (or re-initializes) the store with the specified set of entities. Any
33
+ # existing entries will be removed. Implementations can assume that this data set is up to
34
+ # date-- there is no need to perform individual version comparisons between the existing
35
+ # objects and the supplied features.
36
+ #
37
+ # If possible, the store should update the entire data set atomically. If that is not possible,
38
+ # it should iterate through the outer hash and then the inner hash using the existing iteration
39
+ # order of those hashes (the SDK will ensure that the items were inserted into the hashes in
40
+ # the correct order), storing each item, and then delete any leftover items at the very end.
41
+ #
42
+ # @param all_data [Hash] a hash where each key is one of the data kind objects, and each
43
+ # value is in turn a hash of string keys to entities
44
+ # @return [void]
45
+ #
46
+ def init(all_data)
47
+ end
48
+
49
+ #
50
+ # Returns the entity to which the specified key is mapped, if any.
51
+ #
52
+ # @param kind [Object] the kind of entity to get
53
+ # @param key [String] the unique key of the entity to get
54
+ # @return [Hash] the entity; nil if the key was not found, or if the stored entity's
55
+ # `:deleted` property was true
56
+ #
57
+ def get(kind, key)
58
+ end
59
+
60
+ #
61
+ # Returns all stored entities of the specified kind, not including deleted entities.
62
+ #
63
+ # @param kind [Object] the kind of entity to get
64
+ # @return [Hash] a hash where each key is the entity's `:key` property and each value
65
+ # is the entity
66
+ #
67
+ def all(kind)
68
+ end
69
+
70
+ #
71
+ # Attempt to add an entity, or update an existing entity with the same key. An update
72
+ # should only succeed if the new item's `:version` is greater than the old one;
73
+ # otherwise, the method should do nothing.
74
+ #
75
+ # @param kind [Object] the kind of entity to add or update
76
+ # @param item [Hash] the entity to add or update
77
+ # @return [void]
78
+ #
79
+ def upsert(kind, item)
80
+ end
81
+
82
+ #
83
+ # Attempt to delete an entity if it exists. Deletion should only succeed if the
84
+ # `version` parameter is greater than the existing entity's `:version`; otherwise, the
85
+ # method should do nothing.
86
+ #
87
+ # @param kind [Object] the kind of entity to delete
88
+ # @param key [String] the unique key of the entity
89
+ # @param version [Integer] the entity must have a lower version than this to be deleted
90
+ # @return [void]
91
+ #
92
+ def delete(kind, key, version)
93
+ end
94
+
95
+ #
96
+ # Checks whether this store has been initialized. That means that `init` has been called
97
+ # either by this process, or (if the store can be shared) by another process. This
98
+ # method will be called frequently, so it should be efficient. You can assume that if it
99
+ # has returned true once, it can continue to return true, i.e. a store cannot become
100
+ # uninitialized again.
101
+ #
102
+ # @return [Boolean] true if the store is in an initialized state
103
+ #
104
+ def initialized?
105
+ end
106
+
107
+ #
108
+ # Performs any necessary cleanup to shut down the store when the client is being shut down.
109
+ #
110
+ # @return [void]
111
+ #
112
+ def stop
113
+ end
114
+ end
115
+
116
+ #
117
+ # Mixin that defines the required methods of a data source implementation. This is the
118
+ # component that delivers feature flag data from LaunchDarkly to the LDClient by putting
119
+ # the data in the {FeatureStore}. It is expected to run concurrently on its own thread.
120
+ #
121
+ # The client has its own standard implementation, which uses either a streaming connection or
122
+ # polling depending on your configuration. Normally you will not need to use another one
123
+ # except for testing purposes. {FileDataSource} provides one such test fixture.
124
+ #
125
+ module DataSource
126
+ #
127
+ # Checks whether the data source has finished initializing. Initialization is considered done
128
+ # once it has received one complete data set from LaunchDarkly.
129
+ #
130
+ # @return [Boolean] true if initialization is complete
131
+ #
132
+ def initialized?
133
+ end
134
+
135
+ #
136
+ # Puts the data source into an active state. Normally this means it will make its first
137
+ # connection attempt to LaunchDarkly. If `start` has already been called, calling it again
138
+ # should simply return the same value as the first call.
139
+ #
140
+ # @return [Concurrent::Event] an Event which will be set once initialization is complete
141
+ #
142
+ def start
143
+ end
144
+
145
+ #
146
+ # Puts the data source into an inactive state and releases all of its resources.
147
+ # This state should be considered permanent (`start` does not have to work after `stop`).
148
+ #
149
+ def stop
150
+ end
151
+ end
152
+ end
153
+ end
@@ -1,3 +1,4 @@
1
+ require "ldclient-rb/impl/store_client_wrapper"
1
2
  require "concurrent/atomics"
2
3
  require "digest/sha1"
3
4
  require "logger"
@@ -10,7 +11,6 @@ module LaunchDarkly
10
11
  # A client for LaunchDarkly. Client instances are thread-safe. Users
11
12
  # should create a single client instance for the lifetime of the application.
12
13
  #
13
- #
14
14
  class LDClient
15
15
  include Evaluation
16
16
  #
@@ -18,15 +18,28 @@ module LaunchDarkly
18
18
  # configuration parameter can also supplied to specify advanced options,
19
19
  # but for most use cases, the default configuration is appropriate.
20
20
  #
21
+ # The client will immediately attempt to connect to LaunchDarkly and retrieve
22
+ # your feature flag data. If it cannot successfully do so within the time limit
23
+ # specified by `wait_for_sec`, the constructor will return a client that is in
24
+ # an uninitialized state. See {#initialized?} for more details.
21
25
  #
22
26
  # @param sdk_key [String] the SDK key for your LaunchDarkly account
23
27
  # @param config [Config] an optional client configuration object
28
+ # @param wait_for_sec [Float] maximum time (in seconds) to wait for initialization
24
29
  #
25
30
  # @return [LDClient] The LaunchDarkly client instance
31
+ #
26
32
  def initialize(sdk_key, config = Config.default, wait_for_sec = 5)
27
33
  @sdk_key = sdk_key
28
- @config = config
29
- @store = config.feature_store
34
+
35
+ # We need to wrap the feature store object with a FeatureStoreClientWrapper in order to add
36
+ # some necessary logic around updates. Unfortunately, we have code elsewhere that accesses
37
+ # the feature store through the Config object, so we need to make a new Config that uses
38
+ # the wrapped store.
39
+ @store = Impl::FeatureStoreClientWrapper.new(config.feature_store)
40
+ updated_config = config.clone
41
+ updated_config.instance_variable_set(:@feature_store, @store)
42
+ @config = updated_config
30
43
 
31
44
  if @config.offline? || !@config.send_events
32
45
  @event_processor = NullEventProcessor.new
@@ -39,149 +52,193 @@ module LaunchDarkly
39
52
  return # requestor and update processor are not used in this mode
40
53
  end
41
54
 
42
- if @config.update_processor
43
- @update_processor = @config.update_processor
55
+ data_source_or_factory = @config.data_source || self.method(:create_default_data_source)
56
+ if data_source_or_factory.respond_to? :call
57
+ @data_source = data_source_or_factory.call(sdk_key, @config)
44
58
  else
45
- factory = @config.update_processor_factory || self.method(:create_default_update_processor)
46
- @update_processor = factory.call(sdk_key, config)
59
+ @data_source = data_source_or_factory
47
60
  end
48
61
 
49
- ready = @update_processor.start
62
+ ready = @data_source.start
50
63
  if wait_for_sec > 0
51
64
  ok = ready.wait(wait_for_sec)
52
65
  if !ok
53
66
  @config.logger.error { "[LDClient] Timeout encountered waiting for LaunchDarkly client initialization" }
54
- elsif !@update_processor.initialized?
67
+ elsif !@data_source.initialized?
55
68
  @config.logger.error { "[LDClient] LaunchDarkly client initialization failed" }
56
69
  end
57
70
  end
58
71
  end
59
72
 
73
+ #
74
+ # Tells the client that all pending analytics events should be delivered as soon as possible.
75
+ #
76
+ # When the LaunchDarkly client generates analytics events (from {#variation}, {#variation_detail},
77
+ # {#identify}, or {#track}), they are queued on a worker thread. The event thread normally
78
+ # sends all queued events to LaunchDarkly at regular intervals, controlled by the
79
+ # {Config#flush_interval} option. Calling `flush` triggers a send without waiting for the
80
+ # next interval.
81
+ #
82
+ # Flushing is asynchronous, so this method will return before it is complete. However, if you
83
+ # call {#close}, events are guaranteed to be sent before that method returns.
84
+ #
60
85
  def flush
61
86
  @event_processor.flush
62
87
  end
63
88
 
64
- def toggle?(key, user, default = False)
89
+ #
90
+ # @param key [String] the feature flag key
91
+ # @param user [Hash] the user properties
92
+ # @param default [Boolean] (false) the value to use if the flag cannot be evaluated
93
+ # @return [Boolean] the flag value
94
+ # @deprecated Use {#variation} instead.
95
+ #
96
+ def toggle?(key, user, default = false)
65
97
  @config.logger.warn { "[LDClient] toggle? is deprecated. Use variation instead" }
66
98
  variation(key, user, default)
67
99
  end
68
100
 
101
+ #
102
+ # Creates a hash string that can be used by the JavaScript SDK to identify a user.
103
+ # For more information, see [Secure mode](https://docs.launchdarkly.com/docs/js-sdk-reference#section-secure-mode).
104
+ #
105
+ # @param user [Hash] the user properties
106
+ # @return [String] a hash string
107
+ #
69
108
  def secure_mode_hash(user)
70
109
  OpenSSL::HMAC.hexdigest("sha256", @sdk_key, user[:key].to_s)
71
110
  end
72
111
 
73
- # Returns whether the client has been initialized and is ready to serve feature flag requests
112
+ #
113
+ # Returns whether the client has been initialized and is ready to serve feature flag requests.
114
+ #
115
+ # If this returns false, it means that the client did not succeed in connecting to
116
+ # LaunchDarkly within the time limit that you specified in the constructor. It could
117
+ # still succeed in connecting at a later time (on another thread), or it could have
118
+ # given up permanently (for instance, if your SDK key is invalid). In the meantime,
119
+ # any call to {#variation} or {#variation_detail} will behave as follows:
120
+ #
121
+ # 1. It will check whether the feature store already contains data (that is, you
122
+ # are using a database-backed store and it was populated by a previous run of this
123
+ # application). If so, it will use the last known feature flag data.
124
+ #
125
+ # 2. Failing that, it will return the value that you specified for the `default`
126
+ # parameter of {#variation} or {#variation_detail}.
127
+ #
74
128
  # @return [Boolean] true if the client has been initialized
129
+ #
75
130
  def initialized?
76
- @config.offline? || @config.use_ldd? || @update_processor.initialized?
131
+ @config.offline? || @config.use_ldd? || @data_source.initialized?
77
132
  end
78
133
 
79
134
  #
80
- # Determines the variation of a feature flag to present to a user. At a minimum,
81
- # the user hash should contain a +:key+ .
135
+ # Determines the variation of a feature flag to present to a user.
82
136
  #
83
- # @example Basic user hash
84
- # {key: "user@example.com"}
137
+ # At a minimum, the user hash should contain a `:key`, which should be the unique
138
+ # identifier for your user (or, for an anonymous user, a session identifier or
139
+ # cookie).
85
140
  #
86
- # For authenticated users, the +:key+ should be the unique identifier for
87
- # your user. For anonymous users, the +:key+ should be a session identifier
88
- # or cookie. In either case, the only requirement is that the key
89
- # is unique to a user.
141
+ # Other supported user attributes include IP address, country code, and an arbitrary hash of
142
+ # custom attributes. For more about the supported user properties and how they work in
143
+ # LaunchDarkly, see [Targeting users](https://docs.launchdarkly.com/docs/targeting-users).
144
+ #
145
+ # The optional `:privateAttributeNames` user property allows you to specify a list of
146
+ # attribute names that should not be sent back to LaunchDarkly.
147
+ # [Private attributes](https://docs.launchdarkly.com/docs/private-user-attributes)
148
+ # can also be configured globally in {Config}.
90
149
  #
91
- # You can also pass IP addresses and country codes in the user hash.
150
+ # @example Basic user hash
151
+ # {key: "my-user-id"}
92
152
  #
93
153
  # @example More complete user hash
94
- # {key: "user@example.com", ip: "127.0.0.1", country: "US"}
154
+ # {key: "my-user-id", ip: "127.0.0.1", country: "US", custom: {customer_rank: 1000}}
95
155
  #
96
- # The user hash can contain arbitrary custom attributes stored in a +:custom+ sub-hash:
97
- #
98
- # @example A user hash with custom attributes
99
- # {key: "user@example.com", custom: {customer_rank: 1000, groups: ["google", "microsoft"]}}
100
- #
101
- # Attribute values in the custom hash can be integers, booleans, strings, or
102
- # lists of integers, booleans, or strings.
156
+ # @example User with a private attribute
157
+ # {key: "my-user-id", email: "email@example.com", privateAttributeNames: ["email"]}
103
158
  #
104
159
  # @param key [String] the unique feature key for the feature flag, as shown
105
160
  # on the LaunchDarkly dashboard
106
161
  # @param user [Hash] a hash containing parameters for the end user requesting the flag
107
- # @param default the default value of the flag
162
+ # @param default the default value of the flag; this is used if there is an error
163
+ # condition making it impossible to find or evaluate the flag
164
+ #
165
+ # @return the variation to show the user, or the default value if there's an an error
108
166
  #
109
- # @return the variation to show the user, or the
110
- # default value if there's an an error
111
167
  def variation(key, user, default)
112
168
  evaluate_internal(key, user, default, false).value
113
169
  end
114
170
 
115
171
  #
116
- # Determines the variation of a feature flag for a user, like `variation`, but also
172
+ # Determines the variation of a feature flag for a user, like {#variation}, but also
117
173
  # provides additional information about how this value was calculated.
118
174
  #
119
- # The return value of `variation_detail` is an `EvaluationDetail` object, which has
120
- # three properties:
121
- #
122
- # `value`: the value that was calculated for this user (same as the return value
123
- # of `variation`)
175
+ # The return value of `variation_detail` is an {EvaluationDetail} object, which has
176
+ # three properties: the result value, the positional index of this value in the flag's
177
+ # list of variations, and an object describing the main reason why this value was
178
+ # selected. See {EvaluationDetail} for more on these properties.
124
179
  #
125
- # `variation_index`: the positional index of this value in the flag, e.g. 0 for the
126
- # first variation - or `nil` if the default value was returned
180
+ # Calling `variation_detail` instead of `variation` also causes the "reason" data to
181
+ # be included in analytics events, if you are capturing detailed event data for this flag.
127
182
  #
128
- # `reason`: a hash describing the main reason why this value was selected. Its `:kind`
129
- # property will be one of the following:
130
- #
131
- # * `'OFF'`: the flag was off and therefore returned its configured off value
132
- # * `'FALLTHROUGH'`: the flag was on but the user did not match any targets or rules
133
- # * `'TARGET_MATCH'`: the user key was specifically targeted for this flag
134
- # * `'RULE_MATCH'`: the user matched one of the flag's rules; the `:ruleIndex` and
135
- # `:ruleId` properties indicate the positional index and unique identifier of the rule
136
- # * `'PREREQUISITE_FAILED`': the flag was considered off because it had at least one
137
- # prerequisite flag that either was off or did not return the desired variation; the
138
- # `:prerequisiteKey` property indicates the key of the prerequisite that failed
139
- # * `'ERROR'`: the flag could not be evaluated, e.g. because it does not exist or due
140
- # to an unexpected error, and therefore returned the default value; the `:errorKind`
141
- # property describes the nature of the error, such as `'FLAG_NOT_FOUND'`
142
- #
143
- # The `reason` will also be included in analytics events, if you are capturing
144
- # detailed event data for this flag.
183
+ # For more information, see the reference guide on
184
+ # [Evaluation reasons](https://docs.launchdarkly.com/v2.0/docs/evaluation-reasons).
145
185
  #
146
186
  # @param key [String] the unique feature key for the feature flag, as shown
147
187
  # on the LaunchDarkly dashboard
148
188
  # @param user [Hash] a hash containing parameters for the end user requesting the flag
149
- # @param default the default value of the flag
189
+ # @param default the default value of the flag; this is used if there is an error
190
+ # condition making it impossible to find or evaluate the flag
150
191
  #
151
- # @return an `EvaluationDetail` object describing the result
192
+ # @return [EvaluationDetail] an object describing the result
152
193
  #
153
194
  def variation_detail(key, user, default)
154
195
  evaluate_internal(key, user, default, true)
155
196
  end
156
197
 
157
198
  #
158
- # Registers the user
199
+ # Registers the user. This method simply creates an analytics event containing the user
200
+ # properties, so that LaunchDarkly will know about that user if it does not already.
159
201
  #
160
- # @param [Hash] The user to register
202
+ # Calling {#variation} or {#variation_detail} also sends the user information to
203
+ # LaunchDarkly (if events are enabled), so you only need to use {#identify} if you
204
+ # want to identify the user without evaluating a flag.
161
205
  #
206
+ # Note that event delivery is asynchronous, so the event may not actually be sent
207
+ # until later; see {#flush}.
208
+ #
209
+ # @param user [Hash] The user to register; this can have all the same user properties
210
+ # described in {#variation}
162
211
  # @return [void]
212
+ #
163
213
  def identify(user)
164
214
  sanitize_user(user)
165
215
  @event_processor.add_event(kind: "identify", key: user[:key], user: user)
166
216
  end
167
217
 
168
218
  #
169
- # Tracks that a user performed an event
219
+ # Tracks that a user performed an event. This method creates a "custom" analytics event
220
+ # containing the specified event name (key), user properties, and optional data.
221
+ #
222
+ # Note that event delivery is asynchronous, so the event may not actually be sent
223
+ # until later; see {#flush}.
170
224
  #
171
225
  # @param event_name [String] The name of the event
172
- # @param user [Hash] The user that performed the event. This should be the same user hash used in calls to {#toggle?}
226
+ # @param user [Hash] The user to register; this can have all the same user properties
227
+ # described in {#variation}
173
228
  # @param data [Hash] A hash containing any additional data associated with the event
174
- #
175
229
  # @return [void]
230
+ #
176
231
  def track(event_name, user, data)
177
232
  sanitize_user(user)
178
233
  @event_processor.add_event(kind: "custom", key: event_name, user: user, data: data)
179
234
  end
180
235
 
181
236
  #
182
- # Returns all feature flag values for the given user. This method is deprecated - please use
183
- # {#all_flags_state} instead. Current versions of the client-side SDK will not generate analytics
184
- # events correctly if you pass the result of all_flags.
237
+ # Returns all feature flag values for the given user.
238
+ #
239
+ # @deprecated Please use {#all_flags_state} instead. Current versions of the
240
+ # client-side SDK will not generate analytics events correctly if you pass the
241
+ # result of `all_flags`.
185
242
  #
186
243
  # @param user [Hash] The end user requesting the feature flags
187
244
  # @return [Hash] a hash of feature flag keys to values
@@ -191,21 +248,21 @@ module LaunchDarkly
191
248
  end
192
249
 
193
250
  #
194
- # Returns a FeatureFlagsState object that encapsulates the state of all feature flags for a given user,
251
+ # Returns a {FeatureFlagsState} object that encapsulates the state of all feature flags for a given user,
195
252
  # including the flag values and also metadata that can be used on the front end. This method does not
196
253
  # send analytics events back to LaunchDarkly.
197
254
  #
198
255
  # @param user [Hash] The end user requesting the feature flags
199
- # @param options={} [Hash] Optional parameters to control how the state is generated
256
+ # @param options [Hash] Optional parameters to control how the state is generated
200
257
  # @option options [Boolean] :client_side_only (false) True if only flags marked for use with the
201
258
  # client-side SDK should be included in the state. By default, all flags are included.
202
259
  # @option options [Boolean] :with_reasons (false) True if evaluation reasons should be included
203
- # in the state (see `variation_detail`). By default, they are not included.
260
+ # in the state (see {#variation_detail}). By default, they are not included.
204
261
  # @option options [Boolean] :details_only_for_tracked_flags (false) True if any flag metadata that is
205
- # normally only used for event generation - such as flag versions and evaluation reasons - should be
206
- # omitted for any flag that does not have event tracking or debugging turned on. This reduces the size
207
- # of the JSON data if you are passing the flag state to the front end.
208
- # @return [FeatureFlagsState] a FeatureFlagsState object which can be serialized to JSON
262
+ # normally only used for event generation - such as flag versions and evaluation reasons - should be
263
+ # omitted for any flag that does not have event tracking or debugging turned on. This reduces the size
264
+ # of the JSON data if you are passing the flag state to the front end.
265
+ # @return [FeatureFlagsState] a {FeatureFlagsState} object which can be serialized to JSON
209
266
  #
210
267
  def all_flags_state(user, options={})
211
268
  return FeatureFlagsState.new(false) if @config.offline?
@@ -246,19 +303,19 @@ module LaunchDarkly
246
303
  end
247
304
 
248
305
  #
249
- # Releases all network connections and other resources held by the client, making it no longer usable
306
+ # Releases all network connections and other resources held by the client, making it no longer usable.
250
307
  #
251
308
  # @return [void]
252
309
  def close
253
310
  @config.logger.info { "[LDClient] Closing LaunchDarkly client..." }
254
- @update_processor.stop
311
+ @data_source.stop
255
312
  @event_processor.stop
256
313
  @store.stop
257
314
  end
258
315
 
259
316
  private
260
317
 
261
- def create_default_update_processor(sdk_key, config)
318
+ def create_default_data_source(sdk_key, config)
262
319
  if config.offline?
263
320
  return NullUpdateProcessor.new
264
321
  end
@@ -351,6 +408,7 @@ module LaunchDarkly
351
408
 
352
409
  #
353
410
  # Used internally when the client is offline.
411
+ # @private
354
412
  #
355
413
  class NullUpdateProcessor
356
414
  def start