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
@@ -7,8 +7,8 @@ describe LaunchDarkly::LDClient do
7
7
  let(:offline_client) do
8
8
  subject.new("secret", offline_config)
9
9
  end
10
- let(:update_processor) { LaunchDarkly::NullUpdateProcessor.new }
11
- let(:config) { LaunchDarkly::Config.new({send_events: false, update_processor: update_processor}) }
10
+ let(:null_data) { LaunchDarkly::NullUpdateProcessor.new }
11
+ let(:config) { LaunchDarkly::Config.new({send_events: false, data_source: null_data}) }
12
12
  let(:client) do
13
13
  subject.new("secret", config)
14
14
  end
@@ -357,7 +357,7 @@ describe LaunchDarkly::LDClient do
357
357
  end
358
358
 
359
359
  describe 'with send_events: false' do
360
- let(:config) { LaunchDarkly::Config.new({offline: true, send_events: false, update_processor: update_processor}) }
360
+ let(:config) { LaunchDarkly::Config.new({offline: true, send_events: false, data_source: null_data}) }
361
361
  let(:client) { subject.new("secret", config) }
362
362
 
363
363
  it "uses a NullEventProcessor" do
@@ -367,7 +367,7 @@ describe LaunchDarkly::LDClient do
367
367
  end
368
368
 
369
369
  describe 'with send_events: true' do
370
- let(:config_with_events) { LaunchDarkly::Config.new({offline: false, send_events: true, update_processor: update_processor}) }
370
+ let(:config_with_events) { LaunchDarkly::Config.new({offline: false, send_events: true, data_source: null_data}) }
371
371
  let(:client_with_events) { subject.new("secret", config_with_events) }
372
372
 
373
373
  it "does not use a NullEventProcessor" do
@@ -375,4 +375,83 @@ describe LaunchDarkly::LDClient do
375
375
  expect(ep).not_to be_a(LaunchDarkly::NullEventProcessor)
376
376
  end
377
377
  end
378
+
379
+ describe "feature store data ordering" do
380
+ let(:dependency_ordering_test_data) {
381
+ {
382
+ LaunchDarkly::FEATURES => {
383
+ a: { key: "a", prerequisites: [ { key: "b" }, { key: "c" } ] },
384
+ b: { key: "b", prerequisites: [ { key: "c" }, { key: "e" } ] },
385
+ c: { key: "c" },
386
+ d: { key: "d" },
387
+ e: { key: "e" },
388
+ f: { key: "f" }
389
+ },
390
+ LaunchDarkly::SEGMENTS => {
391
+ o: { key: "o" }
392
+ }
393
+ }
394
+ }
395
+
396
+ class FakeFeatureStore
397
+ attr_reader :received_data
398
+
399
+ def init(all_data)
400
+ @received_data = all_data
401
+ end
402
+ end
403
+
404
+ class FakeUpdateProcessor
405
+ def initialize(store, data)
406
+ @store = store
407
+ @data = data
408
+ end
409
+
410
+ def start
411
+ @store.init(@data)
412
+ ev = Concurrent::Event.new
413
+ ev.set
414
+ ev
415
+ end
416
+
417
+ def stop
418
+ end
419
+
420
+ def initialized?
421
+ true
422
+ end
423
+ end
424
+
425
+ it "passes data set to feature store in correct order on init" do
426
+ store = FakeFeatureStore.new
427
+ data_source_factory = lambda { |sdk_key, config| FakeUpdateProcessor.new(config.feature_store,
428
+ dependency_ordering_test_data) }
429
+ config = LaunchDarkly::Config.new(send_events: false, feature_store: store, data_source: data_source_factory)
430
+ client = subject.new("secret", config)
431
+
432
+ data = store.received_data
433
+ expect(data).not_to be_nil
434
+ expect(data.count).to eq(2)
435
+
436
+ # Segments should always come first
437
+ expect(data.keys[0]).to be(LaunchDarkly::SEGMENTS)
438
+ expect(data.values[0].count).to eq(dependency_ordering_test_data[LaunchDarkly::SEGMENTS].count)
439
+
440
+ # Features should be ordered so that a flag always appears after its prerequisites, if any
441
+ expect(data.keys[1]).to be(LaunchDarkly::FEATURES)
442
+ flags_map = data.values[1]
443
+ flags_list = flags_map.values
444
+ expect(flags_list.count).to eq(dependency_ordering_test_data[LaunchDarkly::FEATURES].count)
445
+ flags_list.each_with_index do |item, item_index|
446
+ (item[:prerequisites] || []).each do |prereq|
447
+ prereq = flags_map[prereq[:key].to_sym]
448
+ prereq_index = flags_list.index(prereq)
449
+ if prereq_index > item_index
450
+ all_keys = (flags_list.map { |f| f[:key] }).join(", ")
451
+ raise "#{item[:key]} depends on #{prereq[:key]}, but #{item[:key]} was listed first; keys in order are [#{all_keys}]"
452
+ end
453
+ end
454
+ end
455
+ end
456
+ end
378
457
  end
