splitclient-rb 4.4.0 → 4.5.1.pre.dev

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e90a30df4c1f1e86befc5572851f37cee1e22eec
4
- data.tar.gz: 8b7eeb1065058af7efe9ec9b104d4b0bd589d199
3
+ metadata.gz: 35f1c408826430c3833af34b39b302e005b0e3d3
4
+ data.tar.gz: ee0fa5c89c7cb7a30dd0a18fa63dc645673170d9
5
5
  SHA512:
6
- metadata.gz: da5a3fc027744717443eb00c87615444890b5cccc6c018baf89f93bd111fba8951ca1f64bdab839eead72e907befee279727402961dfb56dd1e02d8d410bc046
7
- data.tar.gz: a86cd66443680a28c0b207f08cf8ff0c8e0e3130ecd9c77f542a419209c0786b3cbfe4fea4d3dc6d4afb07acb7344ac335d9478834f0a063ca3fc2e01141f910
6
+ metadata.gz: a324c37b240280be2de970a9f028095bb27cacf59bfc41c8408c509c19997933cfa90211953856c2840df9c9683e128c281b3ba33c8a2296d236cb1d97f920bc
7
+ data.tar.gz: a129c6547c71383840c78e5520d4ce544a483bea9eb5b05c09d7c1e87dfdc79b141afe0c73645e4f5b861adafd18230a341d095005cc1e455d63d0053e2b98d6
data/.gitignore CHANGED
@@ -36,3 +36,10 @@ Gemfile.lock
36
36
 
37
37
  # Ignore Byebug command history file.
38
38
  .byebug_history
39
+
40
+ # Ignore built extensions
41
+ lib/murmurhash/murmurhash.bundle
42
+ lib/murmurhash/murmurhash.so
43
+
44
+ ext/murmurhash/murmurhash.bundle
45
+ ext/murmurhash/murmurhash.so
data/CHANGES.txt CHANGED
@@ -1,3 +1,12 @@
1
+ 4.5.1 (Mar 23rd, 2018)
2
+ - Fix Forwardable load issue
3
+ - Fix native extension path issue
4
+
5
+ 4.5.0 (Mar 2nd, 2018)
6
+
7
+ - Move MurmurHash3 implementation inside the gem
8
+ - Add native Java MurmurHash3 implementation -> now support JRuby
9
+
1
10
  4.4.0 (Feb 5th, 2018)
2
11
  - Add track API
3
12
 
data/NEWS CHANGED
@@ -1,3 +1,7 @@
1
+ 4.5.0
2
+
3
+ Add JRuby support
4
+
1
5
  4.4.0
2
6
 
