featurehub-sdk 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a918d4c2cd828f070ede69b41bccaef489154f189bc93b497256f3589abec7f
4
- data.tar.gz: 320522f90925794e6a12df0e3a034ddb46b81a69445d201447bc1bd51743d4e6
3
+ metadata.gz: 033fbbd756fd2a748d584634724881aae1a2d49feec0a2f7cec4aa7245dc8440
4
+ data.tar.gz: 042ff7ee449a8b80a5f120d203c791e7e42c896dce377a5c7af4367c94048829
5
5
  SHA512:
6
- metadata.gz: 5ab24c0101cf91b2a0be85a92e5665d21397a7733be165c2c718208887b1060e29c621e12595ff4b2bbbf4f502fd40a6f1da89b62e147d77f2e9a4c9bd981f15
7
- data.tar.gz: 00ee27a652e9c85cabed5e331c18d4bfb68ee32e625e513f330f8534a89cc191c63f1320ce466d80807cf7a0d7518950da78b005e3c759d0e76791a060757607
6
+ metadata.gz: 0fe881017cbb21138eed0663f0df11d18df61e63be666c5e2e26b68ca478792e8bb51f123ea415d86c8ce6ede3e087b2c7e8b35991c90d6939bac7672f0f7de4
7
+ data.tar.gz: 944146e27443caad934f35b1efb30179ec3c1a8b8c78d2def46e68250b338b156184e79b861be2ae3b929cf4b38a7514978a1757bd7e24a65ede50930010c9a7
data/.rubocop.yml CHANGED
@@ -12,6 +12,9 @@ Style/StringLiteralsInInterpolation:
12
12
  Metrics/BlockLength:
13
13
  Enabled: false
14
14
 
15
+ Metrics/ClassLength:
16
+ Enabled: false
17
+
15
18
  # affects similarity to other SDKs + pointless
16
19
  Metrics/MethodLength:
17
20
  Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## [1.2.0] - 2022-10-14