@@ -9,13 +9,22 @@ $my_prefix = 'testprefix'
9
9
  $null_log = ::Logger.new($stdout)
10
10
  $null_log.level = ::Logger::FATAL
11
11
 
12
+ $base_opts = {
13
+ prefix: $my_prefix,
14
+ logger: $null_log
15
+ }
12
16
 
13
- def create_redis_store()
14
- LaunchDarkly::RedisFeatureStore.new(prefix: $my_prefix, logger: $null_log, expiration: 60)
17
+ def create_redis_store(opts = {})
18
+ LaunchDarkly::RedisFeatureStore.new($base_opts.merge(opts).merge({ expiration: 60 }))
15
19
  end
16
20
 
17
- def create_redis_store_uncached()
18
- LaunchDarkly::RedisFeatureStore.new(prefix: $my_prefix, logger: $null_log, expiration: 0)
21
+ def create_redis_store_uncached(opts = {})
22
+ LaunchDarkly::RedisFeatureStore.new($base_opts.merge(opts).merge({ expiration: 0 }))
23
+ end
24
+
25
+ def clear_all_data
26
+ client = Redis.new
27
+ client.flushdb
19
28
  end
20
29
 
21
30
 
@@ -25,16 +34,17 @@ describe LaunchDarkly::RedisFeatureStore do
25
34
  # These tests will all fail if there isn't a Redis instance running on the default port.
26
35
 
27
36
  context "real Redis with local cache" do
28
- include_examples "feature_store", method(:create_redis_store)
37
+ include_examples "feature_store", method(:create_redis_store), method(:clear_all_data)
29
38
  end
30
39
 
31
40
  context "real Redis without local cache" do
32
- include_examples "feature_store", method(:create_redis_store_uncached)
41
+ include_examples "feature_store", method(:create_redis_store_uncached), method(:clear_all_data)
33
42
  end
34
43
 
35
- def add_concurrent_modifier(store, other_client, flag, start_version, end_version)
44
+ def make_concurrent_modifier_test_hook(other_client, flag, start_version, end_version)
45
+ test_hook = Object.new
36
46
  version_counter = start_version