3
7
  Add the ability to send event data to split service (.track() api)
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [ ![Codeship Status for splitio/ruby-client](https://app.codeship.com/projects/306c6b60-c164-0133-e179-16471d4e6045/status?branch=master)](https://app.codeship.com/projects/137510)
2
+
1
3
  # Split Ruby SDK
2
4
 
3
5
  This SDK is designed to work with [Split](https://www.split.io), the platform for controlled rollouts, serving features to your users via the Split feature flag to manage your complete customer experience.
data/Rakefile CHANGED
@@ -1,4 +1,24 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
3
7
 
4
- Dir.glob('tasks/**/*.rake').each(&method(:import))
8
+ task :spec => :compile
9
+ case RUBY_PLATFORM
10
+ when 'java'
11
+ require 'rake/javaextensiontask'
12
+ Rake::JavaExtensionTask.new 'murmurhash' do |ext|
13
+ ext.lib_dir = 'lib/murmurhash'
14
+ ext.target_version = '1.7'
15
+ ext.source_version = '1.7'
16
+ end
17
+ else
18
+ require 'rake/extensiontask'
19
+ Rake::ExtensionTask.new 'murmurhash' do |ext|
20
+ ext.lib_dir = 'lib/murmurhash'
21
+ end
22
+ end
23
+
24
+ task :default => :spec
@@ -0,0 +1,88 @@
1
+ /*
2
+ * MurmurHash3_x86_32 (C) Austin Appleby
3
+ */
4
+
5
+ #include "murmurhash.h"
6
+
7
+ uint32_t
8
+ murmur_hash_process3_x86_32(const char * key, uint32_t len, uint32_t seed)
9
+ {
10
+ const uint8_t * data = (const uint8_t*)key;
11
+ const int nblocks = len / 4;
12
+ int i;
13
+
14
+ uint32_t h1 = seed;
15
+
16
+ const uint32_t c1 = 0xcc9e2d51;
17
+ const uint32_t c2 = 0x1b873593;
18
+
19
+ //----------
20
+ // body
21
+
22
+ const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
23
+
24
+ for(i = -nblocks; i; i++)
25
+ {
26
+ uint32_t k1 = getblock32(blocks,i);
27
+
28
+ k1 *= c1;
29
+ k1 = ROTL32(k1,15);
30
+ k1 *= c2;
31
+
32
+ h1 ^= k1;
33
+ h1 = ROTL32(h1,13);
34
+ h1 = h1*5+0xe6546b64;
35
+ }
36
+
37
+ //----------
38
+ // tail
39
+
40
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
41
+
42
+ uint32_t k1 = 0;
43
+
44
+ switch(len & 3)
45
+ {
46
+ case 3: k1 ^= tail[2] << 16;
47
+ case 2: k1 ^= tail[1] << 8;
48
+ case 1: k1 ^= tail[0];
49
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
50
+ };
51
+
52
+ //----------
53
+ // finalization
54
+
55
+ h1 ^= len;
56
+
57
+ h1 = fmix32(h1);
58
+
59
+ return h1;
60
+ }
61
+
62
+ VALUE
63
+ murmur3_x86_32_finish(VALUE self)
64
+ {
65
+ uint8_t digest[4];
66
+ uint32_t h;
67
+
68
+ h = _murmur_finish32(self, murmur_hash_process3_x86_32);
69
+ assign_by_endian_32(digest, h);
70
+ return rb_str_new((const char*) digest, 4);
71
+ }
72
+
73
+ VALUE
74
+ murmur3_x86_32_s_digest(int argc, VALUE *argv, VALUE klass)
75
+ {
76
+ uint8_t digest[4];
77
+ uint32_t h;
78
+
79
+ h = _murmur_s_digest32(argc, argv, klass, murmur_hash_process3_x86_32);
80
+ assign_by_endian_32(digest, h);
81
+ return rb_str_new((const char*) digest, 4);
82
+ }
83
+
84
+ VALUE
85
+ murmur3_x86_32_s_rawdigest(int argc, VALUE *argv, VALUE klass)
86
+ {
87
+ return ULL2NUM(_murmur_s_digest32(argc, argv, klass, murmur_hash_process3_x86_32));
88
+ }
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('murmurhash/murmurhash')
@@ -0,0 +1,251 @@
1
+ #include "murmurhash.h"
2
+
3
+ ID id_DEFAULT_SEED;
4
+ ID iv_seed;
5
+ ID iv_buffer;
6
+
7
+
8
+ inline uint32_t rotl32 ( uint32_t x, int8_t r )
9
+ {
10
+ return (x << r) | (x >> (32 - r));
11
+ }
12
+ inline uint64_t rotl64 ( uint64_t x, int8_t r )
13
+ {
14
+ return (x << r) | (x >> (64 - r));
15
+ }
16
+
17
+ FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i )
18
+ {
19
+ return p[i];
20
+ }
21
+
22
+ FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, int i )
23
+ {
24
+ return p[i];
25
+ }
26
+
27
+ FORCE_INLINE uint32_t fmix32 ( uint32_t h )
28
+ {
29
+ h ^= h >> 16;
30
+ h *= 0x85ebca6b;
31
+ h ^= h >> 13;
32
+ h *= 0xc2b2ae35;
33
+ h ^= h >> 16;
34
+
35
+ return h;
36
+ }
37
+
38
+ FORCE_INLINE uint64_t fmix64 ( uint64_t k )
39
+ {
40
+ k ^= k >> 33;
41
+ k *= BIG_CONSTANT(0xff51afd7ed558ccd);
42
+ k ^= k >> 33;
43
+ k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
44
+ k ^= k >> 33;
45
+
46
+ return k;
47
+ }
48
+
49
+ void
50
+ assign_by_endian_32(uint8_t *digest, uint32_t h)
51
+ {
52
+ if (BIGENDIAN_P()) {
53
+ digest[0] = h >> 24;
54
+ digest[1] = h >> 16;
55
+ digest[2] = h >> 8;
56
+ digest[3] = h;
57
+ }
58
+ else {
59
+ digest[3] = h >> 24;
60
+ digest[2] = h >> 16;
61
+ digest[1] = h >> 8;
62
+ digest[0] = h;
63
+ }
64
+ }
65
+
66
+ void
67
+ assign_by_endian_64(uint8_t *digest, uint64_t h)
68
+ {
69
+ if (BIGENDIAN_P()) {
70
+ digest[0] = h >> 56;
71
+ digest[1] = h >> 48;
72
+ digest[2] = h >> 40;
73
+ digest[3] = h >> 32;
74
+ digest[4] = h >> 24;
75
+ digest[5] = h >> 16;
76
+ digest[6] = h >> 8;
77
+ digest[7] = h;
78
+ }
79
+ else {
80
+ digest[7] = h >> 56;
81
+ digest[6] = h >> 48;
82
+ digest[5] = h >> 40;
83
+ digest[4] = h >> 32;
84
+ digest[3] = h >> 24;
85
+ digest[2] = h >> 16;
86
+ digest[1] = h >> 8;
87
+ digest[0] = h;
88
+ }
89
+ }
90
+
91
+ void
92
+ assign_by_endian_128(uint8_t *digest, void *out)
93
+ {
94
+ int i;
95
+
96
+ if (BIGENDIAN_P()) {
97
+ for (i = 0; i < 4; i++) {
98
+ digest[(i*4) ] = ((uint32_t*)out)[i] >> 24;
99
+ digest[(i*4)+1] = ((uint32_t*)out)[i] >> 16;
100
+ digest[(i*4)+2] = ((uint32_t*)out)[i] >> 8;
101
+ digest[(i*4)+3] = ((uint32_t*)out)[i];
102
+ }
103
+ }
104
+ else {
105
+ for (i = 0; i < 4; i++) {
106
+ digest[16-(i*4)-1] = ((uint32_t*)out)[i] >> 24;
107
+ digest[16-(i*4)-2] = ((uint32_t*)out)[i] >> 16;
108
+ digest[16-(i*4)-3] = ((uint32_t*)out)[i] >> 8;
109
+ digest[16-(i*4)-4] = ((uint32_t*)out)[i];
110
+ }
111
+ }
112
+ }
113
+
114
+ static uint32_t
115
+ rstring2uint32_t(VALUE str)
116
+ {
117
+ long len = RSTRING_LEN(str);
118
+ if (UINT32_MAX < len) {
119
+ rb_raise(rb_eRangeError, "String length=%ld will overflow from long to uint32_t", len);
120
+ }
121
+ return (uint32_t)len;
122
+ }
123
+
124
+ uint32_t
125
+ _murmur_finish32(VALUE self, uint32_t (*process)(const char*, uint32_t, uint32_t))
126
+ {
127
+ const char *seed = RSTRING_PTR(rb_ivar_get(self, iv_seed));
128
+ VALUE buffer = rb_ivar_get(self, iv_buffer);
129
+ return process(RSTRING_PTR(buffer), rstring2uint32_t(buffer), *(uint32_t*)seed);
130
+ }
131
+
132
+ uint64_t
133
+ _murmur_finish64(VALUE self, uint64_t (*process)(const char*, uint32_t, uint64_t))
134
+ {
135
+ const char *seed = RSTRING_PTR(rb_ivar_get(self, iv_seed));
136
+ VALUE buffer = rb_ivar_get(self, iv_buffer);
137
+ return process(RSTRING_PTR(buffer), rstring2uint32_t(buffer), *(uint64_t*)seed);
138
+ }
139
+
140
+ void
141
+ _murmur_finish128(VALUE self, void *out, void (*process)(const char*, uint32_t, uint32_t, void*))
142
+ {
143
+ const char *seed = RSTRING_PTR(rb_ivar_get(self, iv_seed));
144
+ VALUE buffer = rb_ivar_get(self, iv_buffer);
145
+ process(RSTRING_PTR(buffer), rstring2uint32_t(buffer), *(uint32_t*)seed, out);
146
+ }
147
+
148
+ uint32_t
149
+ _murmur_s_digest32(int argc, VALUE *argv, VALUE klass, uint32_t (*process)(const char *, uint32_t, uint32_t))
150
+ {
151
+ VALUE str;
152
+ const char *seed;
153
+
154
+ if (argc < 1)
155
+ rb_raise(rb_eArgError, "no data given");
156
+
157
+ str = *argv;
158
+
159
+ StringValue(str);
160
+
161
+ if (1 < argc) {
162
+ StringValue(argv[1]);
163
+ if (RSTRING_LEN(argv[1]) != 4) {
164
+ rb_raise(rb_eArgError, "seed string should be 4 length");
165
+ }
166
+ seed = RSTRING_PTR(argv[1]);
167
+ } else {
168
+ seed = RSTRING_PTR(rb_const_get(klass, id_DEFAULT_SEED));
169
+ }
170
+
171
+ return process(RSTRING_PTR(str), rstring2uint32_t(str), *(uint32_t*)seed);
172
+ }
173
+
174
+ uint64_t
175
+ _murmur_s_digest64(int argc, VALUE *argv, VALUE klass, uint64_t (*process)(const char *, uint32_t, uint64_t))
176
+ {
177
+ VALUE str;
178
+ const char *seed;
179
+
180
+ if (argc < 1)
181
+ rb_raise(rb_eArgError, "no data given");
182
+
183
+ str = *argv;
184
+
185
+ StringValue(str);
186
+
187
+ if (1 < argc) {
188
+ StringValue(argv[1]);
189
+ if (RSTRING_LEN(argv[1]) != 8) {
190
+ rb_raise(rb_eArgError, "seed string should be 8 length");
191
+ }
192
+ seed = RSTRING_PTR(argv[1]);
193
+ } else {
194
+ seed = RSTRING_PTR(rb_const_get(klass, id_DEFAULT_SEED));
195
+ }
196
+
197
+ return process(RSTRING_PTR(str), rstring2uint32_t(str), *(uint64_t*)seed);
198
+ }
199
+
200
+ void
201
+ _murmur_s_digest128(int argc, VALUE *argv, VALUE klass, void *out, void (*process)(const char *, uint32_t, uint32_t, void *))
202
+ {
203
+ VALUE str;
204
+ const char *seed;
205
+ int seed_length = 4;
206
+
207
+ if (argc < 1)
208
+ rb_raise(rb_eArgError, "no data given");
209
+
210
+ str = *argv;
211
+
212
+ StringValue(str);
213
+
214
+ if (1 < argc) {
215
+ StringValue(argv[1]);
216
+ if (RSTRING_LEN(argv[1]) != seed_length) {
217
+ rb_raise(rb_eArgError, "seed string should be %d length", seed_length);
218
+ }
219
+ seed = RSTRING_PTR(argv[1]);
220
+ } else {
221
+ seed = RSTRING_PTR(rb_const_get(klass, id_DEFAULT_SEED));
222
+ }
223
+
224
+ process(RSTRING_PTR(str), rstring2uint32_t(str), *(uint32_t*)seed, out);
225
+ }
226
+
227
+
228
+ void
229
+ Init_murmurhash(void)
230
+ {
231
+ VALUE cDigest_MurmurHash1,
232
+ cDigest_MurmurHash2,
233
+ cDigest_MurmurHash2A,
234
+ cDigest_MurmurHash64A,
235
+ cDigest_MurmurHash64B,
236
+ cDigest_MurmurHashNeutral2,
237
+ cDigest_MurmurHashAligned2,
238
+ cDigest_MurmurHash3_x86_32,
239
+ cDigest_MurmurHash3_x86_128,
240
+ cDigest_MurmurHash3_x64_128;
241
+
242
+ id_DEFAULT_SEED = rb_intern("DEFAULT_SEED");
243
+ iv_seed = rb_intern("@seed");
244
+ iv_buffer = rb_intern("@buffer");
245
+
246
+
247
+ cDigest_MurmurHash3_x86_32 = rb_path2class("Digest::MurmurHashMRI3_x86_32");
248
+ rb_define_singleton_method(cDigest_MurmurHash3_x86_32, "digest", murmur3_x86_32_s_digest, -1);
249
+ rb_define_singleton_method(cDigest_MurmurHash3_x86_32, "rawdigest", murmur3_x86_32_s_rawdigest, -1);
250
+ rb_define_private_method(cDigest_MurmurHash3_x86_32, "finish", murmur3_x86_32_finish, 0);
251
+ }
@@ -0,0 +1,94 @@
1
+ #ifndef MURMURHASH_INCLUDED
2
+ # define MURMURHASH_INCLUDED
3
+
4
+ #include "ruby.h"
5
+
6
+ // Microsoft Visual Studio
7
+
8
+ #if defined(_MSC_VER)
9
+ #define FORCE_INLINE __forceinline
10
+ #include <stdlib.h>
11
+ #define ROTL32(x,y) _rotl(x,y)
12
+ #define ROTL64(x,y) _rotl64(x,y)
13
+ #define BIG_CONSTANT(x) (x)
14
+ #else // defined(_MSC_VER)
15
+ #define FORCE_INLINE inline __attribute__((always_inline))
16
+ #define ROTL32(x,y) rotl32(x,y)
17
+ #define ROTL64(x,y) rotl64(x,y)
18
+ #define BIG_CONSTANT(x) (x##LLU)
19
+ #endif // !defined(_MSC_VER)
20
+
21
+ #ifdef DYNAMIC_ENDIAN
22
+ /* for universal binary of NEXTSTEP and MacOS X */
23
+ /* useless since autoconf 2.63? */
24
+ static int
25
+ is_bigendian(void)
26
+ {
27
+ static int init = 0;
28
+ static int endian_value;
29
+ char *p;
30
+
31
+ if (init) return endian_value;
32
+ init = 1;
33
+ p = (char*)&init;
34
+ return endian_value = p[0] ? 0 : 1;
35
+ }
36
+ # define BIGENDIAN_P() (is_bigendian())
37
+ #elif defined(WORDS_BIGENDIAN)
38
+ # define BIGENDIAN_P() 1
39
+ #else
40
+ # define BIGENDIAN_P() 0
41
+ #endif
42
+
43
+ #define MURMURHASH_MAGIC 0x5bd1e995
44
+ #define MURMURHASH_MAGIC64A BIG_CONSTANT(0xc6a4a7935bd1e995)
45
+
46
+ void assign_by_endian_32(uint8_t *digest, uint32_t h);
47
+ void assign_by_endian_64(uint8_t *digest, uint64_t h);
48
+ void assign_by_endian_128(uint8_t*, void*);
49
+
50
+ uint32_t rotl32(uint32_t, int8_t);
51
+ uint64_t rotl64(uint64_t, int8_t);
52
+ uint32_t getblock32(const uint32_t*, int);
53
+ uint64_t getblock64(const uint64_t*, int);
54
+ uint32_t fmix32(uint32_t);
55
+ uint64_t fmix64(uint64_t);
56
+ uint32_t _murmur_finish32(VALUE, uint32_t (*)(const char*, uint32_t, uint32_t));
57
+ uint64_t _murmur_finish64(VALUE, uint64_t (*)(const char*, uint32_t, uint64_t));
58
+ void _murmur_finish128(VALUE, void*, void (*)(const char*, uint32_t, uint32_t, void*));
59
+ uint32_t _murmur_s_digest32(int, VALUE*, VALUE, uint32_t (*)(const char*, uint32_t, uint32_t));
60
+ uint64_t _murmur_s_digest64(int, VALUE*, VALUE, uint64_t (*)(const char*, uint32_t, uint64_t));
61
+ void _murmur_s_digest128(int, VALUE*, VALUE, void*, void (*)(const char*, uint32_t, uint32_t, void*));
62
+
63
+ VALUE murmur1_finish(VALUE);
64
+ VALUE murmur1_s_digest(int, VALUE*, VALUE);
65
+ VALUE murmur1_s_rawdigest(int, VALUE*, VALUE);
66
+ VALUE murmur2_finish(VALUE);
67
+ VALUE murmur2_s_digest(int, VALUE*, VALUE);
68
+ VALUE murmur2_s_rawdigest(int, VALUE*, VALUE);
69
+ VALUE murmur2a_finish(VALUE);
70
+ VALUE murmur2a_s_digest(int, VALUE*, VALUE);
71
+ VALUE murmur2a_s_rawdigest(int, VALUE*, VALUE);
72
+ VALUE murmur64a_finish(VALUE);
73
+ VALUE murmur64a_s_digest(int, VALUE*, VALUE);
74
+ VALUE murmur64a_s_rawdigest(int, VALUE*, VALUE);
75
+ VALUE murmur64b_finish(VALUE);
76
+ VALUE murmur64b_s_digest(int, VALUE*, VALUE);
77
+ VALUE murmur64b_s_rawdigest(int, VALUE*, VALUE);
78
+ VALUE murmur_neutral2_finish(VALUE);
79
+ VALUE murmur_neutral2_s_digest(int, VALUE*, VALUE);
80
+ VALUE murmur_neutral2_s_rawdigest(int, VALUE*, VALUE);
81
+ VALUE murmur_aligned2_finish(VALUE);
82
+ VALUE murmur_aligned2_s_digest(int, VALUE*, VALUE);
83
+ VALUE murmur_aligned2_s_rawdigest(int, VALUE*, VALUE);
84
+ VALUE murmur3_x86_32_finish(VALUE);
85
+ VALUE murmur3_x86_32_s_digest(int, VALUE*, VALUE);
86
+ VALUE murmur3_x86_32_s_rawdigest(int, VALUE*, VALUE);
87
+ VALUE murmur3_x86_128_finish(VALUE);
88
+ VALUE murmur3_x86_128_s_digest(int, VALUE*, VALUE);
89
+ VALUE murmur3_x86_128_s_rawdigest(int, VALUE*, VALUE);
90
+ VALUE murmur3_x64_128_finish(VALUE);
91
+ VALUE murmur3_x64_128_s_digest(int, VALUE*, VALUE);
92
+ VALUE murmur3_x64_128_s_rawdigest(int, VALUE*, VALUE);
93
+
94
+ #endif /* ifndef MURMURHASH_INCLUDED */
@@ -0,0 +1,58 @@
1
+ module Digest
2
+ ds = Struct.new(:digest_length, :seed_length)
3
+ s1 = ds.new(4, 4)
4
+ s2 = ds.new(8, 8)
5
+ s3 = ds.new(16, 4)
6
+ {
7
+ '1' => s1,
8
+ '2' => s1,
9
+ '2A' => s1,
10
+ '64A' => s2,
11
+ '64B' => s2,
12
+ 'Aligned2' => s1,
13
+ 'Neutral2' => s1,
14
+ '3_x86_32' => s1,
15
+ '3_x86_128' => s3,
16
+ '3_x64_128' => s3,
17
+ }.each do |name, s|
18
+ class_eval %Q{
19
+ class MurmurHashMRI#{name} < Digest::Class
20
+ DEFAULT_SEED = "#{"\x00" * s.seed_length}".b
21
+
22
+ def initialize
23
+ @buffer = ""
24
+ @seed = DEFAULT_SEED
25
+ end
26
+
27
+ def update(str)
28
+ @buffer << str
29
+ self
30
+ end
31
+ alias << update
32
+
33
+ def reset
34
+ @buffer.clear
35
+ @seed = DEFAULT_SEED
36
+ self
37
+ end
38
+
39
+ def seed
40
+ @seed
41
+ end
42
+
43
+ def seed=(s)
44
+ raise ArgumentError, "seed string should be #{s.seed_length} length" if #{s.seed_length} != s.length
45
+ @seed = s
46
+ end
47
+
48
+ def digest_length
49
+ #{s.digest_length}
50
+ end
51
+
52
+ def block_length
53
+ 0
54
+ end
55
+ end
56
+ }
57
+ end
58
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ require 'digest'
2
+ require 'murmurhash/base'
3
+ require 'murmurhash/murmurhash'
@@ -1,5 +1,3 @@
1
- require 'forwardable'
2
-
3
1
  module SplitIoClient
4
2
  module Cache
5
3
  module Repositories
@@ -1,118 +1,123 @@
1
- require 'digest/murmurhash'
2
-
3
1
  module SplitIoClient
4
2
  # Misc class in charge of providing hash functions and
5
3
  # determination of treatment based on concept of buckets
6
4
  # based on provided key
7
5
  #
8
6
  class Splitter < NoMethodError
9
- class << self
10
- #
11
- # Checks if the partiotion size is 100%
12
- #
13
- # @param partitions [object] array of partitions
14
- #
15
- # @return [boolean] true if partition is 100% false otherwise
16
- def hundred_percent_one_treatment?(partitions)
17
- (partitions.size != 1) ? false : (partitions.first.size == 100)
7
+ def initialize
8
+ @murmur_hash = case RUBY_PLATFORM
9
+ when 'java'
10
+ Proc.new { |key, seed| Java::MurmurHash3.murmurhash3_x86_32(key, seed) }
11
+ else
12
+ Proc.new { |key, seed| Digest::MurmurHashMRI3_x86_32.rawdigest(key, [seed].pack('L')) }
18
13
  end
14
+ end
15
+
16
+ #
17
+ # Checks if the partiotion size is 100%
18
+ #
19
+ # @param partitions [object] array of partitions
20
+ #
21
+ # @return [boolean] true if partition is 100% false otherwise
22
+ def hundred_percent_one_treatment?(partitions)
23
+ (partitions.size != 1) ? false : (partitions.first.size == 100)
24
+ end
19
25
 
20
- #
21
- # gets the appropriate treatment based on id, seed and partition value
22
- #
23
- # @param id [string] user key
24
- # @param seed [number] seed for the user key
25
- # @param partitions [object] array of partitions
26
- #
27
- # @return traetment [object] treatment value
28
- def get_treatment(id, seed, partitions, legacy_algo)
29
- legacy = (legacy_algo == 1 || legacy_algo == nil) ? true : false
30
-
31
- if partitions.empty?
32
- return SplitIoClient::Engine::Models::Treatment::CONTROL
33
- end
34
-
35
- if hundred_percent_one_treatment?(partitions)
36
- return (partitions.first).treatment
37
- end
38
-
39
- return get_treatment_for_key(bucket(count_hash(id, seed, legacy_algo)), partitions)
26
+ #
27
+ # gets the appropriate treatment based on id, seed and partition value
28
+ #
29
+ # @param id [string] user key
30
+ # @param seed [number] seed for the user key
31
+ # @param partitions [object] array of partitions
32
+ #
33
+ # @return traetment [object] treatment value
34
+ def get_treatment(id, seed, partitions, legacy_algo)
35
+ legacy = [1, nil].include?(legacy_algo)
36
+
37
+ if partitions.empty?
38
+ return SplitIoClient::Engine::Models::Treatment::CONTROL
40
39
  end
41
40
 
42
- # returns a hash value for the give key, seed pair
43
- #
44
- # @param key [String] user key
45
- # @param seed [Fixnum] seed for the user key
46
- #
47
- # @return hash [String] hash value
48
- def count_hash(key, seed, legacy)
49
- legacy ? legacy_hash(key, seed) : murmur_hash(key, seed)
41
+ if hundred_percent_one_treatment?(partitions)
42
+ return (partitions.first).treatment
50
43
  end
51
44
 
52
- def murmur_hash(key, seed)
53
- Digest::MurmurHash3_x86_32.rawdigest(key, [seed].pack('L'))
54
- end
45
+ return get_treatment_for_key(bucket(count_hash(id, seed, legacy_algo)), partitions)
46
+ end
55
47
 
56
- def legacy_hash(key, seed)
57
- h = 0
48
+ # returns a hash value for the give key, seed pair
49
+ #
50
+ # @param key [String] user key
51
+ # @param seed [Fixnum] seed for the user key
52
+ #
53
+ # @return hash [String] hash value
54
+ def count_hash(key, seed, legacy)
55
+ legacy ? legacy_hash(key, seed) : murmur_hash(key, seed)
56
+ end
58
57
 
59
- for i in 0..key.length-1
60
- h = to_int32(31 * h + key[i].ord)
61
- end
58
+ def murmur_hash(key, seed)
59
+ @murmur_hash.call(key, seed)
60
+ end
62
61
 
63
- h^seed
64
- end
62
+ def legacy_hash(key, seed)
63
+ h = 0
65
64
 
66
- #
67
- # misc method to convert ruby number to int 32 since overflow is handled different to java
68
- #
69
- # @param number [number] ruby number value
70
- #
71
- # @return [int] returns the int 32 value of the provided number
72
- def to_int32(number)
73
- begin
74
- sign = number < 0 ? -1 : 1
75
- abs = number.abs
76
- return 0 if abs == 0 || abs == Float::INFINITY
77
- rescue
78
- return 0
79
- end
65
+ for i in 0..key.length-1
66
+ h = to_int32(31 * h + key[i].ord)
67
+ end
80
68
 
81
- pos_int = sign * abs.floor
82
- int_32bit = pos_int % 2**32
69
+ h^seed
70
+ end
83
71
 
84
- return int_32bit - 2**32 if int_32bit >= 2**31
85
- int_32bit
72
+ #
73
+ # misc method to convert ruby number to int 32 since overflow is handled different to java
74
+ #
75
+ # @param number [number] ruby number value
76
+ #
77
+ # @return [int] returns the int 32 value of the provided number
78
+ def to_int32(number)
79
+ begin
80
+ sign = number < 0 ? -1 : 1
81
+ abs = number.abs
82
+ return 0 if abs == 0 || abs == Float::INFINITY
83
+ rescue
84
+ return 0
86
85
  end
87
86
 
88
- #
89
- # returns the treatment for a bucket given the partitions
90
- #
91
- # @param bucket [number] bucket value
92
- # @param parittions [object] array of partitions
93
- #
94
- # @return treatment [treatment] treatment value for this bucket and partitions
95
- def get_treatment_for_key(bucket, partitions)
96
- buckets_covered_thus_far = 0
97
- partitions.each do |p|
98
- unless p.is_empty?
99
- buckets_covered_thus_far += p.size
100
- return p.treatment if buckets_covered_thus_far >= bucket
101
- end
102
- end
87
+ pos_int = sign * abs.floor
88
+ int_32bit = pos_int % 2**32
103
89
 
104
- return SplitIoClient::Engine::Models::Treatment::CONTROL
105
- end
90
+ return int_32bit - 2**32 if int_32bit >= 2**31
91
+ int_32bit
92
+ end
106
93
 
107
- #
108
- # returns bucket value for the given hash value
109
- #
110
- # @param hash_value [string] hash value
111
- #
112
- # @return bucket [number] bucket number
113
- def bucket(hash_value)
114
- (hash_value.abs % 100) + 1
94
+ #
95
+ # returns the treatment for a bucket given the partitions
96
+ #
97
+ # @param bucket [number] bucket value
98
+ # @param parittions [object] array of partitions
99
+ #
100
+ # @return treatment [treatment] treatment value for this bucket and partitions
101
+ def get_treatment_for_key(bucket, partitions)
102
+ buckets_covered_thus_far = 0
103
+ partitions.each do |p|
104
+ unless p.is_empty?
105
+ buckets_covered_thus_far += p.size
106
+ return p.treatment if buckets_covered_thus_far >= bucket
107
+ end
115
108
  end
109
+
110
+ return SplitIoClient::Engine::Models::Treatment::CONTROL
111
+ end
112
+
113
+ #
114
+ # returns bucket value for the given hash value
115
+ #
116
+ # @param hash_value [string] hash value
117
+ #
118
+ # @return bucket [number] bucket number
119
+ def bucket(hash_value)
120
+ (hash_value.abs % 100) + 1
116
121
  end
117
122
  end
118
123
  end
@@ -40,6 +40,7 @@ module SplitIoClient
40
40
  in_rollout = false
41
41
  key = keys[:bucketing_key] ? keys[:bucketing_key] : keys[:matching_key]
42
42
  legacy_algo = (split[:algo] == 1 || split[:algo] == nil) ? true : false
43
+ splitter = Splitter.new
43
44
 
44
45
  split[:conditions].each do |c|
45
46
  condition = SplitIoClient::Condition.new(c)
@@ -48,7 +49,7 @@ module SplitIoClient
48
49
 
49
50
  if !in_rollout && condition.type == SplitIoClient::Condition::TYPE_ROLLOUT
50
51
  if split[:trafficAllocation] < 100
51
- bucket = Splitter.bucket(Splitter.count_hash(key, split[:trafficAllocationSeed].to_i, legacy_algo))
52
+ bucket = splitter.bucket(splitter.count_hash(key, split[:trafficAllocationSeed].to_i, legacy_algo))
52
53
 
53
54
  if bucket >= split[:trafficAllocation]
54
55
  return treatment_hash(Models::Label::NOT_IN_SPLIT, split[:defaultTreatment], split[:changeNumber])
@@ -67,7 +68,7 @@ module SplitIoClient
67
68
 
68
69
  next unless condition_matched
69
70
 
70
- result = Splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
71
+ result = splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
71
72
 
72
73
  if result.nil?
73
74
  return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber])
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '4.4.0'
2
+ VERSION = '4.5.1-dev'
3
3
  end
