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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2234ff7c3580f12b981ce3bc6eb3215969d4a7e8
4
- data.tar.gz: d8c999182feacf6436ff83c896b3c44e36fbe62e
3
+ metadata.gz: 90690758415a43472c7c84ddd5f7d61b31849622
4
+ data.tar.gz: 2b3707dabf16cafd991c439b44c7ae4d14b4c94d
5
5
  SHA512:
6
- metadata.gz: 96b9510d2429a9ba9bc4bb2eb974acf37d86c566946696dd4987b4d267362c8a451856afd958e54f5f59b9de6713cea14f9bc91385927adc9f06e43101af4729
7
- data.tar.gz: '0891e7f45ac4fb5b7bb85ba234bdded350ccc45e6cc0db0a4e35f0a6699aac9b0041f2f0dad4f57f25ddf77e75b834d65a1335038b3501996a3fb176b1dc33ac'
6
+ metadata.gz: ee7396394f16fe7c98f49e293b1cf89956959ace1320bc8e5f6fa8c3c4bb8f8bc5b07e0a6bcd69f0a23007d41e6efa5b1bffa91bb3a8e96fbb73824226293f96
7
+ data.tar.gz: e91e83451a673f51f28b8d5c24e35192838e13e95eda4cc67db81d43e7766a071b3819646171cfa4800caaf748ae598f972c2e2bec889dece954a48a785fdebb
data/.circleci/config.yml CHANGED
@@ -19,7 +19,7 @@ ruby-docker-template: &ruby-docker-template
19
19
  gem install jruby-openssl; # required by bundler, no effect on Ruby MRI
20
20
  fi
21
21
  - run: ruby -v
22
- - run: gem install bundler -v "~> 1.7"
22
+ - run: gem install bundler -v 1.17.3
23
23
  - run: bundle install
24
24
  - run: mkdir ./rspec
25
25
  - run: bundle exec rspec --format progress --format RspecJunitFormatter -o ./rspec/rspec.xml spec
@@ -32,28 +32,38 @@ jobs:
32
32
  test-2.2:
33
33
  <<: *ruby-docker-template
34
34
  docker:
35
- - image: circleci/ruby:2.2.9-jessie
35
+ - image: circleci/ruby:2.2.10-jessie
36
+ - image: consul
36
37
  - image: redis
38
+ - image: amazon/dynamodb-local
37
39
  test-2.3:
38
40
  <<: *ruby-docker-template
39
41
  docker:
40
- - image: circleci/ruby:2.3.6-jessie
42
+ - image: circleci/ruby:2.3.7-jessie
43
+ - image: consul
41
44
  - image: redis
45
+ - image: amazon/dynamodb-local
42
46
  test-2.4:
43
47
  <<: *ruby-docker-template
44
48
  docker:
45
- - image: circleci/ruby:2.4.4-stretch
49
+ - image: circleci/ruby:2.4.5-stretch
50
+ - image: consul
46
51
  - image: redis
52
+ - image: amazon/dynamodb-local
47
53
  test-2.5:
48
54
  <<: *ruby-docker-template
49
55
  docker:
50
- - image: circleci/ruby:2.5.1-stretch
56
+ - image: circleci/ruby:2.5.3-stretch
57
+ - image: consul
51
58
  - image: redis
59
+ - image: amazon/dynamodb-local
52
60
  test-jruby-9.2:
53
61
  <<: *ruby-docker-template
54
62
  docker:
55
63
  - image: circleci/jruby:9-jdk
64
+ - image: consul
56
65
  - image: redis
66
+ - image: amazon/dynamodb-local
57
67
 
58
68
  # The following very slow job uses an Ubuntu container to run the Ruby versions that
59
69
  # CircleCI doesn't provide Docker images for.
@@ -63,8 +73,11 @@ jobs:
63
73
  environment:
64
74
  - RUBIES: "jruby-9.1.17.0"
65
75
  steps:
76
+ - run: sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
66
77
  - run: sudo apt-get -q update
67
78
  - run: sudo apt-get -qy install redis-server
79
+ - run: sudo apt-cache policy docker-ce
80
+ - run: sudo apt-get -qy install docker-ce
68
81
  - checkout
69
82
  - run:
70
83
  name: install all Ruby versions
@@ -82,10 +95,24 @@ jobs:
82
95
  fi
83
96
  # bundler 2.0 may be preinstalled, we need to remove it if so
84
97
  yes | gem uninstall bundler --version '>=2.0' || true;
85
- gem install bundler -v "~> 1.7";
98
+ gem install bundler -v 1.17.3;
86
99
  bundle install;
87
100
  mv Gemfile.lock "Gemfile.lock.$i"
88
101
  done
102
+ - run:
103
+ name: start DynamoDB
104
+ command: docker run -p 8000:8000 amazon/dynamodb-local
105
+ background: true
106
+ - run:
107
+ name: download Consul
108
+ command: wget https://releases.hashicorp.com/consul/0.8.0/consul_0.8.0_linux_amd64.zip
109
+ - run:
110
+ name: extract Consul
111
+ command: unzip consul_0.8.0_linux_amd64.zip
112
+ - run:
113
+ name: start Consul
114
+ command: ./consul agent -dev
115
+ background: true
89
116
  - run:
90
117
  name: run tests for all versions