37
- expect(store).to receive(:before_update_transaction) { |base_key, key|
47
+ expect(test_hook).to receive(:before_update_transaction) { |base_key, key|
38
48
  if version_counter <= end_version
39
49
  new_flag = flag.clone
40
50
  new_flag[:version] = version_counter
@@ -42,18 +52,18 @@ describe LaunchDarkly::RedisFeatureStore do
42
52
  version_counter = version_counter + 1
43
53
  end
44
54
  }.at_least(:once)
55
+ test_hook
45
56
  end
46
57
 
47
58
  it "handles upsert race condition against external client with lower version" do
48
- store = create_redis_store
49
59
  other_client = Redis.new({ url: "redis://localhost:6379" })
60
+ flag = { key: "foo", version: 1 }
61
+ test_hook = make_concurrent_modifier_test_hook(other_client, flag, 2, 4)
62
+ store = create_redis_store({ test_hook: test_hook })
50
63
 
51
64
  begin
52
- flag = { key: "foo", version: 1 }
53
65
  store.init(LaunchDarkly::FEATURES => { flag[:key] => flag })
54
66
 
55
- add_concurrent_modifier(store, other_client, flag, 2, 4)
56
-
57
67
  my_ver = { key: "foo", version: 10 }
58
68
  store.upsert(LaunchDarkly::FEATURES, my_ver)
59
69
  result = store.get(LaunchDarkly::FEATURES, flag[:key])
@@ -64,15 +74,14 @@ describe LaunchDarkly::RedisFeatureStore do
64
74
  end
65
75
 
66
76
  it "handles upsert race condition against external client with higher version" do
67
- store = create_redis_store
68
77
  other_client = Redis.new({ url: "redis://localhost:6379" })
78
+ flag = { key: "foo", version: 1 }
79
+ test_hook = make_concurrent_modifier_test_hook(other_client, flag, 3, 3)
80
+ store = create_redis_store({ test_hook: test_hook })
69
81
 
70
82
  begin
71
- flag = { key: "foo", version: 1 }
72
83
  store.init(LaunchDarkly::FEATURES => { flag[:key] => flag })
73
84
 
74
- add_concurrent_modifier(store, other_client, flag, 3, 3)
75
-
76
85
  my_ver = { key: "foo", version: 2 }
77
86
  store.upsert(LaunchDarkly::FEATURES, my_ver)
78
87
  result = store.get(LaunchDarkly::FEATURES, flag[:key])
@@ -1,52 +1,58 @@
1
+ require "http_util"
1
2
  require "spec_helper"
2
- require "faraday"
3
3
 
4
4
  describe LaunchDarkly::Requestor do
5
5
  describe ".request_all_flags" do
6
6
  describe "with a proxy" do
7
- let(:requestor) {
8
- LaunchDarkly::Requestor.new(
9
- "key",
10
- LaunchDarkly::Config.new({
11
- :proxy => "http://proxy.com",
12
- :base_uri => "http://ld.com"
13
- })
14
- )
15
- }
16
7
  it "converts the proxy option" do
17
- faraday = Faraday.new
18
- requestor.instance_variable_set(:@client, faraday)
19
- allow(faraday).to receive(:get) do |*args, &block|
20
- req = double(Faraday::Request, :headers => {}, :options => Faraday::RequestOptions.new)
21
- block.call(req)
22
- expect(args).to eq ['http://ld.com/sdk/latest-all']
23
- expect(req.options.proxy[:uri]).to eq URI("http://proxy.com")
24
- double(body: '{"foo": "bar"}', status: 200, headers: {})
8
+ content = '{"flags": {"flagkey": {"key": "flagkey"}}}'
9
+ with_server do |server|
10
+ server.setup_ok_response("/sdk/latest-all", content, "application/json", { "etag" => "x" })
11
+ with_server(StubProxyServer.new) do |proxy|
12
+ config = LaunchDarkly::Config.new(base_uri: server.base_uri.to_s, proxy: proxy.base_uri.to_s)
13
+ r = LaunchDarkly::Requestor.new("sdk-key", config)
14
+ result = r.request_all_data
15
+ expect(result).to eq(JSON.parse(content, symbolize_names: true))
16
+ end
25
17
  end
26
-
27
- requestor.request_all_data()
28
18
  end
29
19
  end
30
20
  describe "without a proxy" do
31
- let(:requestor) {
32
- LaunchDarkly::Requestor.new(
33
- "key",
34
- LaunchDarkly::Config.new({
35
- :base_uri => "http://ld.com"
36
- })
37
- )
38
- }
39
- it "converts the proxy option" do
40
- faraday = Faraday.new
41
- requestor.instance_variable_set(:@client, faraday)
42
- allow(faraday).to receive(:get) do |*args, &block|
43
- req = double(Faraday::Request, :headers => {}, :options => Faraday::RequestOptions.new)
44
- block.call(req)
45
- expect(args).to eq ['http://ld.com/sdk/latest-all']
46
- expect(req.options.proxy).to eq nil
47
- double(body: '{"foo": "bar"}', status: 200, headers: {})
21
+ it "sends headers" do
22
+ content = '{"flags": {}}'
23
+ sdk_key = 'sdk-key'
24
+ with_server do |server|
25
+ server.setup_ok_response("/sdk/latest-all", content, "application/json", { "etag" => "x" })
26
+ r = LaunchDarkly::Requestor.new(sdk_key, LaunchDarkly::Config.new({ base_uri: server.base_uri.to_s }))
27
+ r.request_all_data
28
+ expect(server.requests.length).to eq 1
29
+ req = server.requests[0]
30
+ expect(req.header['authorization']).to eq [sdk_key]
31
+ expect(req.header['user-agent']).to eq ["RubyClient/" + LaunchDarkly::VERSION]
32
+ end
33
+ end
34
+
35
+ it "receives data" do
36
+ content = '{"flags": {"flagkey": {"key": "flagkey"}}}'
37
+ with_server do |server|
38
+ server.setup_ok_response("/sdk/latest-all", content, "application/json", { "etag" => "x" })
39
+ r = LaunchDarkly::Requestor.new("sdk-key", LaunchDarkly::Config.new({ base_uri: server.base_uri.to_s }))
40
+ result = r.request_all_data
41
+ expect(result).to eq(JSON.parse(content, symbolize_names: true))
42
+ end
43
+ end
44
+
45
+ it "handles Unicode content" do
46
+ content = '{"flags": {"flagkey": {"key": "flagkey", "variations": ["blue", "grėeń"]}}}'
47
+ with_server do |server|
48
+ server.setup_ok_response("/sdk/latest-all", content, "application/json", { "etag" => "x" })
49
+ # Note that the ETag header here is important because without it, the HTTP cache will not be used,
50
+ # and the cache is what required a fix to handle Unicode properly. See:
51
+ # https://github.com/launchdarkly/ruby-client/issues/90
52
+ r = LaunchDarkly::Requestor.new("sdk-key", LaunchDarkly::Config.new({ base_uri: server.base_uri.to_s }))
53
+ result = r.request_all_data
54
+ expect(result).to eq(JSON.parse(content, symbolize_names: true))
48
55
  end
49
- requestor.request_all_data()
50
56
  end
51
57
  end
52
58
  end
data/spec/stream_spec.rb CHANGED
@@ -1,5 +1,5 @@
1
+ require "ld-eventsource"
1
2
  require "spec_helper"
2
- require 'ostruct'
3
3
 
4
4
  describe LaunchDarkly::StreamProcessor do
5
5
  subject { LaunchDarkly::StreamProcessor }
@@ -8,52 +8,52 @@ describe LaunchDarkly::StreamProcessor do
8
8
  let(:processor) { subject.new("sdk_key", config, requestor) }
9
9
 
10
10
  describe '#process_message' do
11
- let(:put_message) { OpenStruct.new({data: '{"data":{"flags":{"asdf": {"key": "asdf"}},"segments":{"segkey": {"key": "segkey"}}}}'}) }
12
- let(:patch_flag_message) { OpenStruct.new({data: '{"path": "/flags/key", "data": {"key": "asdf", "version": 1}}'}) }
13
- let(:patch_seg_message) { OpenStruct.new({data: '{"path": "/segments/key", "data": {"key": "asdf", "version": 1}}'}) }
14
- let(:delete_flag_message) { OpenStruct.new({data: '{"path": "/flags/key", "version": 2}'}) }
15
- let(:delete_seg_message) { OpenStruct.new({data: '{"path": "/segments/key", "version": 2}'}) }
16
- let(:indirect_patch_flag_message) { OpenStruct.new({data: "/flags/key"}) }
17
- let(:indirect_patch_segment_message) { OpenStruct.new({data: "/segments/key"}) }
11
+ let(:put_message) { SSE::StreamEvent.new(:put, '{"data":{"flags":{"asdf": {"key": "asdf"}},"segments":{"segkey": {"key": "segkey"}}}}') }
12
+ let(:patch_flag_message) { SSE::StreamEvent.new(:patch, '{"path": "/flags/key", "data": {"key": "asdf", "version": 1}}') }
13
+ let(:patch_seg_message) { SSE::StreamEvent.new(:patch, '{"path": "/segments/key", "data": {"key": "asdf", "version": 1}}') }
14
+ let(:delete_flag_message) { SSE::StreamEvent.new(:delete, '{"path": "/flags/key", "version": 2}') }
15
+ let(:delete_seg_message) { SSE::StreamEvent.new(:delete, '{"path": "/segments/key", "version": 2}') }
16
+ let(:indirect_patch_flag_message) { SSE::StreamEvent.new(:'indirect/patch', "/flags/key") }
17
+ let(:indirect_patch_segment_message) { SSE::StreamEvent.new(:'indirect/patch', "/segments/key") }
18
18
 
19
19
  it "will accept PUT methods" do
20
- processor.send(:process_message, put_message, LaunchDarkly::PUT)
20
+ processor.send(:process_message, put_message)
21
21
  expect(config.feature_store.get(LaunchDarkly::FEATURES, "asdf")).to eq(key: "asdf")
22
22
  expect(config.feature_store.get(LaunchDarkly::SEGMENTS, "segkey")).to eq(key: "segkey")
23
23
  end
24
24
  it "will accept PATCH methods for flags" do
25
- processor.send(:process_message, patch_flag_message, LaunchDarkly::PATCH)
25
+ processor.send(:process_message, patch_flag_message)
26
26
  expect(config.feature_store.get(LaunchDarkly::FEATURES, "asdf")).to eq(key: "asdf", version: 1)
27
27
  end
28
28
  it "will accept PATCH methods for segments" do
29
- processor.send(:process_message, patch_seg_message, LaunchDarkly::PATCH)
29
+ processor.send(:process_message, patch_seg_message)
30
30
  expect(config.feature_store.get(LaunchDarkly::SEGMENTS, "asdf")).to eq(key: "asdf", version: 1)
31
31
  end
32
32
  it "will accept DELETE methods for flags" do
33
- processor.send(:process_message, patch_flag_message, LaunchDarkly::PATCH)
34
- processor.send(:process_message, delete_flag_message, LaunchDarkly::DELETE)
33
+ processor.send(:process_message, patch_flag_message)
34
+ processor.send(:process_message, delete_flag_message)
35
35
  expect(config.feature_store.get(LaunchDarkly::FEATURES, "key")).to eq(nil)
36
36
  end
37
37
  it "will accept DELETE methods for segments" do
38
- processor.send(:process_message, patch_seg_message, LaunchDarkly::PATCH)
39
- processor.send(:process_message, delete_seg_message, LaunchDarkly::DELETE)
38
+ processor.send(:process_message, patch_seg_message)
39
+ processor.send(:process_message, delete_seg_message)
40
40
  expect(config.feature_store.get(LaunchDarkly::SEGMENTS, "key")).to eq(nil)
41
41
  end
42
42
  it "will accept INDIRECT PATCH method for flags" do
43
43
  flag = { key: 'key', version: 1 }
44
44
  allow(requestor).to receive(:request_flag).with(flag[:key]).and_return(flag)
45
- processor.send(:process_message, indirect_patch_flag_message, LaunchDarkly::INDIRECT_PATCH);
45
+ processor.send(:process_message, indirect_patch_flag_message);
46
46
  expect(config.feature_store.get(LaunchDarkly::FEATURES, flag[:key])).to eq(flag)
47
47
  end
48
48
  it "will accept INDIRECT PATCH method for segments" do
49
49
  segment = { key: 'key', version: 1 }
50
50
  allow(requestor).to receive(:request_segment).with(segment[:key]).and_return(segment)
51
- processor.send(:process_message, indirect_patch_segment_message, LaunchDarkly::INDIRECT_PATCH);
51
+ processor.send(:process_message, indirect_patch_segment_message);
52
52
  expect(config.feature_store.get(LaunchDarkly::SEGMENTS, segment[:key])).to eq(segment)
53
53
  end
54
54
  it "will log a warning if the method is not recognized" do
55
55
  expect(processor.instance_variable_get(:@config).logger).to receive :warn
56
- processor.send(:process_message, put_message, "get")
56
+ processor.send(:process_message, SSE::StreamEvent.new(type: :get, data: "", id: nil))
57
57
  end
58
58
  end
59
59
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ldclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.3
4
+ version: 5.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-11 00:00:00.000000000 Z
11
+ date: 2019-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-dynamodb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.18'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.18'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: diplomat
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 2.0.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.0.2
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: redis
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -245,33 +273,19 @@ dependencies:
245
273
  - !ruby/object:Gem::Version
246
274
  version: '1.0'
247
275
  - !ruby/object:Gem::Dependency
248
- name: http_tools
276
+ name: ld-eventsource
249
277
  requirement: !ruby/object:Gem::Requirement
250
278
  requirements:
251
279
  - - "~>"
252
280
  - !ruby/object:Gem::Version
253
- version: 0.4.5
254
- type: :runtime
255
- prerelease: false
256
- version_requirements: !ruby/object:Gem::Requirement
257
- requirements:
258
- - - "~>"
259
- - !ruby/object:Gem::Version
260
- version: 0.4.5
261
- - !ruby/object:Gem::Dependency
262
- name: socketry
263
- requirement: !ruby/object:Gem::Requirement
264
- requirements:
265
- - - "~>"
266
- - !ruby/object:Gem::Version
267
- version: 0.5.1
281
+ version: '1.0'
268
282
  type: :runtime
269
283
  prerelease: false
270
284
  version_requirements: !ruby/object:Gem::Requirement
271
285
  requirements:
272
286
  - - "~>"
273
287
  - !ruby/object:Gem::Version
274
- version: 0.5.1
288
+ version: '1.0'
275
289
  description: Official LaunchDarkly SDK for Ruby
276
290
  email:
277
291
  - team@launchdarkly.com
@@ -305,7 +319,19 @@ files:
305
319
  - lib/ldclient-rb/expiring_cache.rb
306
320
  - lib/ldclient-rb/file_data_source.rb
307
321
  - lib/ldclient-rb/flags_state.rb
322
+ - lib/ldclient-rb/impl.rb
323
+ - lib/ldclient-rb/impl/integrations/consul_impl.rb
324
+ - lib/ldclient-rb/impl/integrations/dynamodb_impl.rb
325
+ - lib/ldclient-rb/impl/integrations/redis_impl.rb
326
+ - lib/ldclient-rb/impl/store_client_wrapper.rb
327
+ - lib/ldclient-rb/impl/store_data_set_sorter.rb
308
328
  - lib/ldclient-rb/in_memory_store.rb
329
+ - lib/ldclient-rb/integrations.rb
330
+ - lib/ldclient-rb/integrations/consul.rb
331
+ - lib/ldclient-rb/integrations/dynamodb.rb
332
+ - lib/ldclient-rb/integrations/redis.rb
333
+ - lib/ldclient-rb/integrations/util/store_wrapper.rb
334
+ - lib/ldclient-rb/interfaces.rb
309
335
  - lib/ldclient-rb/ldclient.rb
310
336
  - lib/ldclient-rb/memoized_value.rb
311
337
  - lib/ldclient-rb/newrelic.rb
@@ -318,11 +344,7 @@ files:
318
344
  - lib/ldclient-rb/user_filter.rb
319
345
  - lib/ldclient-rb/util.rb
320
346
  - lib/ldclient-rb/version.rb
321
- - lib/sse_client.rb
322
- - lib/sse_client/backoff.rb
323
- - lib/sse_client/sse_client.rb
324
- - lib/sse_client/sse_events.rb
325
- - lib/sse_client/streaming_http.rb
347
+ - scripts/gendocs.sh
326
348
  - scripts/release.sh
327
349
  - spec/config_spec.rb
328
350
  - spec/evaluation_spec.rb
@@ -337,7 +359,11 @@ files:
337
359
  - spec/fixtures/sanitized_numeric_key_user.json
338
360
  - spec/fixtures/user.json
339
361
  - spec/flags_state_spec.rb
362
+ - spec/http_util.rb
340
363
  - spec/in_memory_feature_store_spec.rb
364
+ - spec/integrations/consul_feature_store_spec.rb
365
+ - spec/integrations/dynamodb_feature_store_spec.rb
366
+ - spec/integrations/store_wrapper_spec.rb
341
367
  - spec/ldclient_spec.rb
342
368
  - spec/newrelic_spec.rb
343
369
  - spec/polling_spec.rb
@@ -346,10 +372,6 @@ files:
346
372
  - spec/segment_store_spec_base.rb
347
373
  - spec/simple_lru_cache_spec.rb
348
374
  - spec/spec_helper.rb
349
- - spec/sse_client/sse_client_spec.rb
350
- - spec/sse_client/sse_events_spec.rb
351
- - spec/sse_client/sse_shared.rb
352
- - spec/sse_client/streaming_http_spec.rb
353
375
  - spec/store_spec.rb
354
376
  - spec/stream_spec.rb
355
377
  - spec/user_filter_spec.rb
@@ -357,7 +379,7 @@ files:
357
379
  - spec/version_spec.rb
358
380
  homepage: https://github.com/launchdarkly/ruby-client
359
381
  licenses:
360
- - Apache 2.0
382
+ - Apache-2.0
361
383
  metadata: {}
362
384
  post_install_message:
363
385
  rdoc_options: []
@@ -393,7 +415,11 @@ test_files:
393
415
  - spec/fixtures/sanitized_numeric_key_user.json
394
416
  - spec/fixtures/user.json
395
417
  - spec/flags_state_spec.rb
418
+ - spec/http_util.rb
396
419
  - spec/in_memory_feature_store_spec.rb
420
+ - spec/integrations/consul_feature_store_spec.rb
421
+ - spec/integrations/dynamodb_feature_store_spec.rb
422
+ - spec/integrations/store_wrapper_spec.rb
397
423
  - spec/ldclient_spec.rb
398
424
  - spec/newrelic_spec.rb
399
425
  - spec/polling_spec.rb
@@ -402,10 +428,6 @@ test_files:
402
428
  - spec/segment_store_spec_base.rb
403
429
  - spec/simple_lru_cache_spec.rb
404
430
  - spec/spec_helper.rb
405
- - spec/sse_client/sse_client_spec.rb
406
- - spec/sse_client/sse_events_spec.rb
407
- - spec/sse_client/sse_shared.rb
408
- - spec/sse_client/streaming_http_spec.rb
409
431
  - spec/store_spec.rb
410
432
  - spec/stream_spec.rb
411
433
  - spec/user_filter_spec.rb