toggly 0.2.1 → 0.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -0
  3. data/README.md +34 -2
  4. data/lib/toggly/client/cache_telemetry.rb +36 -0
  5. data/lib/toggly/client/snapshot_support.rb +38 -0
  6. data/lib/toggly/client.rb +173 -51
  7. data/lib/toggly/config.rb +39 -1
  8. data/lib/toggly/context.rb +135 -9
  9. data/lib/toggly/definition_cache.rb +78 -0
  10. data/lib/toggly/definitions_provider.rb +72 -18
  11. data/lib/toggly/evaluation_engine.rb +4 -3
  12. data/lib/toggly/evaluators/always_off.rb +5 -1
  13. data/lib/toggly/evaluators/always_on.rb +5 -1
  14. data/lib/toggly/evaluators/base.rb +21 -3
  15. data/lib/toggly/evaluators/browser_family.rb +27 -0
  16. data/lib/toggly/evaluators/browser_language.rb +26 -0
  17. data/lib/toggly/evaluators/context_property.rb +5 -1
  18. data/lib/toggly/evaluators/contextual_targeting.rb +4 -0
  19. data/lib/toggly/evaluators/country.rb +30 -0
  20. data/lib/toggly/evaluators/device_type.rb +27 -0
  21. data/lib/toggly/evaluators/operating_system.rb +31 -0
  22. data/lib/toggly/evaluators/percentage.rb +11 -49
  23. data/lib/toggly/evaluators/segment_helpers.rb +98 -0
  24. data/lib/toggly/evaluators/targeting.rb +61 -14
  25. data/lib/toggly/evaluators/time_window.rb +14 -9
  26. data/lib/toggly/evaluators/user_claims.rb +27 -0
  27. data/lib/toggly/feature_definition.rb +1 -2
  28. data/lib/toggly/http_request_mapper.rb +64 -0
  29. data/lib/toggly/registry.rb +25 -6
  30. data/lib/toggly/request_context.rb +77 -0
  31. data/lib/toggly/sticky_hash.rb +39 -0
  32. data/lib/toggly/telemetry/grpc_clients.rb +333 -0
  33. data/lib/toggly/telemetry/metrics_batcher.rb +140 -0
  34. data/lib/toggly/telemetry/pb/metrics_pb.rb +28 -0
  35. data/lib/toggly/telemetry/pb/metrics_services_pb.rb +28 -0
  36. data/lib/toggly/telemetry/pb/usage_pb.rb +27 -0
  37. data/lib/toggly/telemetry/pb/usage_services_pb.rb +28 -0
  38. data/lib/toggly/telemetry/runtime.rb +262 -0
  39. data/lib/toggly/telemetry/runtime_flush.rb +89 -0
  40. data/lib/toggly/telemetry/usage_batcher.rb +277 -0
  41. data/lib/toggly/telemetry.rb +37 -0
  42. data/lib/toggly/user_agent_parser.rb +69 -0
  43. data/lib/toggly/version.rb +1 -1
  44. data/lib/toggly.rb +16 -1
  45. data/proto/metrics.proto +60 -0
  46. data/proto/usage.proto +55 -0
  47. metadata +29 -3
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toggly
4
+ # Best-effort User-Agent parse result for segment filters.
5
+ class ParsedUserAgent
6
+ # @return [String]
7
+ attr_reader :browser_family, :os_family, :device_family
8
+
9
+ def initialize(browser_family:, os_family:, device_family:)
10
+ @browser_family = browser_family
11
+ @os_family = os_family
12
+ @device_family = device_family
13
+ end
14
+ end
15
+
16
+ # Best-effort UA parsing (parity with toggly-eval / Java / Python).
17
+ module UserAgentParser
18
+ module_function
19
+
20
+ # @param user_agent [String, nil]
21
+ # @return [ParsedUserAgent, nil]
22
+ def parse(user_agent)
23
+ return nil if user_agent.nil? || user_agent.empty?
24
+
25
+ ParsedUserAgent.new(
26
+ browser_family: detect_browser(user_agent),
27
+ os_family: detect_os(user_agent),
28
+ device_family: detect_device(user_agent)
29
+ )
30
+ end
31
+
32
+ def detect_browser(user_agent)
33
+ return "Edge" if user_agent.include?("Edg/") || user_agent.include?("EdgiOS/")
34
+ return "Opera" if user_agent.include?("OPR/") || user_agent.include?("Opera")
35
+ return "Chrome" if user_agent.include?("Chrome/") || user_agent.include?("CriOS/")
36
+ return "Firefox" if user_agent.include?("Firefox/") || user_agent.include?("FxiOS/")
37
+ if user_agent.include?("Safari/") && user_agent.include?("Version/") &&
38
+ !user_agent.include?("Chrome") && !user_agent.include?("Chromium")
39
+ return "Safari"
40
+ end
41
+
42
+ "Other"
43
+ end
44
+ module_function :detect_browser
45
+
46
+ def detect_os(user_agent)
47
+ return "Android" if user_agent.include?("Android")
48
+ if user_agent.include?("iPhone") || user_agent.include?("iPad") || user_agent.include?("iPod") ||
49
+ user_agent.include?("CPU iPhone OS") || user_agent.include?("CPU OS")
50
+ return "iOS"
51
+ end
52
+ return "Mac OS" if user_agent.include?("Mac OS X") || user_agent.include?("Macintosh")
53
+ return "Windows" if user_agent.include?("Windows")
54
+ return "Linux" if user_agent.include?("Linux")
55
+
56
+ "Other"
57
+ end
58
+ module_function :detect_os
59
+
60
+ def detect_device(user_agent)
61
+ return "iPhone" if user_agent.include?("iPhone")
62
+ return "iPad" if user_agent.include?("iPad")
63
+ return "iPod" if user_agent.include?("iPod")
64
+
65
+ "Other"
66
+ end
67
+ module_function :detect_device
68
+ end
69
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Toggly
4
- VERSION = "0.2.1"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/toggly.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "toggly/version"
4
+ require_relative "toggly/telemetry"
4
5
  require_relative "toggly/config"