2
+
3
+ - Fixing polling client for server eval
4
+ - Added in tests for polling client
5
+ - Added in server eval for streaming client
6
+ - Added expired environment support for polling and streaming
7
+ - Added cache busting for server eval polling client
8
+ -
9
+
10
+ ## [1.1.0] - 2022-10-12
11
+
12
+ - Adds support for array values in flag evaluation contexts via [this PR](https://github.com/featurehub-io/featurehub-ruby-sdk/pull/12)
13
+
1
14
  ## [1.0.0] - 2022-06-06
2
15
 
3
16
  - Initial release, feature complete
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- featurehub-sdk (1.0.0)
4
+ featurehub-sdk (1.2.0)
5
5
  concurrent-ruby (~> 1.1.10)
6
6
  faraday (~> 2.3)
7
7
  ld-eventsource (~> 2.2.0)
@@ -73,7 +73,7 @@ module FeatureHub
73
73
  end
74
74
 
75
75
  def get_attr(key, default_val = nil)
76
- (@attributes[key.to_sym] || [default_val])[0]
76
+ (@attributes[key.to_sym] || [default_val]).compact
77
77
  end
78
78
 
79
79
  def default_percentage_key
@@ -74,7 +74,10 @@ module FeatureHub
74
74
  edge_provider
75
75
  end
76
76
 
77
- def use_polling_edge_service(interval = ENV.fetch("FEATUREHUB_POLL_INTERVAL", "30").to_i); end
77
+ def use_polling_edge_service(interval = ENV.fetch("FEATUREHUB_POLL_INTERVAL", "30").to_i)
78
+ @interval = interval
79
+ @edge_service_provider = method(:create_polling_edge_provider)
80
+ end
78
81
 
79
82
  def new_context
80
83
  get_or_create_edge_service
@@ -99,8 +102,11 @@ module FeatureHub
99
102
  @edge_service_provider.call(@repository, @api_keys, @edge_url, @logger)
100
103
  end
101
104
 
105
+ def create_polling_edge_provider(repo, api_keys, edge_url, logger)
106
+ FeatureHub::Sdk::PollingEdgeService.new(repo, api_keys, edge_url, @interval, logger)
107
+ end
108
+
102
109
  def create_default_provider(repo, api_keys, edge_url, logger)
103
- # FeatureHub::Sdk::PollingEdgeService.new(repo, api_keys, edge_url, 10, logger)
104
110
  FeatureHub::Sdk::StreamingEdgeService.new(repo, api_keys, edge_url, logger)
105
111
  end
106
112
 
@@ -67,26 +67,30 @@ module FeatureHub
67
67
 
68
68
  def match_attribute(context, rs_attr)
69
69
  rs_attr.attributes.each do |attr|
70
- supplied_value = context.get_attr(attr.field_name)
71
- if supplied_value.nil? && attr.field_name.downcase == "now"
70
+ supplied_values = context.get_attr(attr.field_name)
71
+ if supplied_values.empty? && attr.field_name.downcase == "now"
72
72
  case attr.field_type
73
73
  when "DATE"
74
- supplied_value = Time.new.utc.iso8601[0..9]
74
+ supplied_values = [Time.new.utc.iso8601[0..9]]
75
75
  when "DATETIME"
76
- supplied_value = Time.new.utc.iso8601
76
+ supplied_values = [Time.new.utc.iso8601]
77
77
  end
78
78
  end
79
79
 
80
- if attr.values.nil? && supplied_value.nil?
80
+ if attr.values.nil? && supplied_values.empty?
81
81
  return false unless attr.conditional.equals?
82
82
 
83
83
  next
84
84
  end
85
85
 
86
- return false if attr.values.nil? || supplied_value.nil?
86
+ return false if attr.values.nil? || supplied_values.empty?
87
87
 
88
88
  # this attribute has to match or we failed
89
- return false unless @matcher_repository.find_matcher(attr).match(supplied_value, attr)
89
+ match = supplied_values.any? do |supplied_value|
90
+ @matcher_repository.find_matcher(attr).match(supplied_value, attr)
91
+ end
92
+
93
+ return false unless match
90
94
  end
91
95
 
92
96
  true
@@ -4,12 +4,13 @@ require "faraday"
4
4
  require "faraday/net_http"
5
5
  require "json"
6
6
  require "concurrent-ruby"
7
+ require "digest/sha2"
7
8
 
8
9
  module FeatureHub
9
10
  module Sdk
10
11
  # uses a periodic polling mechanism to get updates
11
12
  class PollingEdgeService < EdgeService
12
- attr_reader :repository, :api_keys, :edge_url, :interval
13
+ attr_reader :repository, :api_keys, :edge_url, :interval, :stopped, :etag, :cancel, :sha_context
13
14
 
14
15
  def initialize(repository, api_keys, edge_url, interval, logger = nil)
15
16
  super(repository, api_keys, edge_url)
@@ -25,6 +26,8 @@ module FeatureHub
25
26
  @cancel = false
26
27
  @context = nil
27
28
  @etag = nil
29
+ @stopped = false
30
+ @sha_context = nil
28
31
 
29
32
  generate_url
30
33
  end
@@ -48,34 +51,53 @@ module FeatureHub
48
51
  return if new_header == @context
49
52
 
50
53
  @context = new_header
54
+ @sha_context = Digest::SHA256.hexdigest(@context)
51
55
 
52
- get_updates
56
+ if active
57
+ get_updates
58
+ else
59
+ poll
60
+ end
53
61
  end
54
62
 
55
63
  def close
56
64
  cancel_task
57
65
  end
58
66
 
67
+ def active
68
+ !@task.nil?
69
+ end
70
+
59
71
  private
60
72
 
61
73
  def poll_with_interval
62
- return if @cancel || !@task.nil?
63
-
64
- get_updates
74
+ return if @cancel || !@task.nil? || @stopped
65
75
 
66
76
  @logger.info("starting polling for #{determine_request_url}")
67
- @task = Concurrent::TimerTask.new(execution_interval: @interval) do
77
+ @task = Concurrent::TimerTask.new(execution_interval: @interval, run_now: false) do
68
78
  get_updates
69
79
  end
70
- @task.execute
80
+
81
+ get_updates
82
+
83
+ @task&.execute # could have been shutdown
71
84
  end
72
85
 
73
86
  def cancel_task
87
+ @cancel = true
88
+ shutdown_task
89
+ end
90
+
91
+ def stopped_task
92
+ @stopped = true
93
+ shutdown_task
94
+ end
95
+
96
+ def shutdown_task
74
97
  return if @task.nil?
75
98
 
76
99
  @task.shutdown
77
100
  @task = nil
78
- @cancel = true
79
101
  end
80
102
 
81
103
  # rubocop:disable Naming/AccessorMethodName
@@ -86,36 +108,63 @@ module FeatureHub
86
108
  "X-SDK": "Ruby",
87
109
  "X-SDK-Version": FeatureHub::Sdk::VERSION
88
110
  }
