ldclient-rb 5.4.3 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
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