tggl 0.1.0 → 1.0.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.
- checksums.yaml +4 -4
- data/README.md +51 -32
- data/lib/tggl/client.rb +24 -20
- data/lib/tggl/local_client.rb +10 -10
- data/lib/tggl/version.rb +1 -1
- data/sig/tggl/response.rbs +1 -1
- data/tggl.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f2f3f7c97f21e54b3592793c93c5921072fcb3ad5cae368722387f5944b15be
|
4
|
+
data.tar.gz: 4d11a8c0c434364968b8b6aceea82743e5c858e67c6deaa8e4e681bec130256d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b97a0bb7f6f4ebc6c970295d48f00d4eaac668440dc0c86024bdc232ff791fef0e015f19d20130fb03a24b0d7ae6f5931ba971129a4b09ad4a61f05667e5d0b
|
7
|
+
data.tar.gz: 11d96b403156f66bc924d7f79e349b1e8591316129ebfa9511f2084be013bf6fc59dc8c5d3a3e40b4100f8d4f84b7de79f6a9f4c354922ffc6a66f90fe201e13
|
data/README.md
CHANGED
@@ -1,35 +1,54 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
1
|
+
<p align="center">
|
2
|
+
<picture>
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://tggl.io/tggl-io-logo-white.svg">
|
4
|
+
<img align="center" alt="Tggl Logo" src="https://tggl.io/tggl-io-logo-black.svg" width="200rem" />
|
5
|
+
</picture>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<h1 align="center">Tggl Ruby SDK</h1>
|
9
|
+
|
10
|
+
<p align="center">
|
11
|
+
The Ruby SDK can be used both on the client and server to evaluate flags and report usage to the Tggl API or a <a href="https://tggl.io/developers/evaluating-flags/tggl-proxy">proxy</a>.
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<p align="center">
|
15
|
+
<a href="https://tggl.io/">🔗 Website</a>
|
16
|
+
•
|
17
|
+
<a href="https://tggl.io/developers/sdks/ruby">📚 Documentation</a>
|
18
|
+
•
|
19
|
+
<a href="https://rubygems.org/gems/tggl">📦 RubyGem</a>
|
20
|
+
•
|
21
|
+
<a href="https://www.youtube.com/@Tggl-io">🎥 Videos</a>
|
22
|
+
</p>
|
18
23
|
|
19
24
|
## Usage
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
Install the dependency:
|
27
|
+
|
28
|
+
```bash
|
29
|
+
gem install tggl
|
30
|
+
```
|
31
|
+
|
32
|
+
Start evaluating flags:
|
33
|
+
|
34
|
+
```rb
|
35
|
+
require "tggl"
|
36
|
+
|
37
|
+
$client = Tggl::Client.new("YOUR_API_KEY")
|
38
|
+
|
39
|
+
# An API call to Tggl is performed here
|
40
|
+
$flags = $client.eval_context({
|
41
|
+
userId: "abc",
|
42
|
+
email: "foo@gmail.com",
|
43
|
+
country: "FR",
|
44
|
+
# ...
|
45
|
+
})
|
46
|
+
|
47
|
+
if $flags.is_active? "my-feature"
|
48
|
+
# ...
|
49
|
+
end
|
50
|
+
|
51
|
+
if $flags.get "my-feature" == "Variation A"
|
52
|
+
# ...
|
53
|
+
end
|
54
|
+
```
|
data/lib/tggl/client.rb
CHANGED
@@ -18,33 +18,37 @@ module Tggl
|
|
18
18
|
|
19
19
|
def eval_context(context)
|
20
20
|
response = eval_contexts([context]).first
|
21
|
-
raise "Unexpected empty response from Tggl" if response.nil?
|
21
|
+
raise StandardError.new "Unexpected empty response from Tggl" if response.nil?
|
22
22
|
|
23
23
|
response
|
24
24
|
end
|
25
25
|
|
26
26
|
def eval_contexts(contexts)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
if
|
42
|
-
|
27
|
+
begin
|
28
|
+
uri = URI(@url)
|
29
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
30
|
+
http.use_ssl = true
|
31
|
+
|
32
|
+
request = Net::HTTP::Post.new(uri.path, {
|
33
|
+
'X-Tggl-Api-Key' => @api_key,
|
34
|
+
'Content-Type' => 'application/json'
|
35
|
+
})
|
36
|
+
request.body = contexts.to_json
|
37
|
+
|
38
|
+
response = http.request(request)
|
39
|
+
result = JSON.parse(response.body, symbolize_names: true)
|
40
|
+
|
41
|
+
if response.code.to_i > 200
|
42
|
+
if result.nil?
|
43
|
+
raise StandardError.new "Invalid response from Tggl: #{response.code}"
|
44
|
+
end
|
45
|
+
raise StandardError.new result['error']
|
43
46
|
end
|
44
|
-
raise result['error']
|
45
|
-
end
|
46
47
|
|
47
|
-
|
48
|
+
result.map { |flags| Response.new(flags, reporter: @reporter) }
|
49
|
+
rescue
|
50
|
+
contexts.map { || Response.new({}, reporter: @reporter) }
|
51
|
+
end
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
data/lib/tggl/local_client.rb
CHANGED
@@ -32,9 +32,9 @@ module Tggl
|
|
32
32
|
|
33
33
|
if response.code.to_i > 200
|
34
34
|
if result.nil?
|
35
|
-
raise "Invalid response from Tggl: #{response.code}"
|
35
|
+
raise StandardError.new "Invalid response from Tggl: #{response.code}"
|
36
36
|
end
|
37
|
-
raise result['error']
|
37
|
+
raise StandardError.new result['error']
|
38
38
|
end
|
39
39
|
|
40
40
|
@config = Hash.new
|
@@ -139,12 +139,12 @@ module Tggl
|
|
139
139
|
|
140
140
|
if rule[:operator] === "STR_AFTER"
|
141
141
|
return false unless value.is_a?(String)
|
142
|
-
return value >= rule[:value]
|
142
|
+
return (value >= rule[:value]) != (rule[:negate].nil? ? false : rule[:negate])
|
143
143
|
end
|
144
144
|
|
145
145
|
if rule[:operator] === "STR_BEFORE"
|
146
146
|
return false unless value.is_a?(String)
|
147
|
-
return value <= rule[:value]
|
147
|
+
return (value <= rule[:value]) != (rule[:negate].nil? ? false : rule[:negate])
|
148
148
|
end
|
149
149
|
|
150
150
|
if rule[:operator] === "REGEXP"
|
@@ -179,9 +179,9 @@ module Tggl
|
|
179
179
|
if rule[:operator] === "DATE_AFTER"
|
180
180
|
if value.is_a?(String)
|
181
181
|
val = value[0, '2000-01-01T23:59:59'.length] + ('2000-01-01T23:59:59'[value.length..] || "")
|
182
|
-
return rule[:iso] <= val
|
182
|
+
return (rule[:iso] <= val) != (rule[:negate].nil? ? false : rule[:negate])
|
183
183
|
elsif value.is_a?(Integer) || value.is_a?(Float)
|
184
|
-
return value < 631_152_000_000 ? (value * 1000 >= rule[:timestamp]) : (value >= rule[:timestamp])
|
184
|
+
return (value < 631_152_000_000 ? (value * 1000 >= rule[:timestamp]) : (value >= rule[:timestamp])) != (rule[:negate].nil? ? false : rule[:negate])
|
185
185
|
end
|
186
186
|
return false
|
187
187
|
end
|
@@ -189,9 +189,9 @@ module Tggl
|
|
189
189
|
if rule[:operator] === "DATE_BEFORE"
|
190
190
|
if value.is_a?(String)
|
191
191
|
val = value[0, '2000-01-01T00:00:00'.length] + ('2000-01-01T00:00:00'[value.length..] || "")
|
192
|
-
return rule[:iso] >= val
|
192
|
+
return (rule[:iso] >= val) != (rule[:negate].nil? ? false : rule[:negate])
|
193
193
|
elsif value.is_a?(Integer) || value.is_a?(Float)
|
194
|
-
return value < 631_152_000_000 ? (value * 1000 <= rule[:timestamp]) : (value <= rule[:timestamp])
|
194
|
+
return (value < 631_152_000_000 ? (value * 1000 <= rule[:timestamp]) : (value <= rule[:timestamp])) != (rule[:negate].nil? ? false : rule[:negate])
|
195
195
|
end
|
196
196
|
return false
|
197
197
|
end
|
@@ -248,10 +248,10 @@ module Tggl
|
|
248
248
|
return false unless value.is_a?(String) || value.is_a?(Integer) || value.is_a?(Float)
|
249
249
|
probability = XXhash.xxh32(value.to_s, rule[:seed]) / 0xFFFFFFFF.to_f
|
250
250
|
probability -= 1.0e-8 if probability == 1
|
251
|
-
return probability >= rule[:rangeStart] && probability < rule[:rangeEnd]
|
251
|
+
return (probability >= rule[:rangeStart] && probability < rule[:rangeEnd]) != (rule[:negate].nil? ? false : rule[:negate])
|
252
252
|
end
|
253
253
|
|
254
|
-
raise "Unsupported operator #{rule[:operator]}"
|
254
|
+
raise StandardError.new "Unsupported operator #{rule[:operator]}"
|
255
255
|
end
|
256
256
|
end
|
257
257
|
end
|
data/lib/tggl/version.rb
CHANGED
data/sig/tggl/response.rbs
CHANGED
@@ -3,7 +3,7 @@ module Tggl
|
|
3
3
|
@flags: Hash[Symbol, any]
|
4
4
|
@reporter: Reporting | nil
|
5
5
|
|
6
|
-
def initialize: (Hash[Symbol, untyped] flags, Reporting | nil
|
6
|
+
def initialize: (Hash[Symbol, untyped] flags, { reporter: Reporting | nil, error?: Exception | nil } options) -> void
|
7
7
|
|
8
8
|
def is_active?: (String slug) -> bool
|
9
9
|
def get: (String slug, untyped default_value) -> untyped
|
data/tggl.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["nick-keller"]
|
9
9
|
spec.email = ["hello@tggl.io"]
|
10
10
|
|
11
|
-
spec.summary = "Tggl
|
11
|
+
spec.summary = "Tggl Ruby SDK"
|
12
12
|
spec.homepage = "https://tggl.io/developers/sdks/ruby"
|
13
13
|
spec.license = "MIT"
|
14
14
|
spec.required_ruby_version = ">= 2.6.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tggl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nick-keller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xxhash
|
@@ -120,5 +120,5 @@ requirements: []
|
|
120
120
|
rubygems_version: 3.4.10
|
121
121
|
signing_key:
|
122
122
|
specification_version: 4
|
123
|
-
summary: Tggl
|
123
|
+
summary: Tggl Ruby SDK
|
124
124
|
test_files: []
|