ldclient-rb 5.4.3 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +33 -6
  3. data/CHANGELOG.md +19 -0
  4. data/CONTRIBUTING.md +0 -12
  5. data/Gemfile.lock +22 -3
  6. data/README.md +41 -35
  7. data/ldclient-rb.gemspec +4 -3
  8. data/lib/ldclient-rb.rb +9 -1
  9. data/lib/ldclient-rb/cache_store.rb +1 -0
  10. data/lib/ldclient-rb/config.rb +201 -90
  11. data/lib/ldclient-rb/evaluation.rb +56 -8
  12. data/lib/ldclient-rb/event_summarizer.rb +3 -0
  13. data/lib/ldclient-rb/events.rb +16 -0
  14. data/lib/ldclient-rb/expiring_cache.rb +1 -0
  15. data/lib/ldclient-rb/file_data_source.rb +18 -13
  16. data/lib/ldclient-rb/flags_state.rb +3 -2
  17. data/lib/ldclient-rb/impl.rb +13 -0
  18. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +158 -0
  19. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +228 -0
  20. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +155 -0
  21. data/lib/ldclient-rb/impl/store_client_wrapper.rb +47 -0
  22. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +55 -0
  23. data/lib/ldclient-rb/in_memory_store.rb +15 -4
  24. data/lib/ldclient-rb/integrations.rb +55 -0
  25. data/lib/ldclient-rb/integrations/consul.rb +38 -0
  26. data/lib/ldclient-rb/integrations/dynamodb.rb +47 -0
  27. data/lib/ldclient-rb/integrations/redis.rb +55 -0
  28. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +230 -0
  29. data/lib/ldclient-rb/interfaces.rb +153 -0
  30. data/lib/ldclient-rb/ldclient.rb +135 -77
  31. data/lib/ldclient-rb/memoized_value.rb +2 -0
  32. data/lib/ldclient-rb/newrelic.rb +1 -0
  33. data/lib/ldclient-rb/non_blocking_thread_pool.rb +3 -3
  34. data/lib/ldclient-rb/polling.rb +1 -0
  35. data/lib/ldclient-rb/redis_store.rb +24 -190
  36. data/lib/ldclient-rb/requestor.rb +3 -2
  37. data/lib/ldclient-rb/simple_lru_cache.rb +1 -0
  38. data/lib/ldclient-rb/stream.rb +22 -10
  39. data/lib/ldclient-rb/user_filter.rb +1 -0
  40. data/lib/ldclient-rb/util.rb +1 -0
  41. data/lib/ldclient-rb/version.rb +1 -1
  42. data/scripts/gendocs.sh +12 -0
  43. data/spec/feature_store_spec_base.rb +173 -72
  44. data/spec/file_data_source_spec.rb +2 -2
  45. data/spec/http_util.rb +103 -0
  46. data/spec/in_memory_feature_store_spec.rb +1 -1
  47. data/spec/integrations/consul_feature_store_spec.rb +41 -0
  48. data/spec/integrations/dynamodb_feature_store_spec.rb +104 -0
  49. data/spec/integrations/store_wrapper_spec.rb +276 -0
  50. data/spec/ldclient_spec.rb +83 -4
  51. data/spec/redis_feature_store_spec.rb +25 -16
  52. data/spec/requestor_spec.rb +44 -38
  53. data/spec/stream_spec.rb +18 -18
  54. metadata +55 -33
  55. data/lib/sse_client.rb +0 -4
  56. data/lib/sse_client/backoff.rb +0 -38
  57. data/lib/sse_client/sse_client.rb +0 -171
  58. data/lib/sse_client/sse_events.rb +0 -67
  59. data/lib/sse_client/streaming_http.rb +0 -199
  60. data/spec/sse_client/sse_client_spec.rb +0 -177
  61. data/spec/sse_client/sse_events_spec.rb +0 -100
  62. data/spec/sse_client/sse_shared.rb +0 -82
  63. data/spec/sse_client/streaming_http_spec.rb +0 -263
@@ -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