111
+
112
+ headers["x-featurehub"] = @context unless @context.nil?
89
113
  headers["if-none-match"] = @etag unless @etag.nil?
114
+
90
115
  @logger.debug("polling for #{url}")
91
- resp = @conn.get(url, request: { timeout: @timeout }, headers: headers)
116
+ resp = @conn.get url, {}, headers
92
117
  case resp.status
93
118
  when 200
94
- @etag = resp.headers["etag"]
95
- process_results(JSON.parse(resp.body))
119
+ success(resp)
120
+ when 236
121
+ stopped_task
122
+ success(resp)
96
123
  when 404 # no such key
97
124
  @repository.notify("failed", nil)
98
- @cancel = true
125
+ cancel_task
99
126
  @logger.error("featurehub: key does not exist, stopping polling")
100
127
  when 503 # dacha busy
101
- @logger.debug("featurehub: dacha is busy, trying tgaina")
128
+ @logger.debug("featurehub: dacha is busy, trying again")
102
129
  else
103
130
  @logger.debug("featurehub: unknown error #{resp.status}")
104
131
  end
105
132
  end
133
+
106
134
  # rubocop:enable Naming/AccessorMethodName
107
135
 
136
+ def success(resp)
137
+ @etag = resp.headers["etag"]
138
+
139
+ check_interval_change(resp.headers["cache-control"]) if resp.headers["cache-control"]
140
+
141
+ process_results(JSON.parse(resp.body))
142
+ end
143
+
108
144
  def process_results(data)
109
145
  data.each do |environment|
110
146
  @repository.notify("features", environment["features"]) if environment
111
147
  end
112
148
  end
113
149
 
150
+ def check_interval_change(cache_control_header)
151
+ found = cache_control_header.scan(/max-age=(\d+)/)
152
+
153
+ return if @task.nil? || found.empty? || found[0].empty?
154
+
155
+ new_interval = found[0][0].to_i
156
+
157
+ return unless new_interval.positive? && new_interval != @interval
158
+
159
+ @interval = new_interval
160
+ @task.execution_interval = @interval
161
+ end
162
+
114
163
  def determine_request_url
115
164
  if @context.nil?
116
- @url
165
+ "#{@url}&contextSha=0"
117
166
  else
118
- "#{@url}&#{@context}"
167
+ "#{@url}&contextSha=#{@sha_context}"
119
168
  end
120
169
  end
121
170
 
@@ -125,6 +174,7 @@ module FeatureHub
125
174
  @timeout = ENV.fetch("FEATUREHUB_POLL_HTTP_TIMEOUT", "12").to_i
126
175
  @conn = Faraday.new(url: @edge_url) do |f|
127
176
  f.adapter :net_http
177
+ f.options.timeout = @timeout
128
178
  end
129
179
  end
130
180
  end
@@ -7,7 +7,7 @@ module FeatureHub
7
7
  module Sdk
8
8
  # provides a streaming service
9
9
  class StreamingEdgeService < FeatureHub::Sdk::EdgeService
10
- attr_reader :repository, :sse_client, :url, :closed
10
+ attr_reader :repository, :sse_client, :url, :stopped
11
11
 
12
12
  def initialize(repository, api_keys, edge_url, logger = nil)
13
13
  super(repository, api_keys, edge_url)
@@ -15,42 +15,78 @@ module FeatureHub
15
15
  @url = "#{edge_url}features/#{api_keys[0]}"
16
16
  @repository = repository
17
17
  @sse_client = nil
18
- @closed = true
18
+ @context = nil
19
19
  @logger = logger || FeatureHub::Sdk.default_logger
20
20
  end
21
21
 
22
+ def closed
23
+ @sse_client.nil?
24
+ end
25
+
22
26
  def poll
23
- start_streaming unless @sse_client
27
+ start_streaming unless @sse_client || @stopped
24
28
  end
25
29
 
26
30
  def active
27
- !@closed && !@sse_client.nil?
31
+ !@sse_client.nil?
28
32
  end
29
33
 
30
34
  def close
31
- @closed = true
35
+ close_connection
36
+ end
37
+
38
+ private
39
+
40
+ def close_connection
32
41
  return if @sse_client.nil?
33
42
 
34
43
  @sse_client.close