6
+ require_relative "toggly/request_context"
7
+ require_relative "toggly/http_request_mapper"
8
+ require_relative "toggly/sticky_hash"
9
+ require_relative "toggly/user_agent_parser"
5
10
  require_relative "toggly/context"
6
11
  require_relative "toggly/errors"
7
12
  require_relative "toggly/feature_definition"
8
13
  require_relative "toggly/evaluators/base"
14
+ require_relative "toggly/evaluators/segment_helpers"
9
15
  require_relative "toggly/evaluators/always_on"
10
16
  require_relative "toggly/evaluators/always_off"
11
17
  require_relative "toggly/evaluators/percentage"
@@ -13,12 +19,19 @@ require_relative "toggly/evaluators/targeting"
13
19
  require_relative "toggly/evaluators/time_window"
14
20
  require_relative "toggly/evaluators/contextual_targeting"
15
21
  require_relative "toggly/evaluators/context_property"
22
+ require_relative "toggly/evaluators/browser_family"
23
+ require_relative "toggly/evaluators/browser_language"
24
+ require_relative "toggly/evaluators/country"
25
+ require_relative "toggly/evaluators/device_type"
26
+ require_relative "toggly/evaluators/operating_system"
27
+ require_relative "toggly/evaluators/user_claims"
16
28
  require_relative "toggly/entity_context"
17
29
  require_relative "toggly/registry"
18
30
  require_relative "toggly/evaluation_engine"
19
31
  require_relative "toggly/snapshot_providers/base"
20
32
  require_relative "toggly/snapshot_providers/memory"
21
33
  require_relative "toggly/snapshot_providers/file"
34
+ require_relative "toggly/definition_cache"
22
35
  require_relative "toggly/definitions_provider"
23
36
  require_relative "toggly/client"
24
37
 
@@ -38,7 +51,9 @@ require_relative "toggly/client"
38
51
  # context = Toggly::Context.new(
39
52
  # identity: "user-123",
40
53
  # groups: ["beta-testers"],
41
- # traits: { country: "US" }
54
+ # claims: { "role" => "admin" },
55
+ # request: Toggly::RequestContext.new(country: "US"),
56
+ # traits: { plan: "enterprise" }
42
57
  # )
43
58
  #
44
59
  # if client.enabled?("premium-feature", context: context)