@@ -1,3 +1,5 @@
1
+ require 'forwardable'
2
+
1
3
  require 'splitclient-rb/version'
2
4
 
3
5
  require 'splitclient-rb/exceptions/impressions_shutdown_exception'
@@ -78,6 +80,9 @@ require 'splitclient-rb/engine/models/label'
78
80
  require 'splitclient-rb/engine/models/treatment'
79
81
  require 'splitclient-rb/utilitites'
80
82
 
83
+ # C extension
84
+ require 'murmurhash/murmurhash_mri'
85
+
81
86
  module SplitIoClient
82
87
  def self.root
83
88
  File.dirname(__dir__)
@@ -14,18 +14,30 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://github.com/splitio/ruby-client"
15
15
  spec.license = "Apache 2.0"
16
16
 
17
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|features|ext)/}) }
18
+
18
19
  spec.bindir = "exe"
19
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
21
  spec.require_paths = ["lib"]
21
22
 
23
+ if defined?(JRUBY_VERSION)
24
+ spec.platform = 'java'
25
+ spec.files << 'ext/murmurhash/MurmurHash3.java'
26
+ else
27
+ spec.files.concat(%w(
28
+ ext/murmurhash/3_x86_32.c
29
+ ext/murmurhash/extconf.rb
30
+ ext/murmurhash/murmurhash.c
31
+ ext/murmurhash/murmurhash.h)
32
+ )
33
+ spec.extensions = ["ext/murmurhash/extconf.rb"]
34
+ end
35
+
22
36
  spec.add_development_dependency "bundler", "~> 1.11"
