Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ldclient-rb.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "redis", "~> 3.3.5"
spec.add_development_dependency "connection_pool", ">= 2.1.2"
spec.add_development_dependency "moneta", "~> 1.0.0"

spec.add_runtime_dependency "json", [">= 1.8", "< 3"]
spec.add_runtime_dependency "faraday", [">= 0.9", "< 2"]
spec.add_runtime_dependency "faraday-http-cache", [">= 1.3.0", "< 3"]
spec.add_runtime_dependency "semantic", "~> 1.6.0"
spec.add_runtime_dependency "thread_safe", "~> 0.3"
spec.add_runtime_dependency "net-http-persistent", "~> 2.9"
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0.4"
Expand Down
93 changes: 66 additions & 27 deletions lib/ldclient-rb/evaluation.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,57 @@
require "date"
require "semantic"

module LaunchDarkly
module Evaluation
BUILTINS = [:key, :ip, :country, :email, :firstName, :lastName, :avatar, :name, :anonymous]

NUMERIC_VERSION_COMPONENTS_REGEX = Regexp.new("^[0-9.]*")

DATE_OPERAND = lambda do |v|
if v.is_a? String
begin
DateTime.rfc3339(v).strftime("%Q").to_i
rescue => e
nil
end
elsif v.is_a? Numeric
v
else
nil
end
end

SEMVER_OPERAND = lambda do |v|
if v.is_a? String
for _ in 0..2 do
begin
return Semantic::Version.new(v)
rescue ArgumentError
v = addZeroVersionComponent(v)
end
end
end
nil
end

def self.addZeroVersionComponent(v)
NUMERIC_VERSION_COMPONENTS_REGEX.match(v) { |m|
m[0] + ".0" + v[m[0].length..-1]
}
end

def self.comparator(converter)
lambda do |a, b|
av = converter.call(a)
bv = converter.call(b)
if !av.nil? && !bv.nil?
yield av <=> bv
else
return false
end
end
end

OPERATORS = {
in:
lambda do |a, b|
Expand Down Expand Up @@ -42,33 +90,15 @@ module Evaluation
(a.is_a? Numeric) && (a >= b)
end,
before:
lambda do |a, b|
begin
if a.is_a? String
a = DateTime.rfc3339(a).strftime('%Q').to_i
end
if b.is_a? String
b = DateTime.rfc3339(b).strftime('%Q').to_i
end
(a.is_a? Numeric) ? a < b : false
rescue => e
false
end
end,
comparator(DATE_OPERAND) { |n| n < 0 },
after:
lambda do |a, b|
begin
if a.is_a? String
a = DateTime.rfc3339(a).strftime("%Q").to_i
end
if b.is_a? String
b = DateTime.rfc3339(b).strftime("%Q").to_i
end
(a.is_a? Numeric) ? a > b : false
rescue => e
false
end
end
comparator(DATE_OPERAND) { |n| n > 0 },
semVerEqual:
comparator(SEMVER_OPERAND) { |n| n == 0 },
semVerLessThan:
comparator(SEMVER_OPERAND) { |n| n < 0 },
semVerGreaterThan:
comparator(SEMVER_OPERAND) { |n| n > 0 }
}

class EvaluationError < StandardError
Expand Down Expand Up @@ -223,7 +253,10 @@ def variation_for_user(rule, user, flag)
def bucket_user(user, key, bucket_by, salt)
return nil unless user[:key]

id_hash = user_value(user, bucket_by)
id_hash = bucketable_string_value(user_value(user, bucket_by))
if id_hash.nil?
return 0.0
end

if user[:secondary]
id_hash += "." + user[:secondary]
Expand All @@ -235,6 +268,12 @@ def bucket_user(user, key, bucket_by, salt)
hash_val.to_i(16) / Float(0xFFFFFFFFFFFFFFF)
end

def bucketable_string_value(value)
return value if value.is_a? String
return value.to_s if value.is_a? Integer
nil
end

def user_value(user, attribute)
attribute = attribute.to_sym

Expand Down
Loading