35
44
  @sse_client = nil
36
45
  end
37
46
 
38
- private
47
+ def stop
48
+ @stopped = true
49
+ close_connection
50
+ end
51
+
52
+ def context_change(new_header)
53
+ return if new_header == @context
54
+
55
+ @context = new_header
56
+ close
57
+ poll
58
+ end
39
59
 
40
60
  def start_streaming
41
- @closed = false
42
61
  @logger.info("streaming from #{@url}")
62
+ # we can get an error before returning the new() function and get a race condition on the close
63
+ must_close = false
43
64
  @sse_client = SSE::Client.new(@url) do |client|
44
65
  client.on_event do |event|
45
- @repository.notify(event.type, JSON.parse(event.data))
66
+ json_data = JSON.parse(event.data)
67
+
68
+ if event.type == "config"
69
+ process_config(json_data)
70
+ else
71
+ @repository.notify(event.type, json_data)
72
+ end
46
73
  end
47
74
  client.on_error do |error|
48
75
  if error.is_a?(SSE::Errors::HTTPStatusError) && (error.status == 404)
49
76
  @repository.notify("failure", nil)
50
77
  close
78
+ must_close = true
51
79
  end
52
80
  end
53
81
  end
82
+
83
+ return unless must_close
84
+
85
+ close # try again
86
+ end
87
+
88
+ def process_config(json_data)
89
+ stop if json_data["edge.stale"]
54
90
  end
55
91
  end
56
92
  end
@@ -3,7 +3,7 @@
3
3
  module FeatureHub
4
4
  # already documented elsewhere
5
5
  module Sdk
6
- VERSION = "1.0.0"
6
+ VERSION = "1.2.0"
7
7
 
8
8
  def default_logger
9
9
  log = ::Logger.new($stdout)
@@ -1,6 +1,7 @@
1
1
  module FeatureHub
2
2
  module Sdk
3
3
  VERSION: String
4
+
4
5
  # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
6
  #
6
7
 
@@ -11,13 +12,17 @@ module FeatureHub
11
12
  feature_state: Hash[untyped, untyped]?, parent_state: FeatureState?, ctx: ClientContext?) -> void
12
13
 
13
14
  def locked?: -> bool
15
+
14
16
  def exists?: (top_feature: FeatureState?) -> bool
17
+
15
18
  def id: -> String?
19
+
16
20
  def feature_type: -> String?
17
21
 
18
22
  def with_context: (ctx: ClientContext) -> FeatureState
19
23
 
20
24
  def update_feature_state: (feature_state: Hash[untyped, untyped]) -> void
25
+
21
26
  # this is the feature state of the top level, it always walks up
22
27
  def feature_state: () -> Hash[untyped, untyped]
23
28
 
@@ -57,19 +62,20 @@ module FeatureHub
57
62
  attr_reader matched: bool
58
63
  attr_reader value: [bool? | String? | Float?]
59
64
 
60
- def initialize:(matched: bool, value: [bool? | String? | Float?]) -> void
65
+ def initialize: (matched: bool, value: [bool? | String? | Float?]) -> void
61
66
  end
62
67
 
63
68
  class InterceptorValue
64
- def initialize: (val: [bool? | String? | Float? ]) -> void
65
- def cast:(feature_type: String?) -> [bool? | String? | Float? ]
69
+ def initialize: (val: [bool? | String? | Float?]) -> void
70
+
71
+ def cast: (feature_type: String?) -> [bool? | String? | Float?]
66
72
  end
67
73
 
68
74
  class ValueInterceptor
69
75
  def intercepted_value: (feature_key: Symbol) -> InterceptorValue?
70
76
  end
71
77
 
72
- class EnvironmentInterceptor < ValueInterceptor
78
+ class EnvironmentInterceptor < ValueInterceptor
73
79
  end
74
80
 
75
81
  class PercentageCalculator
@@ -78,17 +84,25 @@ module FeatureHub
78
84
 
79
85
  class ApplyFeatures
80
86
  def initialize: (percent_calculator: PercentageCalculator?, matcher_repository: MatcherRepository?) -> void
87
+
81
88
  def apply: (strategies: Array[RolloutStrategy], key: String, feature_value_id: String, context: ClientContext) -> Applied
89
+
82
90
  def match_attribute: (context: ClientContext, rs: RolloutStrategyAttribute) -> bool