23
37
  spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "rake-compiler"
24
39
  spec.add_development_dependency "rspec"
25
40
  spec.add_development_dependency "webmock"
26
- spec.add_development_dependency "byebug"
27
- spec.add_development_dependency "pry"
28
- spec.add_development_dependency "pry-byebug"
29
41
  spec.add_development_dependency "simplecov"
30
42
  spec.add_development_dependency "allocation_stats"
31
43
 
@@ -35,5 +47,4 @@ Gem::Specification.new do |spec|
35
47
  spec.add_runtime_dependency "faraday", ">= 0.8"
36
48
  spec.add_runtime_dependency "net-http-persistent", "~> 2.9"
37
49
  spec.add_runtime_dependency "redis", ">= 3.2"
38
- spec.add_runtime_dependency "digest-murmurhash", ">= 1.1"
39
50
  end
@@ -1,4 +1,4 @@
1
1
  desc "Open an irb session preloaded with this library"
2
- task :console do
2
+ task :irb do
3
3
  sh "irb -rubygems -I lib -r splitclient-rb.rb"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.0
4
+ version: 4.5.1.pre.dev
5
5
  platform: ruby
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-23 00:00:00.000000000 Z
11
+ date: 2018-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,21 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: webmock
42
+ name: rake-compiler
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - ">="
@@ -67,21 +53,7 @@ dependencies:
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
55
  - !ruby/object:Gem::Dependency
70
- name: byebug
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: pry
56
+ name: rspec
85
57
  requirement: !ruby/object:Gem::Requirement
86
58
  requirements:
87
59
  - - ">="
@@ -95,7 +67,7 @@ dependencies:
95
67
  - !ruby/object:Gem::Version
96
68
  version: '0'
97
69
  - !ruby/object:Gem::Dependency
98
- name: pry-byebug
70
+ name: webmock
99
71
  requirement: !ruby/object:Gem::Requirement
100
72
  requirements:
101
73
  - - ">="
@@ -220,26 +192,13 @@ dependencies:
220
192
  - - ">="
221
193
  - !ruby/object:Gem::Version
222
194
  version: '3.2'
223
- - !ruby/object:Gem::Dependency
224
- name: digest-murmurhash
225
- requirement: !ruby/object:Gem::Requirement
226
- requirements:
227
- - - ">="
228
- - !ruby/object:Gem::Version
229
- version: '1.1'
230
- type: :runtime
231
- prerelease: false
232
- version_requirements: !ruby/object:Gem::Requirement
233
- requirements:
234
- - - ">="
235
- - !ruby/object:Gem::Version
236
- version: '1.1'
237
195
  description: Ruby client for using split SDK.
238
196
  email:
239
197
  - pato@split.io
240
198
  executables:
241
199
  - splitio
242
- extensions: []
200
+ extensions:
201
+ - ext/murmurhash/extconf.rb
243
202
  extra_rdoc_files: []
244
203
  files:
245
204
  - ".gitignore"
@@ -250,8 +209,14 @@ files:
250
209
  - NEWS
251
210
  - README.md
252
211
  - Rakefile
253
- - console
254
212
  - exe/splitio
213
+ - ext/murmurhash/3_x86_32.c
214
+ - ext/murmurhash/extconf.rb
215
+ - ext/murmurhash/murmurhash.c
216
+ - ext/murmurhash/murmurhash.h
217
+ - lib/murmurhash/base.rb
218
+ - lib/murmurhash/murmurhash.jar
219
+ - lib/murmurhash/murmurhash_mri.rb
255
220
  - lib/splitclient-rb.rb
256
221
  - lib/splitclient-rb/cache/adapters/memory_adapter.rb
257
222
  - lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb
@@ -328,12 +293,10 @@ files:
328
293
  - lib/splitclient-rb/split_factory_builder.rb
329
294
  - lib/splitclient-rb/utilitites.rb
330
295
  - lib/splitclient-rb/version.rb
331
- - runTests
332
296
  - splitclient-rb.gemspec
333
297
  - splitio.yml.example
334
298
  - tasks/benchmark_get_treatment.rake
335
- - tasks/benchmark_hashing_algorithm.rake
336
- - tasks/console.rake
299
+ - tasks/irb.rake
337
300
  - tasks/rspec.rake
338
301
  homepage: https://github.com/splitio/ruby-client
339
302
  licenses:
@@ -350,12 +313,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
350
313
  version: '0'
351
314
  required_rubygems_version: !ruby/object:Gem::Requirement
352
315
  requirements:
353
- - - ">="
316
+ - - ">"
354
317
  - !ruby/object:Gem::Version
355
- version: '0'
318
+ version: 1.3.1
356
319
  requirements: []
357
320
  rubyforge_project:
358
- rubygems_version: 2.5.1
321
+ rubygems_version: 2.6.8
359
322
  signing_key:
360
323
  specification_version: 4
361
324
  summary: Ruby client for split SDK.
data/console DELETED
@@ -1,2 +0,0 @@
1
- #!/bin/bash
2
- bundle exec rake console
data/runTests DELETED
@@ -1,2 +0,0 @@
1
- #!/bin/bash
2
- SPLITCLIENT_ENV=test bundle exec rspec spec
@@ -1,51 +0,0 @@
1
- require 'benchmark'
2
- require 'digest/murmurhash'
3
-
4
- desc 'Benchmark murmur32 hashing algorithm'
5
-
6
- task :benchmark_hashing_algorithm do
7
- iterations = 200_000
8
- key = SecureRandom.uuid
9
-
10
- Benchmark.bmbm do |x|
11
- x.report('MurmurHash1') do
12
- iterations.times { Digest::MurmurHash1.rawdigest(key) }
13
- end
14
-
15
- x.report('MurmurHash2') do
16
- iterations.times { Digest::MurmurHash2.rawdigest(key) }
17
- end
18
-
19
- x.report('MurmurHash2A') do
20
- iterations.times { Digest::MurmurHash2A.rawdigest(key) }
21
- end
22
-
23
- x.report('LegacyHash') do
24
- iterations.times { legacy_hash(key, 123) }
25
- end
26
- end
27
- end
28
-
29
- def legacy_hash(key, seed)
30
- h = 0
31
- for i in 0..key.length-1
32
- h = to_int32(31 * h + key[i].ord)
33
- end
34
- h^seed
35
- end
36
-
37
- def to_int32(number)
38
- begin
39
- sign = number < 0 ? -1 : 1
40
- abs = number.abs
41
- return 0 if abs == 0 || abs == Float::INFINITY
42
- rescue
43
- return 0
44
- end
45
-
46
- pos_int = sign * abs.floor
47
- int_32bit = pos_int % 2**32
48
-
49
- return int_32bit - 2**32 if int_32bit >= 2**31
50
- int_32bit
51
- end