91
118
  shell: /bin/bash -leo pipefail
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to the LaunchDarkly Ruby SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## [5.5.0] - 2019-01-17
6
+ ### Added:
7
+ - It is now possible to use Consul or DynamoDB as a persistent feature store, similar to the existing Redis integration. See the `LaunchDarkly::Integrations::Consul` and `LaunchDarkly::Integrations::DynamoDB` modules, and the reference guide [Using a persistent feature store](https://docs.launchdarkly.com/v2.0/docs/using-a-persistent-feature-store).
8
+ - There is now a `LaunchDarkly::Integrations::Redis` module, which is the preferred method for creating a Redis feature store.
9
+ - All of the database feature stores now support local caching not only for individual feature flag queries, but also for `all_flags_state`.
10
+ - The `Config` property `data_source` is the new name for `update_processor` and `update_processor_factory`.
11
+
12
+ ### Changed:
13
+ - The implementation of the SSE protocol for streaming has been moved into a separate gem, [`ld-eventsource`](https://github.com/launchdarkly/ruby-eventsource). This has no effect on streaming functionality.
14
+
15
+ ### Fixed:
16
+ - Added or corrected a large number of documentation comments. All API classes and methods are now documented, and internal implementation details have been hidden from the documentation. You can view the latest documentation on [RubyDoc](https://www.rubydoc.info/gems/ldclient-rb).
17
+ - Fixed a problem in the Redis feature store that would only happen under unlikely circumstances: trying to evaluate a flag when the LaunchDarkly client had not yet been fully initialized and the store did not yet have data in it, and then trying again when the client was still not ready but the store _did_ have data (presumably put there by another process). Previously, the second attempt would fail.
18
+ - In polling mode, the SDK did not correctly handle non-ASCII Unicode characters in feature flag data. ([#90](https://github.com/launchdarkly/ruby-client/issues/90))
19
+
20
+ ### Deprecated:
21
+ - `RedisFeatureStore.new`. This implementation class may be changed or moved in the future; use `LaunchDarkly::Integrations::Redis::new_feature_store`.
22
+ - `Config.update_processor` and `Config.update_processor_factory`; use `Config.data_source`.
23
+
5
24
  ## [5.4.3] - 2019-01-11
6
25
  ### Changed:
7
26
  - The SDK is now compatible with `net-http-persistent` 3.x. (Thanks, [CodingAnarchy](https://github.com/launchdarkly/ruby-client/pull/113)!)
data/CONTRIBUTING.md CHANGED
@@ -2,15 +2,3 @@ Contributing to LaunchDarkly SDK for Ruby
2
2
  =========================================
3
3
 
4
4
  We encourage pull-requests and other contributions from the community. We've also published an [SDK contributor's guide](http://docs.launchdarkly.com/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work.
5
-
6
- Dependencies
7
- ------------
8
- [ld-em-eventsource](https://github.com/launchdarkly/em-eventsource)
9
-
10
-
11
- Style
12
- -----
13
-
14
- Our pull requests have [Hound CI](https://houndci.com/) set up to do style checking.
15
- We also run [Rubocop](https://github.com/bbatsov/rubocop).
16
-
data/Gemfile.lock CHANGED
@@ -5,20 +5,33 @@ PATH
5
5
  concurrent-ruby (~> 1.0)
6
6
  faraday (>= 0.9, < 2)
7
7
  faraday-http-cache (>= 1.3.0, < 3)
8
- http_tools (~> 0.4.5)
9
8
  json (>= 1.8, < 3)
9
+ ld-eventsource (~> 1.0)
10
10
  net-http-persistent (>= 2.9, < 4.0)
11
11
  semantic (~> 1.6)
12
- socketry (~> 0.5.1)
13
12
 
14
13
  GEM
15
14
  remote: https://rubygems.org/
16
15
  specs:
16
+ aws-eventstream (1.0.1)
17
+ aws-partitions (1.128.0)
18
+ aws-sdk-core (3.44.2)
19
+ aws-eventstream (~> 1.0)
20
+ aws-partitions (~> 1.0)
21
+ aws-sigv4 (~> 1.0)
22
+ jmespath (~> 1.0)
23
+ aws-sdk-dynamodb (1.19.0)
24
+ aws-sdk-core (~> 3, >= 3.39.0)
25
+ aws-sigv4 (~> 1.0)
26
+ aws-sigv4 (1.0.3)
17
27
  codeclimate-test-reporter (0.6.0)
18
28
  simplecov (>= 0.7.1, < 1.0.0)
19
29
  concurrent-ruby (1.1.4)
20
30
  connection_pool (2.2.1)
21
31
  diff-lcs (1.3)
32
+ diplomat (2.0.2)
33
+ faraday (~> 0.9)
34
+ json
22
35
  docile (1.1.5)
23
36
  faraday (0.15.4)
24
37
  multipart-post (>= 1.2, < 3)
@@ -27,10 +40,14 @@ GEM
27
40
  ffi (1.9.25)
28
41
  ffi (1.9.25-java)
29
42
  hitimes (1.3.0)
30
- hitimes (1.3.0-java)
31
43
  http_tools (0.4.5)
44
+ jmespath (1.4.0)
32
45
  json (1.8.6)
33
46
  json (1.8.6-java)
47
+ ld-eventsource (1.0.0)
48
+ concurrent-ruby (~> 1.0)
49
+ http_tools (~> 0.4.5)
50
+ socketry (~> 0.5.1)
34
51
  listen (3.1.5)
35
52
  rb-fsevent (~> 0.9, >= 0.9.4)
36
53
  rb-inotify (~> 0.9, >= 0.9.7)
@@ -74,9 +91,11 @@ PLATFORMS
74
91
  ruby
75
92
 
76
93
  DEPENDENCIES
94
+ aws-sdk-dynamodb (~> 1.18)
77
95
  bundler (~> 1.7)
78
96
  codeclimate-test-reporter (~> 0)
79
97
  connection_pool (>= 2.1.2)
98
+ diplomat (>= 2.0.2)
80
99
  ldclient-rb!
81
100
  listen (~> 3.0)
82
101
  rake (~> 10.0)
data/README.md CHANGED
@@ -15,37 +15,37 @@ This version of the LaunchDarkly SDK has a minimum Ruby version of 2.2.6, or 9.1
15
15
  Quick setup
16
16
  -----------
17
17
 
18
- 0. Install the Ruby SDK with `gem`
18
+ 1. Install the Ruby SDK with `gem`
19
19
 
20
- ```shell
20
+ ```shell
21
21
  gem install ldclient-rb
22
22
  ```
23
23
 
24
- 1. Require the LaunchDarkly client:
24
+ 2. Require the LaunchDarkly client:
25
25
 
26
- ```ruby
26
+ ```ruby
27
27
  require 'ldclient-rb'
28
28
  ```
29
29
 
30
- 2. Create a new LDClient with your SDK key:
30
+ 3. Create a new LDClient with your SDK key:
31
31
 
32
- ```ruby
32
+ ```ruby
33
33
  client = LaunchDarkly::LDClient.new("your_sdk_key")
34
34
  ```
35
35
 
36
36
  ### Ruby on Rails
37
37
 
38
- 0. Add `gem 'ldclient-rb'` to your Gemfile and `bundle install`
38
+ 1. Add `gem 'ldclient-rb'` to your Gemfile and `bundle install`
39
39
 
40
- 1. Initialize the launchdarkly client in `config/initializers/launchdarkly.rb`:
40
+ 2. Initialize the launchdarkly client in `config/initializers/launchdarkly.rb`:
41
41
 
42
- ```ruby
42
+ ```ruby
43
43
  Rails.configuration.ld_client = LaunchDarkly::LDClient.new("your_sdk_key")
44
44
  ```
45
45
 
46
- 2. You may want to include a function in your ApplicationController
46
+ 3. You may want to include a function in your ApplicationController
47
47
 
48
- ```ruby
48
+ ```ruby
49
49
  def launchdarkly_settings
50
50
  if current_user.present?
51
51
  {
@@ -72,31 +72,44 @@ Rails.configuration.ld_client = LaunchDarkly::LDClient.new("your_sdk_key")
72
72
  end
73
73
  ```
74
74
 
75
- 3. In your controllers, access the client using
75
+ 4. In your controllers, access the client using
76
76
 
77
- ```ruby
77
+ ```ruby
78
78
  Rails.application.config.ld_client.variation('your.flag.key', launchdarkly_settings, false)
79
79
  ```
80
80
 
81
81
  Note that this gem will automatically switch to using the Rails logger it is detected.
82
82
 
83
83
 
84
+ Your first feature flag
85
+ -----------------------
86
+
87
+ 1. Create a new feature flag on your [dashboard](https://app.launchdarkly.com).
88
+ 2. In your application code, use the feature's key to check whether the flag is on for each user:
89
+
90
+ ```ruby
91
+ if client.variation("your.flag.key", {key: "user@test.com"}, false)
92
+ # application code to show the feature
93
+ else
94
+ # the code to run if the feature is off
95
+ end
96
+ ```
97
+
84
98
  HTTPS proxy
85
- ------------
86
- The Ruby SDK uses Faraday and Socketry to handle its network traffic. Both of these provide built-in support for the use of an HTTPS proxy. If the HTTPS_PROXY environment variable is present then the SDK will proxy all network requests through the URL provided.
99
+ -----------
100
+
101
+ The Ruby SDK uses Faraday and Socketry to handle its network traffic. Both of these provide built-in support for the use of an HTTPS proxy. If the HTTPS_PROXY environment variable is present then the SDK will proxy all network requests through the URL provided. (HTTP_PROXY is not used because all LaunchDarkly services require HTTPS.)
87
102
 
88
103
  How to set the HTTPS_PROXY environment variable on Mac/Linux systems:
89
104
  ```
90
105
  export HTTPS_PROXY=https://web-proxy.domain.com:8080
91
106
  ```
92
107
 
93
-
94
108
  How to set the HTTPS_PROXY environment variable on Windows systems:
95
109
  ```
96
110
  set HTTPS_PROXY=https://web-proxy.domain.com:8080
97
111
  ```
98
112
 
99
-
100
113
  If your proxy requires authentication then you can prefix the URN with your login information:
101
114
  ```
102
115
  export HTTPS_PROXY=http://user:pass@web-proxy.domain.com:8080
@@ -106,29 +119,22 @@ or
106
119
  set HTTPS_PROXY=http://user:pass@web-proxy.domain.com:8080
107
120
  ```
108
121
 
122
+ Database integrations
123
+ ---------------------
109
124
 
110
- Your first feature flag
111
- -----------------------
112
-
113
- 1. Create a new feature flag on your [dashboard](https://app.launchdarkly.com)
114
- 2. In your application code, use the feature's key to check whether the flag is on for each user:
115
-
116
- ```ruby
117
- if client.variation("your.flag.key", {key: "user@test.com"}, false)
118
- # application code to show the feature
119
- else
120
- # the code to run if the feature is off
121
- end
122
- ```
125
+ Feature flag data can be kept in a persistent store using Redis, DynamoDB, or Consul. These adapters are implemented in the `LaunchDarkly::Integrations::Redis`, `LaunchDarkly::Integrations::DynamoDB`, and `LaunchDarkly::Integrations::Consul` modules; to use them, call the `new_feature_store` method in the module, and put the returned object in the `feature_store` property of your client configuration. See the [API documentation](https://www.rubydoc.info/gems/ldclient-rb/LaunchDarkly/Integrations) and the [SDK reference guide](https://docs.launchdarkly.com/v2.0/docs/using-a-persistent-feature-store) for more information.
123
126
 
124
127
  Using flag data from a file
125
128
  ---------------------------
126
- For testing purposes, the SDK can be made to read feature flag state from a file or files instead of connecting to LaunchDarkly. See [`file_data_source.rb`](https://github.com/launchdarkly/ruby-client/blob/master/lib/ldclient-rb/file_data_source.rb) for more details.
129
+
130
+ For testing purposes, the SDK can be made to read feature flag state from a file or files instead of connecting to LaunchDarkly. See `LaunchDarkly::FileDataSource` or the [SDK reference guide](https://docs.launchdarkly.com/v2.0/docs/reading-flags-from-a-file) for more details.
127
131
 
128
132
  Learn more
129
133
  -----------
130
134
 
131
- Check out our [documentation](http://docs.launchdarkly.com) for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the [complete reference guide for this SDK](http://docs.launchdarkly.com/docs/ruby-sdk-reference).
135
+ Check out our [documentation](http://docs.launchdarkly.com) for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the [reference guide for this SDK](http://docs.launchdarkly.com/docs/ruby-sdk-reference).
136
+
137
+ Generated API documentation is on [RubyDoc.info](https://www.rubydoc.info/gems/ldclient-rb).
132
138
 
133
139
  Testing
134
140
  -------
@@ -138,10 +144,10 @@ We run integration tests for all our SDKs using a centralized test harness. This
138
144
  Contributing
139
145
  ------------
140
146
 
141
- See [Contributing](https://github.com/launchdarkly/ruby-client/blob/master/CONTRIBUTING.md)
147
+ See [Contributing](https://github.com/launchdarkly/ruby-client/blob/master/CONTRIBUTING.md).
142
148
 
143
149
  About LaunchDarkly
144
- -----------
150
+ ------------------
145
151
 
146
152
  * LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
147
153
  * Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.
@@ -153,9 +159,9 @@ About LaunchDarkly
153
159
  * [JavaScript](http://docs.launchdarkly.com/docs/js-sdk-reference "LaunchDarkly JavaScript SDK")
154
160
  * [PHP](http://docs.launchdarkly.com/docs/php-sdk-reference "LaunchDarkly PHP SDK")
155
161
  * [Python](http://docs.launchdarkly.com/docs/python-sdk-reference "LaunchDarkly Python SDK")
156
- * [Python Twisted](http://docs.launchdarkly.com/docs/python-twisted-sdk-reference "LaunchDarkly Python Twisted SDK")
157
162
  * [Go](http://docs.launchdarkly.com/docs/go-sdk-reference "LaunchDarkly Go SDK")
158
163
  * [Node.JS](http://docs.launchdarkly.com/docs/node-sdk-reference "LaunchDarkly Node SDK")
164
+ * [Electron](http://docs.launchdarkly.com/docs/electron-sdk-reference "LaunchDarkly Electron SDK")
159
165
  * [.NET](http://docs.launchdarkly.com/docs/dotnet-sdk-reference "LaunchDarkly .Net SDK")
160
166
  * [Ruby](http://docs.launchdarkly.com/docs/ruby-sdk-reference "LaunchDarkly Ruby SDK")
161
167
  * [iOS](http://docs.launchdarkly.com/docs/ios-sdk-reference "LaunchDarkly iOS SDK")
data/ldclient-rb.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.summary = "LaunchDarkly SDK for Ruby"
14
14
  spec.description = "Official LaunchDarkly SDK for Ruby"
15
15
  spec.homepage = "https://github.com/launchdarkly/ruby-client"
16
- spec.license = "Apache 2.0"
16
+ spec.license = "Apache-2.0"
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -21,9 +21,11 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
  spec.extensions = 'ext/mkrf_conf.rb'
23
23
 
24
+ spec.add_development_dependency "aws-sdk-dynamodb", "~> 1.18"
24
25
  spec.add_development_dependency "bundler", "~> 1.7"
25
26
  spec.add_development_dependency "rspec", "~> 3.2"
26
27
  spec.add_development_dependency "codeclimate-test-reporter", "~> 0"
28
+ spec.add_development_dependency "diplomat", ">= 2.0.2"
27
29
  spec.add_development_dependency "redis", "~> 3.3.5"
28
30
  spec.add_development_dependency "connection_pool", ">= 2.1.2"
29
31
  spec.add_development_dependency "rake", "~> 10.0"
@@ -37,6 +39,5 @@ Gem::Specification.new do |spec|
37
39
  spec.add_runtime_dependency "semantic", "~> 1.6"
38
40
  spec.add_runtime_dependency "net-http-persistent", [">= 2.9", "< 4.0"]
39
41
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
40
- spec.add_runtime_dependency "http_tools", '~> 0.4.5'
41
- spec.add_runtime_dependency "socketry", "~> 0.5.1"
42
+ spec.add_runtime_dependency "ld-eventsource", '~> 1.0'
42
43
  end
data/lib/ldclient-rb.rb CHANGED
@@ -1,4 +1,12 @@
1
+
2
+ #
3
+ # Namespace for the LaunchDarkly Ruby SDK.
4
+ #
5
+ module LaunchDarkly
6
+ end
7
+
1
8
  require "ldclient-rb/version"
9
+ require "ldclient-rb/interfaces"
2
10
  require "ldclient-rb/util"
3
11
  require "ldclient-rb/evaluation"
4
12
  require "ldclient-rb/flags_state"
@@ -16,6 +24,6 @@ require "ldclient-rb/simple_lru_cache"
16
24
  require "ldclient-rb/non_blocking_thread_pool"
17
25
  require "ldclient-rb/event_summarizer"
18
26
  require "ldclient-rb/events"
19
- require "ldclient-rb/redis_store"
20
27
  require "ldclient-rb/requestor"
21
28
  require "ldclient-rb/file_data_source"
29
+ require "ldclient-rb/integrations"
@@ -7,6 +7,7 @@ module LaunchDarkly
7
7
  #
8
8
  # @see https://github.com/plataformatec/faraday-http-cache
9
9
  # @see https://github.com/ruby-concurrency
10
+ # @private
10
11
  #
11
12
  class ThreadSafeMemoryStore
12
13
  #
@@ -8,66 +8,36 @@ module LaunchDarkly
8
8
  #
9
9
  #
10
10
  class Config
11
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
12
+
11
13
  #
12
14
  # Constructor for creating custom LaunchDarkly configurations.
13
15
  #
14
16
  # @param opts [Hash] the configuration options
15
- # @option opts [Logger] :logger A logger to use for messages from the
16
- # LaunchDarkly client. Defaults to the Rails logger in a Rails
17
- # environment, or stdout otherwise.
18
- # @option opts [String] :base_uri ("https://app.launchdarkly.com") The base
19
- # URL for the LaunchDarkly server. Most users should use the default value.
20
- # @option opts [String] :stream_uri ("https://stream.launchdarkly.com") The
21
- # URL for the LaunchDarkly streaming events server. Most users should use the default value.
22
- # @option opts [String] :events_uri ("https://events.launchdarkly.com") The
23
- # URL for the LaunchDarkly events server. Most users should use the default value.
24
- # @option opts [Integer] :capacity (10000) The capacity of the events
25
- # buffer. The client buffers up to this many events in memory before
26
- # flushing. If the capacity is exceeded before the buffer is flushed,
27
- # events will be discarded.
28
- # @option opts [Float] :flush_interval (30) The number of seconds between
29
- # flushes of the event buffer.
30
- # @option opts [Float] :read_timeout (10) The read timeout for network
31
- # connections in seconds.
32
- # @option opts [Float] :connect_timeout (2) The connect timeout for network
33
- # connections in seconds.
34
- # @option opts [Object] :cache_store A cache store for the Faraday HTTP caching
35
- # library. Defaults to the Rails cache in a Rails environment, or a
36
- # thread-safe in-memory store otherwise.
37
- # @option opts [Object] :feature_store A store for feature flags and related data. Defaults to an in-memory
38
- # cache, or you can use RedisFeatureStore.
39
- # @option opts [Boolean] :use_ldd (false) Whether you are using the LaunchDarkly relay proxy in
40
- # daemon mode. In this configuration, the client will not use a streaming connection to listen
41
- # for updates, but instead will get feature state from a Redis instance. The `stream` and
42
- # `poll_interval` options will be ignored if this option is set to true.
43
- # @option opts [Boolean] :offline (false) Whether the client should be initialized in
44
- # offline mode. In offline mode, default values are returned for all flags and no
45
- # remote network requests are made.
46
- # @option opts [Float] :poll_interval (30) The number of seconds between polls for flag updates
47
- # if streaming is off.
48
- # @option opts [Boolean] :stream (true) Whether or not the streaming API should be used to receive flag updates.
49
- # Streaming should only be disabled on the advice of LaunchDarkly support.
50
- # @option opts [Boolean] all_attributes_private (false) If true, all user attributes (other than the key)
51
- # will be private, not just the attributes specified in `private_attribute_names`.
52
- # @option opts [Array] :private_attribute_names Marks a set of attribute names private. Any users sent to
53
- # LaunchDarkly with this configuration active will have attributes with these names removed.
54
- # @option opts [Boolean] :send_events (true) Whether or not to send events back to LaunchDarkly.
55
- # This differs from `offline` in that it affects only the sending of client-side events, not
56
- # streaming or polling for events from the server.
57
- # @option opts [Integer] :user_keys_capacity (1000) The number of user keys that the event processor
58
- # can remember at any one time, so that duplicate user details will not be sent in analytics events.
59
- # @option opts [Float] :user_keys_flush_interval (300) The interval in seconds at which the event
60
- # processor will reset its set of known user keys.
61
- # @option opts [Boolean] :inline_users_in_events (false) Whether to include full user details in every
62
- # analytics event. By default, events will only include the user key, except for one "index" event
63
- # that provides the full details for the user.
64
- # @option opts [Object] :update_processor (DEPRECATED) An object that will receive feature flag data from
65
- # LaunchDarkly. Defaults to either the streaming or the polling processor, can be customized for tests.
66
- # @option opts [Object] :update_processor_factory A function that takes the SDK and configuration object
67
- # as parameters, and returns an object that can obtain feature flag data and put it into the feature
68
- # store. Defaults to creating either the streaming or the polling processor, can be customized for tests.
69
- # @return [type] [description]
70
- # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
17
+ # @option opts [Logger] :logger See {#logger}.
18
+ # @option opts [String] :base_uri ("https://app.launchdarkly.com") See {#base_uri}.
19
+ # @option opts [String] :stream_uri ("https://stream.launchdarkly.com") See {#stream_uri}.
20
+ # @option opts [String] :events_uri ("https://events.launchdarkly.com") See {#events_uri}.
21
+ # @option opts [Integer] :capacity (10000) See {#capacity}.
22
+ # @option opts [Float] :flush_interval (30) See {#flush_interval}.
23
+ # @option opts [Float] :read_timeout (10) See {#read_timeout}.
24
+ # @option opts [Float] :connect_timeout (2) See {#connect_timeout}.
25
+ # @option opts [Object] :cache_store See {#cache_store}.
26
+ # @option opts [Object] :feature_store See {#feature_store}.
27
+ # @option opts [Boolean] :use_ldd (false) See {#use_ldd?}.
28
+ # @option opts [Boolean] :offline (false) See {#offline?}.
29
+ # @option opts [Float] :poll_interval (30) See {#poll_interval}.
30
+ # @option opts [Boolean] :stream (true) See {#stream?}.
31
+ # @option opts [Boolean] all_attributes_private (false) See {#all_attributes_private}.
32
+ # @option opts [Array] :private_attribute_names See {#private_attribute_names}.
33
+ # @option opts [Boolean] :send_events (true) See {#send_events}.
34
+ # @option opts [Integer] :user_keys_capacity (1000) See {#user_keys_capacity}.
35
+ # @option opts [Float] :user_keys_flush_interval (300) See {#user_keys_flush_interval}.
36
+ # @option opts [Boolean] :inline_users_in_events (false) See {#inline_users_in_events}.
37
+ # @option opts [Object] :data_source See {#data_source}.
38
+ # @option opts [Object] :update_processor Obsolete synonym for `data_source`.
39
+ # @option opts [Object] :update_processor_factory Obsolete synonym for `data_source`.
40
+ #
71
41
  def initialize(opts = {})
72
42
  @base_uri = (opts[:base_uri] || Config.default_base_uri).chomp("/")
73
43
  @stream_uri = (opts[:stream_uri] || Config.default_stream_uri).chomp("/")
@@ -90,48 +60,62 @@ module LaunchDarkly
90
60
  @user_keys_capacity = opts[:user_keys_capacity] || Config.default_user_keys_capacity
91
61
  @user_keys_flush_interval = opts[:user_keys_flush_interval] || Config.default_user_keys_flush_interval
92
62
  @inline_users_in_events = opts[:inline_users_in_events] || false
63
+ @data_source = opts[:data_source] || opts[:update_processor] || opts[:update_processor_factory]
93
64
  @update_processor = opts[:update_processor]
94
65
  @update_processor_factory = opts[:update_processor_factory]
95
66
  end
96
67
 
97
68
  #
98
- # The base URL for the LaunchDarkly server.
69
+ # The base URL for the LaunchDarkly server. This is configurable mainly for testing
70
+ # purposes; most users should use the default value.
71
+ # @return [String]
99
72
  #
100
- # @return [String] The configured base URL for the LaunchDarkly server.
101
73
  attr_reader :base_uri
102
74
 
103
75
  #
104
- # The base URL for the LaunchDarkly streaming server.
76
+ # The base URL for the LaunchDarkly streaming server. This is configurable mainly for testing
77
+ # purposes; most users should use the default value.
78
+ # @return [String]
105
79
  #
106
- # @return [String] The configured base URL for the LaunchDarkly streaming server.
107
80
  attr_reader :stream_uri
108
81
 
109
82
  #
110
- # The base URL for the LaunchDarkly events server.
83
+ # The base URL for the LaunchDarkly events server. This is configurable mainly for testing
84
+ # purposes; most users should use the default value.
85
+ # @return [String]
111
86
  #
112
- # @return [String] The configured base URL for the LaunchDarkly events server.
113
87
  attr_reader :events_uri
114
88
 
115
89
  #
116
90
  # Whether streaming mode should be enabled. Streaming mode asynchronously updates
117
- # feature flags in real-time using server-sent events.
91
+ # feature flags in real-time using server-sent events. Streaming is enabled by default, and
92
+ # should only be disabled on the advice of LaunchDarkly support.
93
+ # @return [Boolean]
118
94
  #
119
- # @return [Boolean] True if streaming mode should be enabled
120
95
  def stream?
121
96
  @stream
122
97
  end
123
98
 
124
99
  #
125
- # Whether to use the LaunchDarkly relay proxy in daemon mode. In this mode, we do
126
- # not use polling or streaming to get feature flag updates from the server, but instead
127
- # read them from a Redis instance that is updated by the proxy.
100
+ # Whether to use the LaunchDarkly relay proxy in daemon mode. In this mode, the client does not
101
+ # use polling or streaming to get feature flag updates from the server, but instead reads them
102
+ # from the {#feature_store feature store}, which is assumed to be a database that is populated by
103
+ # a LaunchDarkly relay proxy. For more information, see ["The relay proxy"](https://docs.launchdarkly.com/v2.0/docs/the-relay-proxy)
104
+ # and ["Using a persistent feature store"](https://docs.launchdarkly.com/v2.0/docs/using-a-persistent-feature-store).
105
+ #
106
+ # All other properties related to streaming or polling are ignored if this option is set to true.
107
+ #
108
+ # @return [Boolean]
128
109
  #
129
- # @return [Boolean] True if using the LaunchDarkly relay proxy in daemon mode
130
110
  def use_ldd?
131
111
  @use_ldd
132
112
  end
133
113
 
134
- # TODO docs
114
+ #
115
+ # Whether the client should be initialized in offline mode. In offline mode, default values are
116
+ # returned for all flags and no remote network requests are made.
117
+ # @return [Boolean]
118
+ #
135
119
  def offline?
136
120
  @offline
137
121
  end
@@ -139,20 +123,23 @@ module LaunchDarkly
139
123
  #
140
124
  # The number of seconds between flushes of the event buffer. Decreasing the flush interval means
141
125
  # that the event buffer is less likely to reach capacity.
126
+ # @return [Float]
142
127
  #
143
- # @return [Float] The configured number of seconds between flushes of the event buffer.
144
128
  attr_reader :flush_interval
145
129
 
146
130
  #
147
131
  # The number of seconds to wait before polling for feature flag updates. This option has no
148
- # effect unless streaming is disabled
132
+ # effect unless streaming is disabled.
133
+ # @return [Float]
134
+ #
149
135
  attr_reader :poll_interval
150
136
 
151
137
  #
152
138
  # The configured logger for the LaunchDarkly client. The client library uses the log to
153
- # print warning and error messages.
139
+ # print warning and error messages. If not specified, this defaults to the Rails logger
140
+ # in a Rails environment, or stdout otherwise.
141
+ # @return [Logger]
154
142
  #
155
- # @return [Logger] The configured logger
156
143
  attr_reader :logger
157
144
 
158
145
  #
@@ -161,114 +148,206 @@ module LaunchDarkly
161
148
  # the buffer is flushed, events will be discarded.
162
149
  # Increasing the capacity means that events are less likely to be discarded,
163
150
  # at the cost of consuming more memory.
151
+ # @return [Integer]
164
152
  #
165
- # @return [Integer] The configured capacity of the event buffer
166
153
  attr_reader :capacity
167
154
 
168
155
  #
169
- # The store for the Faraday HTTP caching library. Stores should respond to
170
- # 'read' and 'write' requests.
156
+ # A store for HTTP caching. This must support the semantics used by the
157
+ # [`faraday-http-cache`](https://github.com/plataformatec/faraday-http-cache) gem. Defaults
158
+ # to the Rails cache in a Rails environment, or a thread-safe in-memory store otherwise.
159
+ # @return [Object]
171
160
  #
172
- # @return [Object] The configured store for the Faraday HTTP caching library.
173
161
  attr_reader :cache_store
174
162
 
175
163
  #
176
- # The read timeout for network connections in seconds.
164
+ # The read timeout for network connections in seconds. This does not apply to the streaming
165
+ # connection, which uses a longer timeout since the server does not send data constantly.
166
+ # @return [Float]
177
167
  #
178
- # @return [Float] The read timeout in seconds.
179
168
  attr_reader :read_timeout
180
169
 
181
170
  #
182
171
  # The connect timeout for network connections in seconds.
172
+ # @return [Float]
183
173
  #
184
- # @return [Float] The connect timeout in seconds.
185
174
  attr_reader :connect_timeout
186
175
 
187
176
  #
188
- # A store for feature flag configuration rules.
177
+ # A store for feature flags and related data. The client uses it to store all data received
178
+ # from LaunchDarkly, and uses the last stored data when evaluating flags. Defaults to
179
+ # {InMemoryFeatureStore}; for other implementations, see {LaunchDarkly::Integrations}.
180
+ #
181
+ # For more information, see ["Using a persistent feature store"](https://docs.launchdarkly.com/v2.0/docs/using-a-persistent-feature-store).
182
+ #
183
+ # @return [LaunchDarkly::Interfaces::FeatureStore]
189
184
  #
190
185
  attr_reader :feature_store
191
186
 
192
- # The proxy configuration string
187
+ #
188
+ # The proxy configuration string.
189
+ # @return [String]
193
190
  #
194
191
  attr_reader :proxy
195
192
 
193
+ #
194
+ # True if all user attributes (other than the key) should be considered private. This means
195
+ # that the attribute values will not be sent to LaunchDarkly in analytics events and will not
196
+ # appear on the LaunchDarkly dashboard.
197
+ # @return [Boolean]
198
+ # @see #private_attribute_names
199
+ #
196
200
  attr_reader :all_attributes_private
197
201
 
202
+ #
203
+ # A list of user attribute names that should always be considered private. This means that the
204
+ # attribute values will not be sent to LaunchDarkly in analytics events and will not appear on
205
+ # the LaunchDarkly dashboard.
206
+ #
207
+ # You can also specify the same behavior for an individual flag evaluation by storing an array
208
+ # of attribute names in the `:privateAttributeNames` property (note camelcase name) of the
209
+ # user object.
210
+ #
211
+ # @return [Array<String>]
212
+ # @see #all_attributes_private
213
+ #
198
214
  attr_reader :private_attribute_names
199
215
 
200
216
  #
201
- # Whether to send events back to LaunchDarkly.
217
+ # Whether to send events back to LaunchDarkly. This differs from {#offline?} in that it affects
218
+ # only the sending of client-side events, not streaming or polling for events from the server.
219
+ # @return [Boolean]
202
220
  #
203
221
  attr_reader :send_events
204
222
 
205
223
  #
206
- # The number of user keys that the event processor can remember at any one time, so that
207
- # duplicate user details will not be sent in analytics events.
224
+ # The number of user keys that the event processor can remember at any one time. This reduces the
225
+ # amount of duplicate user details sent in analytics events.
226
+ # @return [Integer]
227
+ # @see #user_keys_flush_interval
208
228
  #
209
229
  attr_reader :user_keys_capacity
210
230
 
211
231
  #
212
232
  # The interval in seconds at which the event processor will reset its set of known user keys.
233
+ # @return [Float]
234
+ # @see #user_keys_capacity
213
235
  #
214
236
  attr_reader :user_keys_flush_interval
215
237
 
216
238
  #
217
- # Whether to include full user details in every
218
- # analytics event. By default, events will only include the user key, except for one "index" event
219
- # that provides the full details for the user.
239
+ # Whether to include full user details in every analytics event. By default, events will only
240
+ # include the user key, except for one "index" event that provides the full details for the user.
241
+ # The only reason to change this is if you are using the Analytics Data Stream.
242
+ # @return [Boolean]
220
243
  #
221
244
  attr_reader :inline_users_in_events
222
245
 
246
+ #
247
+ # An object that is responsible for receiving feature flag data from LaunchDarkly. By default,
248
+ # the client uses its standard polling or streaming implementation; this is customizable for
249
+ # testing purposes.
250
+ #
251
+ # This may be set to either an object that conforms to {LaunchDarkly::Interfaces::DataSource},
252
+ # or a lambda (or Proc) that takes two parameters-- SDK key and {Config}-- and returns such an
253
+ # object.
254
+ #
255
+ # @return [LaunchDarkly::Interfaces::DataSource|lambda]
256
+ # @see FileDataSource
257
+ #
258
+ attr_reader :data_source
259
+
260
+ # @deprecated This is replaced by {#data_source}.
223
261
  attr_reader :update_processor
224
262
 
263
+ # @deprecated This is replaced by {#data_source}.
225
264
  attr_reader :update_processor_factory
226
-
265
+
227
266
  #
228
267
  # The default LaunchDarkly client configuration. This configuration sets
229
268
  # reasonable defaults for most users.
230
- #
231
269
  # @return [Config] The default LaunchDarkly configuration.
270
+ #
232
271
  def self.default
233
272
  Config.new
234
273
  end
235
274
 
275
+ #
276
+ # The default value for {#capacity}.
277
+ # @return [Integer] 10000
278
+ #
236
279
  def self.default_capacity
237
280
  10000
238
281
  end
239
282
 
283
+ #
284
+ # The default value for {#base_uri}.
285
+ # @return [String] "https://app.launchdarkly.com"
286
+ #
240
287
  def self.default_base_uri
241
288
  "https://app.launchdarkly.com"
242
289
  end
243
290
 
291
+ #
292
+ # The default value for {#stream_uri}.
293
+ # @return [String] "https://stream.launchdarkly.com"
294
+ #
244
295
  def self.default_stream_uri
245
296
  "https://stream.launchdarkly.com"
246
297
  end
247
298
 
299
+ #
300
+ # The default value for {#events_uri}.
301
+ # @return [String] "https://events.launchdarkly.com"
302
+ #
248
303
  def self.default_events_uri
249
304
  "https://events.launchdarkly.com"
250
305
  end
251
306
 
307
+ #
308
+ # The default value for {#cache_store}.
309
+ # @return [Object] the Rails cache if in Rails, or a simple in-memory implementation otherwise
310
+ #
252
311
  def self.default_cache_store
253
312
  defined?(Rails) && Rails.respond_to?(:cache) ? Rails.cache : ThreadSafeMemoryStore.new
254
313
  end
255
314
 
315
+ #
316
+ # The default value for {#flush_interval}.
317
+ # @return [Float] 10
318
+ #
256
319
  def self.default_flush_interval
257
320
  10
258
321
  end
259
322
 
323
+ #
324
+ # The default value for {#read_timeout}.
325
+ # @return [Float] 10
326
+ #
260
327
  def self.default_read_timeout
261
328
  10
262
329
  end
263
330
 
331
+ #
332
+ # The default value for {#connect_timeout}.
333
+ # @return [Float] 10
334
+ #
264
335
  def self.default_connect_timeout
265
336
  2
266
337
  end
267
338
 
339
+ #
340
+ # The default value for {#proxy}.
341
+ # @return [String] nil
342
+ #
268
343
  def self.default_proxy
269
344
  nil
270
345
  end
271
346
 
347
+ #
348
+ # The default value for {#logger}.
349
+ # @return [Logger] the Rails logger if in Rails, or a default Logger at WARN level otherwise
350
+ #
272
351
  def self.default_logger
273
352
  if defined?(Rails) && Rails.respond_to?(:logger)
274
353
  Rails.logger
@@ -279,34 +358,66 @@ module LaunchDarkly
279
358
  end
280
359
  end
281
360
 
361
+ #
362
+ # The default value for {#stream?}.
363
+ # @return [Boolean] true
364
+ #
282
365
  def self.default_stream
283
366
  true
284
367
  end
285
368
 
369
+ #
370
+ # The default value for {#use_ldd?}.
371
+ # @return [Boolean] false
372
+ #
286
373
  def self.default_use_ldd
287
374
  false
288
375
  end
289
376
 
377
+ #
378
+ # The default value for {#feature_store}.
379
+ # @return [LaunchDarkly::Interfaces::FeatureStore] an {InMemoryFeatureStore}
380
+ #
290
381
  def self.default_feature_store
291
382
  InMemoryFeatureStore.new
292
383
  end
293
384
 
385
+ #
386
+ # The default value for {#offline?}.
387
+ # @return [Boolean] false
388
+ #
294
389
  def self.default_offline
295
390
  false
296
391
  end
297
392
 
393
+ #
394
+ # The default value for {#poll_interval}.
395
+ # @return [Float] 30
396
+ #
298
397
  def self.default_poll_interval
299
398
  30
300
399
  end
301
400
 
401
+ #
402
+ # The default value for {#send_events}.
403
+ # @return [Boolean] true
404
+ #
302
405
  def self.default_send_events
303
406
  true
304
407
  end
305
408
 
409
+ #
410
+ # The default value for {#user_keys_capacity}.
411
+ # @return [Integer] 1000
412
+ #
306
413
  def self.default_user_keys_capacity
307
414
  1000
308
415
  end
309
416
 
417
+ #
418
+ # The default value for {#user_keys_flush_interval}.
419
+ # @return [Float] 300
420
+ #
310
421
  def self.default_user_keys_flush_interval
311
422
  300
312
423
  end