@@ -0,0 +1,60 @@
1
+ syntax = "proto3";
2
+
3
+ package Metrics;
4
+
5
+ option go_package = "github.com/ops-ai/Toggly.FeatureManagement/toggly-go/toggly/metrics/metricspb";
6
+
7
+ import "google/protobuf/timestamp.proto";
8
+
9
+ message MetricStat {
10
+ string appKey = 1;
11
+ string environment = 2;
12
+ google.protobuf.Timestamp time = 3;
13
+ repeated MetricStatMessage stats = 4;
14
+ repeated MetricCounterMessage counters = 5;
15
+ repeated MetricObservationMessage observations = 6;
16
+ optional string instanceName = 7;
17
+ }
18
+
19
+ message MetricStatMessage {
20
+ string metric = 1;
21
+ int32 enabledCount = 2 [deprecated = true];
22
+ int32 disabledCount = 3 [deprecated = true];
23
+ optional string feature = 4;
24
+ double value = 5 [deprecated = true];
25
+ optional double valueDisabled = 6 [deprecated = true];
26
+
27
+ // Multi-variate support - Key: variant name (e.g., "enabled", "control")
28
+ map<string, double> variantValues = 7;
29
+ }
30
+
31
+ message MetricCounterMessage {
32
+ string metric = 1;
33
+ int32 enabledCount = 2 [deprecated = true];
34
+ int32 disabledCount = 3 [deprecated = true];
35
+ optional string feature = 4;
36
+ double value = 5 [deprecated = true];
37
+ optional double valueDisabled = 6 [deprecated = true];
38
+
39
+ map<string, double> variantValues = 7;
40
+ }
41
+
42
+ message MetricObservationMessage {
43
+ google.protobuf.Timestamp time = 1;
44
+ string metric = 2;
45
+ int32 enabledCount = 3 [deprecated = true];
46
+ int32 disabledCount = 4 [deprecated = true];
47
+ optional string feature = 5;
48
+ double value = 6 [deprecated = true];
49
+ optional double valueDisabled = 7 [deprecated = true];
50
+
51
+ map<string, double> variantValues = 8;
52
+ }
53
+
54
+ message MetricResult {
55
+ int32 count = 1;
56
+ }
57
+
58
+ service Metrics {
59
+ rpc SendMetrics(MetricStat) returns (MetricResult);
60
+ }
data/proto/usage.proto ADDED
@@ -0,0 +1,55 @@
1
+ syntax = "proto3";
2
+
3
+ package Usage;
4
+
5
+ option go_package = "github.com/ops-ai/Toggly.FeatureManagement/toggly-go/toggly/usage/usagepb";
6
+
7
+ import "google/protobuf/timestamp.proto";
8
+
9
+ message FeatureStat {
10
+ string appKey = 1;
11
+ string environment = 2;
12
+ google.protobuf.Timestamp time = 3;
13
+ repeated StatMessage stats = 4;
14
+ int32 totalUniqueUsers = 5;
15
+ optional string instanceName = 6;
16
+ optional google.protobuf.Timestamp processStartTime = 7;
17
+ optional string appVersion = 8;
18
+ repeated int32 uniqueUserHashes = 9; // Application-level unique user ID hashes
19
+ optional int32 definitionCacheHits = 10; // SDK-reported definition-refresh cache hits (batch delta)
20
+ optional int32 definitionCacheMisses = 11; // SDK-reported definition-refresh cache misses (batch delta)
21
+ }
22
+
23
+ message StatMessage {
24
+ string feature = 1;
25
+ int32 enabledCount = 2 [deprecated = true]; // Legacy: use variantStats instead
26
+ int32 disabledCount = 3 [deprecated = true]; // Legacy: use variantStats instead
27
+ int32 uniqueContextIdentifierEnabledCount = 4;
28
+ int32 uniqueContextIdentifierDisabledCount = 5;
29
+ int32 uniqueRequestEnabledCount = 6 [deprecated = true]; // Legacy: use variantStats instead
30
+ int32 uniqueRequestDisabledCount = 7 [deprecated = true]; // Legacy: use variantStats instead
31
+ int32 usedCount = 8 [deprecated = true]; // Legacy: use variantStats instead
32
+ int32 uniqueUsersUsedCount = 9;
33
+ repeated int32 uniqueUserHashes = 10; // Unique user ID hashes for "used" tracking
34
+
35
+ // Multi-variate support - all new metrics should use this
36
+ map<string, VariantStats> variantStats = 11; // Key: variant name (e.g., "enabled", "disabled")
37
+
38
+ // Unique user tracking for "viewed" metric (per feature, not per variant)
39
+ repeated int32 uniqueViewedUserHashes = 12;
40
+ }
41
+
42
+ message VariantStats {
43
+ int32 checkCount = 1;
44
+ int32 requestCount = 2;
45
+ int32 usedCount = 3;
46
+ int32 viewedCount = 4;
47
+ }
48
+
49
+ message StatResult {
50
+ int32 featureCount = 1;
51
+ }
52
+
53
+ service Usage {
54
+ rpc SendStats(FeatureStat) returns (StatResult);
55
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toggly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ops.ai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-04 00:00:00.000000000 Z
11
+ date: 2026-09-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: High-performance Ruby SDK for Toggly feature flag management. Works with
14
14
  or without Toggly.io.
@@ -23,8 +23,11 @@ files:
23
23
  - README.md
24
24
  - lib/toggly.rb
25
25
  - lib/toggly/client.rb
26
+ - lib/toggly/client/cache_telemetry.rb
27
+ - lib/toggly/client/snapshot_support.rb
26
28
  - lib/toggly/config.rb
27
29
  - lib/toggly/context.rb
30
+ - lib/toggly/definition_cache.rb
28
31
  - lib/toggly/definitions_provider.rb
29
32
  - lib/toggly/entity_context.rb
30
33
  - lib/toggly/errors.rb
@@ -32,17 +35,40 @@ files:
32
35
  - lib/toggly/evaluators/always_off.rb
33
36
  - lib/toggly/evaluators/always_on.rb
34
37
  - lib/toggly/evaluators/base.rb
38
+ - lib/toggly/evaluators/browser_family.rb
39
+ - lib/toggly/evaluators/browser_language.rb
35
40
  - lib/toggly/evaluators/context_property.rb
36
41
  - lib/toggly/evaluators/contextual_targeting.rb
42
+ - lib/toggly/evaluators/country.rb
43
+ - lib/toggly/evaluators/device_type.rb
44
+ - lib/toggly/evaluators/operating_system.rb
37
45
  - lib/toggly/evaluators/percentage.rb
46
+ - lib/toggly/evaluators/segment_helpers.rb
38
47
  - lib/toggly/evaluators/targeting.rb
39
48
  - lib/toggly/evaluators/time_window.rb
49
+ - lib/toggly/evaluators/user_claims.rb
40
50
  - lib/toggly/feature_definition.rb
51
+ - lib/toggly/http_request_mapper.rb
41
52
  - lib/toggly/registry.rb
53
+ - lib/toggly/request_context.rb
42
54
  - lib/toggly/snapshot_providers/base.rb
43
55
  - lib/toggly/snapshot_providers/file.rb
44
56
  - lib/toggly/snapshot_providers/memory.rb
57
+ - lib/toggly/sticky_hash.rb
58
+ - lib/toggly/telemetry.rb
59
+ - lib/toggly/telemetry/grpc_clients.rb
60
+ - lib/toggly/telemetry/metrics_batcher.rb
61
+ - lib/toggly/telemetry/pb/metrics_pb.rb
62
+ - lib/toggly/telemetry/pb/metrics_services_pb.rb
63
+ - lib/toggly/telemetry/pb/usage_pb.rb
64
+ - lib/toggly/telemetry/pb/usage_services_pb.rb
65
+ - lib/toggly/telemetry/runtime.rb
66
+ - lib/toggly/telemetry/runtime_flush.rb
67
+ - lib/toggly/telemetry/usage_batcher.rb
68
+ - lib/toggly/user_agent_parser.rb
45
69
  - lib/toggly/version.rb
70
+ - proto/metrics.proto
71
+ - proto/usage.proto
46
72
  homepage: https://toggly.io
47
73
  licenses:
48
74
  - MIT
@@ -52,7 +78,7 @@ metadata:
52
78
  changelog_uri: https://github.com/ops-ai/toggly-ruby/blob/main/CHANGELOG.md
53
79
  documentation_uri: https://docs.toggly.io/sdks/ruby
54
80
  rubygems_mfa_required: 'true'
55
- optional_dependencies: websocket-client-simple
81
+ optional_dependencies: websocket-client-simple, grpc, google-protobuf
56
82
  post_install_message:
57
83
  rdoc_options: []
58
84
  require_paths: