Skip to content

Commit dc07a0a

Browse files
authored
Merge pull request #94 from launchdarkly/2.5.0
release 2.5.0
2 parents 6bfbdd4 + 119e520 commit dc07a0a

File tree

3 files changed

+384
-28
lines changed

3 files changed

+384
-28
lines changed

ldclient-rb.gemspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ Gem::Specification.new do |spec|
2828
spec.add_development_dependency "redis", "~> 3.3.5"
2929
spec.add_development_dependency "connection_pool", ">= 2.1.2"
3030
spec.add_development_dependency "moneta", "~> 1.0.0"
31-
31+
3232
spec.add_runtime_dependency "json", [">= 1.8", "< 3"]
3333
spec.add_runtime_dependency "faraday", [">= 0.9", "< 2"]
3434
spec.add_runtime_dependency "faraday-http-cache", [">= 1.3.0", "< 3"]
35+
spec.add_runtime_dependency "semantic", "~> 1.6.0"
3536
spec.add_runtime_dependency "thread_safe", "~> 0.3"
3637
spec.add_runtime_dependency "net-http-persistent", "~> 2.9"
3738
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0.4"

lib/ldclient-rb/evaluation.rb

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,57 @@
11
require "date"
2+
require "semantic"
23

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

8+
NUMERIC_VERSION_COMPONENTS_REGEX = Regexp.new("^[0-9.]*")
9+
10+
DATE_OPERAND = lambda do |v|
11+
if v.is_a? String
12+
begin
13+
DateTime.rfc3339(v).strftime("%Q").to_i
14+
rescue => e
15+
nil
16+
end
17+
elsif v.is_a? Numeric
18+
v
19+
else
20+
nil
21+
end
22+
end
23+
24+
SEMVER_OPERAND = lambda do |v|
25+
if v.is_a? String
26+
for _ in 0..2 do
27+
begin
28+
return Semantic::Version.new(v)
29+
rescue ArgumentError
30+
v = addZeroVersionComponent(v)
31+
end
32+
end
33+
end
34+
nil
35+
end
36+
37+
def self.addZeroVersionComponent(v)
38+
NUMERIC_VERSION_COMPONENTS_REGEX.match(v) { |m|
39+
m[0] + ".0" + v[m[0].length..-1]
40+
}
41+
end
42+
43+
def self.comparator(converter)
44+
lambda do |a, b|
45+
av = converter.call(a)
46+
bv = converter.call(b)
47+
if !av.nil? && !bv.nil?
48+
yield av <=> bv
49+
else
50+
return false
51+
end
52+
end
53+
end
54+
755
OPERATORS = {
856
in:
957
lambda do |a, b|
@@ -42,33 +90,15 @@ module Evaluation
4290
(a.is_a? Numeric) && (a >= b)
4391
end,
4492
before:
45-
lambda do |a, b|
46-
begin
47-
if a.is_a? String
48-
a = DateTime.rfc3339(a).strftime('%Q').to_i
49-
end
50-
if b.is_a? String
51-
b = DateTime.rfc3339(b).strftime('%Q').to_i
52-
end
53-
(a.is_a? Numeric) ? a < b : false
54-
rescue => e
55-
false
56-
end
57-
end,
93+
comparator(DATE_OPERAND) { |n| n < 0 },
5894
after:
59-
lambda do |a, b|
60-
begin
61-
if a.is_a? String
62-
a = DateTime.rfc3339(a).strftime("%Q").to_i
63-
end
64-
if b.is_a? String
65-
b = DateTime.rfc3339(b).strftime("%Q").to_i
66-
end
67-
(a.is_a? Numeric) ? a > b : false
68-
rescue => e
69-
false
70-
end
71-
end
95+
comparator(DATE_OPERAND) { |n| n > 0 },
96+
semVerEqual:
97+
comparator(SEMVER_OPERAND) { |n| n == 0 },
98+
semVerLessThan:
99+
comparator(SEMVER_OPERAND) { |n| n < 0 },
100+
semVerGreaterThan:
101+
comparator(SEMVER_OPERAND) { |n| n > 0 }
72102
}
73103

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

226-
id_hash = user_value(user, bucket_by)
256+
id_hash = bucketable_string_value(user_value(user, bucket_by))
257+
if id_hash.nil?
258+
return 0.0
259+
end
227260

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

271+
def bucketable_string_value(value)
272+
return value if value.is_a? String
273+
return value.to_s if value.is_a? Integer
274+
nil
275+
end
276+
238277
def user_value(user, attribute)
239278
attribute = attribute.to_sym
240279

0 commit comments

Comments
 (0)