featurevisor 0.1.1

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.
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Featurevisor
4
+ # Log levels for the logger
5
+ LOG_LEVELS = %w[fatal error warn info debug].freeze
6
+ DEFAULT_LOG_LEVEL = "info".freeze
7
+ LOGGER_PREFIX = "[Featurevisor]".freeze
8
+
9
+ # Logger class for handling different log levels
10
+ class Logger
11
+ attr_reader :level, :handler
12
+
13
+ # Initialize a new logger
14
+ # @param options [Hash] Logger options
15
+ # @option options [String] :level Log level (default: "info")
16
+ # @option options [Proc] :handler Custom log handler (default: default_log_handler)
17
+ def initialize(options = {})
18
+ @level = options[:level] || DEFAULT_LOG_LEVEL
19
+ @handler = options[:handler] || method(:default_log_handler)
20
+ end
21
+
22
+ # Set the log level
23
+ # @param level [String] New log level
24
+ def set_level(level)
25
+ @level = level
26
+ end
27
+
28
+ # Log a message at a specific level
29
+ # @param level [String] Log level
30
+ # @param message [String] Log message
31
+ # @param details [Hash, nil] Additional details
32
+ def log(level, message, details = nil)
33
+ return unless should_handle?(level)
34
+
35
+ @handler.call(level, message, details)
36
+ end
37
+
38
+ # Log a debug message
39
+ # @param message [String] Log message
40
+ # @param details [Hash, nil] Additional details
41
+ def debug(message, details = nil)
42
+ log("debug", message, details)
43
+ end
44
+
45
+ # Log an info message
46
+ # @param message [String] Log message
47
+ # @param details [Hash, nil] Additional details
48
+ def info(message, details = nil)
49
+ log("info", message, details)
50
+ end
51
+
52
+ # Log a warning message
53
+ # @param message [String] Log message
54
+ # @param details [Hash, nil] Additional details
55
+ def warn(message, details = nil)
56
+ log("warn", message, details)
57
+ end
58
+
59
+ # Log an error message
60
+ # @param message [String] Log message
61
+ # @param details [Hash, nil] Additional details
62
+ def error(message, details = nil)
63
+ log("error", message, details)
64
+ end
65
+
66
+ # Log a fatal message
67
+ # @param message [String] Log message
68
+ # @param details [Hash, nil] Additional details
69
+ def fatal(message, details = nil)
70
+ log("fatal", message, details)
71
+ end
72
+
73
+ private
74
+
75
+ # Check if the current level should handle the given log level
76
+ # @param log_level [String] Log level to check
77
+ # @return [Boolean] True if should handle
78
+ def should_handle?(log_level)
79
+ current_index = LOG_LEVELS.index(@level)
80
+ target_index = LOG_LEVELS.index(log_level)
81
+
82
+ return false if current_index.nil? || target_index.nil?
83
+
84
+ current_index >= target_index
85
+ end
86
+
87
+ # Default log handler that outputs to console
88
+ # @param level [String] Log level
89
+ # @param message [String] Log message
90
+ # @param details [Hash, nil] Additional details
91
+ def default_log_handler(level, message, details = nil)
92
+ method_name = case level
93
+ when "info" then "puts"
94
+ when "warn" then "warn"
95
+ when "error", "fatal" then "warn"
96
+ else "puts"
97
+ end
98
+
99
+ case method_name
100
+ when "puts"
101
+ if details && !details.empty?
102
+ Kernel.puts("#{LOGGER_PREFIX} #{message} #{details.inspect}")
103
+ else
104
+ Kernel.puts("#{LOGGER_PREFIX} #{message}")
105
+ end
106
+ when "warn"
107
+ if details && !details.empty?
108
+ Kernel.warn("#{LOGGER_PREFIX} #{message} #{details.inspect}")
109
+ else
110
+ Kernel.warn("#{LOGGER_PREFIX} #{message}")
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ # Create a new logger instance
117
+ # @param options [Hash] Logger options
118
+ # @return [Logger] New logger instance
119
+ def self.create_logger(options = {})
120
+ Logger.new(options)
121
+ end
122
+
123
+ # Default log handler function
124
+ # @param level [String] Log level
125
+ # @param message [String] Log message
126
+ # @param details [Hash, nil] Additional details
127
+ def self.default_log_handler(level, message, details = nil)
128
+ method_name = case level
129
+ when "info" then "puts"
130
+ when "warn" then "warn"
131
+ when "error", "fatal" then "warn"
132
+ else "puts"
133
+ end
134
+
135
+ case method_name
136
+ when "puts"
137
+ if details && !details.empty?
138
+ Kernel.puts("#{LOGGER_PREFIX} #{message} #{details.inspect}")
139
+ else
140
+ Kernel.puts("#{LOGGER_PREFIX} #{message}")
141
+ end
142
+ when "warn"
143
+ if details && !details.empty?
144
+ Kernel.warn("#{LOGGER_PREFIX} #{message} #{details.inspect}")
145
+ else
146
+ Kernel.warn("#{LOGGER_PREFIX} #{message}")
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Featurevisor
4
+ # MurmurHash v3 implementation ported from TypeScript
5
+ # Original: https://github.com/perezd/node-murmurhash
6
+ # @param key [String, Array<Integer>] Input key to hash
7
+ # @param seed [Integer] Seed value for the hash
8
+ # @return [Integer] 32-bit hash value
9
+ def self.murmur_hash_v3(key, seed)
10
+ # Convert string to bytes if needed
11
+ key = key.bytes if key.is_a?(String)
12
+
13
+ remainder = key.length & 3 # key.length % 4
14
+ bytes = key.length - remainder
15
+ h1 = seed
16
+ c1 = 0xcc9e2d51
17
+ c2 = 0x1b873593
18
+ i = 0
19
+
20
+ # Process 4-byte chunks
21
+ while i < bytes
22
+ k1 = (key[i] & 0xff) |
23
+ ((key[i + 1] & 0xff) << 8) |
24
+ ((key[i + 2] & 0xff) << 16) |
25
+ ((key[i + 3] & 0xff) << 24)
26
+ i += 4
27
+
28
+ k1 = ((k1 & 0xffff) * c1 + ((((k1 >> 16) * c1) & 0xffff) << 16)) & 0xffffffff
29
+ k1 = (k1 << 15) | (k1 >> 17)
30
+ k1 = ((k1 & 0xffff) * c2 + ((((k1 >> 16) * c2) & 0xffff) << 16)) & 0xffffffff
31
+
32
+ h1 ^= k1
33
+ h1 = (h1 << 13) | (h1 >> 19)
34
+ h1b = ((h1 & 0xffff) * 5 + ((((h1 >> 16) * 5) & 0xffff) << 16)) & 0xffffffff
35
+ h1 = (h1b & 0xffff) + 0x6b64 + ((((h1b >> 16) + 0xe654) & 0xffff) << 16)
36
+ end
37
+
38
+ # Process remaining bytes
39
+ k1 = 0
40
+
41
+ # Handle remainder processing with fall-through behavior like TypeScript switch
42
+ if remainder >= 3
43
+ k1 ^= (key[i + 2] & 0xff) << 16
44
+ end
45
+ if remainder >= 2
46
+ k1 ^= (key[i + 1] & 0xff) << 8
47
+ end
48
+ if remainder >= 1
49
+ k1 ^= key[i] & 0xff
50
+
51
+ k1 = ((k1 & 0xffff) * c1 + ((((k1 >> 16) * c1) & 0xffff) << 16)) & 0xffffffff
52
+ k1 = (k1 << 15) | (k1 >> 17)
53
+ k1 = ((k1 & 0xffff) * c2 + ((((k1 >> 16) * c2) & 0xffff) << 16)) & 0xffffffff
54
+ h1 ^= k1
55
+ end
56
+
57
+ h1 ^= key.length
58
+
59
+ # Final mixing - use unsigned right shift equivalent
60
+ h1 ^= h1 >> 16
61
+ h1 = ((h1 & 0xffff) * 0x85ebca6b + ((((h1 >> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff
62
+ h1 ^= h1 >> 13
63
+ h1 = ((h1 & 0xffff) * 0xc2b2ae35 + ((((h1 >> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff
64
+ h1 ^= h1 >> 16
65
+
66
+ # Convert to unsigned 32-bit integer (equivalent to >>> 0 in TypeScript)
67
+ h1 & 0xffffffff
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module Featurevisor
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "featurevisor/version"
2
+ require_relative "featurevisor/murmurhash"
3
+ require_relative "featurevisor/compare_versions"
4
+ require_relative "featurevisor/logger"
5
+ require_relative "featurevisor/emitter"
6
+ require_relative "featurevisor/conditions"
7
+ require_relative "featurevisor/datafile_reader"
8
+ require_relative "featurevisor/bucketer"
9
+ require_relative "featurevisor/hooks"
10
+ require_relative "featurevisor/evaluate"
11
+ require_relative "featurevisor/instance"
12
+ require_relative "featurevisor/child_instance"
13
+ require_relative "featurevisor/events"
14
+
15
+ module Featurevisor
16
+ class Error < StandardError; end
17
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: featurevisor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Fahad Heylaal
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rspec
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.12'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.12'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ description: Featurevisor Ruby SDK with CLI tools for feature flags management
41
+ executables:
42
+ - featurevisor
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - LICENSE
47
+ - README.md
48
+ - bin/cli.rb
49
+ - bin/commands.rb
50
+ - bin/commands/assess_distribution.rb
51
+ - bin/commands/benchmark.rb
52
+ - bin/commands/test.rb
53
+ - bin/featurevisor
54
+ - lib/featurevisor.rb
55
+ - lib/featurevisor/bucketer.rb
56
+ - lib/featurevisor/child_instance.rb
57
+ - lib/featurevisor/compare_versions.rb
58
+ - lib/featurevisor/conditions.rb
59
+ - lib/featurevisor/datafile_reader.rb
60
+ - lib/featurevisor/emitter.rb
61
+ - lib/featurevisor/evaluate.rb
62
+ - lib/featurevisor/events.rb
63
+ - lib/featurevisor/hooks.rb
64
+ - lib/featurevisor/instance.rb
65
+ - lib/featurevisor/logger.rb
66
+ - lib/featurevisor/murmurhash.rb
67
+ - lib/featurevisor/version.rb
68
+ homepage: https://featurevisor.com
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 3.0.0
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubygems_version: 3.6.9
87
+ specification_version: 4
88
+ summary: Featurevisor Ruby SDK
89
+ test_files: []