91
+
83
92
  def self.determine_percentage_key: (context: ClientContext, rsi: RolloutStrategy) -> String?
84
93
  end
85
94
 
86
95
  class InternalFeatureRepository
87
96
  def feature: (key: String) -> FeatureState?
97
+
88
98
  def find_interceptor: (feature_value: String) -> InterceptorValue?
99
+
89
100
  def ready?: -> bool
101
+
90
102
  def not_ready!: -> void
103
+
91
104
  def apply: (strategies: Array[RolloutStrategy], key: String, feature_id: String, context: ClientContext) -> Applied
105
+
92
106
  def notify: (status: String, data: Hash[untyped, untyped]) -> void
93
107
  end
94
108
 
@@ -96,15 +110,20 @@ module FeatureHub
96
110
  @features: Hash[String, FeatureState]
97
111
  @ready: bool
98
112
 
99
- def initialize: (apply_features: nil | ApplyFeatures ) -> void
100
- def apply:(strategies: Array[RolloutStrategy], key: String, feature_id: String, context: ClientContext) -> Applied
113
+ def initialize: (apply_features: nil | ApplyFeatures) -> void
114
+
115
+ def apply: (strategies: Array[RolloutStrategy], key: String, feature_id: String, context: ClientContext) -> Applied
101
116
 
102
117
  def notify: (status: String, data: Hash[untyped, untyped]) -> void
118
+
103
119
  def feature: (key: String) -> FeatureState
120
+
104
121
  def register_interceptor: (interceptor: ValueInterceptor) -> void
105
122
 
106
123
  def find_interceptor: (feature_value: String) -> InterceptorValue?
124
+
107
125
  def ready?: -> bool
126
+
108
127
  def not_ready!: -> void
109
128
 
110
129
  def extract_feature_state: -> Array[Hash[untyped, untyped]]
@@ -114,37 +133,61 @@ module FeatureHub
114
133
  attr_reader repo: InternalFeatureRepository
115
134
 
116
135
  def initialize: (repository: InternalFeatureRepository) -> void
136
+
117
137
  def user_key: (value: String) -> ClientContext
138
+
118
139
  def session_key: (value: String) -> ClientContext
140
+
119
141
  def version: (value: String) -> ClientContext
120
- def country: (value: Symbol ) -> ClientContext
121
- def platform: (value: Symbol ) -> ClientContext
122
- def device: (value: Symbol ) -> ClientContext
123
- def attribute_value: (key: String, values: Array[String] ) -> ClientContext
142
+
143
+ def country: (value: Symbol) -> ClientContext
144
+
145
+ def platform: (value: Symbol) -> ClientContext
146
+
147
+ def device: (value: Symbol) -> ClientContext
148
+
149
+ def attribute_value: (key: String, values: Array[String]) -> ClientContext
150
+
124
151
  def clear: -> ClientContext
125
- def get_attr: (key: String, default_val: String?) -> String?
152
+
153
+ def get_attr: (key: String, default_val: String?) -> Array[String]
154
+
126
155
  def default_percentage_key: -> String?
156
+
127
157
  def enabled: (key: String) -> bool?
128
158
 
129
159
  def feature: (key: String) -> FeatureState
160
+
130
161
  def set?: (key: String) -> bool?
162
+
131
163
  def number: (key: String) -> Float?
164
+
132
165
  def string: (key: String) -> String?
166
+
133
167
  def json: (key: String) -> Hash[untyped, untyped]?
168
+
134
169
  def raw_json: (key: String) -> String?
170
+
135
171
  def flag: (key: String) -> bool?
172
+
136
173
  def boolean: (key: String) -> bool?
174
+
137
175
  def exists?: (key: String) -> bool
138
176
 
139
177
  def build: -> ClientContext
178
+
140
179
  def build_sync: -> ClientContext
180
+
141
181
  def close: -> ClientContext
142
182
  end
143
183
 
144
184
  class EdgeService
145
185
  def initialize: (repository: InternalFeatureRepository, api_keys: Array[String], edge_url: String) -> void
186
+
146
187
  def poll: -> void
188
+
147
189
  def context_change: (new_header: String?) -> void
190
+
148
191
  def close: -> void
149
192
  end
150
193
 
@@ -189,15 +232,25 @@ module FeatureHub
189
232
 
190
233
  class RolloutStrategyCondition
191
234
  def equals?: -> bool
235
+
192
236
  def ends_with?: -> bool
237
+
193
238
  def starts_with?: -> bool
239
+
194
240
  def greater?: -> bool
241
+
195
242
  def greater_equals?: -> bool
243
+
196
244
  def less?: -> bool
245
+
197
246
  def less_equals?: -> bool
247
+
198
248
  def not_equals?: -> bool
249
+
199
250
  def includes?: -> bool
251
+
200
252
  def excludes?: -> bool
253
+
201
254
  def regex?: -> bool
202
255
  end
203
256
 
@@ -209,6 +262,7 @@ module FeatureHub
209
262
  attr_reader field_type: String
210
263
 
211
264
  def float_values: -> Array[Float]
265
+
212
266
  def str_values: -> Array[String]
213
267
  end
214
268
 
@@ -221,15 +275,16 @@ module FeatureHub
221
275
  attr_reader value: [bool? | String? | Float?]
222
276
 
223
277
  def percentage_attributes?: -> bool
278
+
224
279
  def attributes?: -> bool
225
280
  end
226
281
 
227
282
  class StrategyMatcher
228
- def match: (supplied_value: String, attr: RolloutStrategyAttribute ) -> bool
283
+ def match: (supplied_value: String, attr: RolloutStrategyAttribute) -> bool
229
284
  end
230
285
 
231
286
  class BooleanMatcher < StrategyMatcher
232
- def match: (supplied_value: String, attr: RolloutStrategyAttribute ) -> bool
287
+ def match: (supplied_value: String, attr: RolloutStrategyAttribute) -> bool
233
288
  end
234
289
 
235
290
  class StringMatcher < StrategyMatcher
@@ -250,7 +305,6 @@ module FeatureHub
250
305
 
251
306
  class MatcherRegistry < MatcherRepository
252
307
  end
253
- end
308
+ end
254
309
 
255
310
  end
256
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: featurehub-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Vowles
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-06-16 00:00:00.000000000 Z
12
+ date: 2022-11-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: concurrent-ruby
@@ -90,13 +90,13 @@ extra_rdoc_files: []
90
90
  files:
91
91
  - ".rspec"
92
92
  - ".rubocop.yml"
93
+ - ".ruby-version"
93
94
  - CHANGELOG.md
94
95
  - CODE_OF_CONDUCT.md
95
96
  - Gemfile
96
97
  - Gemfile.lock
97
98
  - LICENSE.txt
98
99
  - Rakefile
99
- - featurehub-sdk.gemspec
100
100
  - featurehub-sdk.iml
101
101
  - lib/feature_hub/sdk/context.rb
102
102
  - lib/feature_hub/sdk/feature_hub_config.rb
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path("lib", __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require "feature_hub/sdk/version"
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = "featurehub-sdk"
9
- spec.version = FeatureHub::Sdk::VERSION
10
- spec.authors = ["Richard Vowles", "Irina Southwell"]
11
- spec.email = ["richard@bluetrainsoftware.com"]
12
-
13
- spec.summary = "FeatureHub Ruby SDK"
14
- spec.description = "FeatureHub Ruby SDK"
15
- spec.homepage = "https://www.featurehub.io"
16
- spec.license = "MIT"
17
- spec.required_ruby_version = ">= 2.6.0"
18
-
19
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
20
-
21
- spec.metadata["homepage_uri"] = spec.homepage
22
- spec.metadata["source_code_uri"] = "https://github.com/featurehub-io/featurehub-ruby-sdk"
23
- spec.metadata["changelog_uri"] = "https://github.com/featurehub-io/featurehub-ruby-sdk/featurehub-sdk/CHANGELOG.md"
24
- spec.metadata["rubygems_mfa_required"] = "true"
25
-
26
- # Specify which files should be added to the gem when it is released.
27
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
- `git ls-files -z`.split("\x0").reject do |f|
30
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
31
- end
32
- end
33
- spec.bindir = "exe"
34
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
35
- spec.require_paths = ["lib"]
36
-
37
- spec.add_dependency "concurrent-ruby", "~> 1.1.10"
38
- spec.add_dependency "faraday", "~> 2.3"
39
- spec.add_dependency "ld-eventsource", "~> 2.2.0"
40
- spec.add_dependency "murmurhash3", "~> 0.1.6"
41
- spec.add_dependency "sem_version", "~> 2.0.0"
42
-
43
- # For more information and examples about making a new gem, check out our
44
- # guide at: https://bundler.io/guides/creating_gem.html
45
- end