json-bloomfilter 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +9 -1
- data/Gemfile.lock +3 -1
- data/README.md +3 -2
- data/Rakefile +11 -4
- data/coffee/bitarray.coffee +8 -4
- data/js/json-bloomfilter.min.js +1 -1
- data/json-bloomfilter.gemspec +2 -0
- data/lib/json/bloomfilter.rb +2 -2
- data/lib/json/bloomfilter/version.rb +1 -1
- data/pkg/json-bloomfilter-0.1.0.gem +0 -0
- data/spec/javascripts/bitarray_spec.js +1 -1
- data/spec/javascripts/bloomfilter_spec.js +0 -1
- data/spec/json/bloomfilter/bitarray_spec.rb +5 -5
- data/spec/json/bloomfilter_spec.rb +1 -1
- metadata +19 -2
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
json-bloomfilter (0.1.
|
4
|
+
json-bloomfilter (0.1.1)
|
5
|
+
json
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: http://rubygems.org/
|
@@ -28,6 +29,7 @@ GEM
|
|
28
29
|
rspec (>= 1.3.1)
|
29
30
|
selenium-webdriver (>= 0.1.3)
|
30
31
|
jasmine-core (1.3.1)
|
32
|
+
json (1.7.6)
|
31
33
|
libv8 (3.11.8.13)
|
32
34
|
libwebsocket (0.1.7.1)
|
33
35
|
addressable
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Serialisable (JSON) Bloom Filter
|
2
2
|
|
3
|
-
[![Build Status](https://travis-ci.org/cbetta/json-bloomfilter.png?branch=master)](https://travis-ci.org/cbetta/json-bloomfilter)
|
3
|
+
[![Build Status](https://travis-ci.org/cbetta/json-bloomfilter.png?branch=master)](https://travis-ci.org/cbetta/json-bloomfilter) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/cbetta/json-bloomfilter)
|
4
4
|
|
5
5
|
A bloom filter implementation that is serialisable to JSON and compatible between both Ruby and Javascript. Very useful when needing to train a bloom filter in one language and using it in the other.
|
6
6
|
|
@@ -114,7 +114,8 @@ Additionally you can pass along:
|
|
114
114
|
|
115
115
|
## Release notes
|
116
116
|
|
117
|
-
* **0.1.
|
117
|
+
* **0.1.1** Fixes a JS integer overflow issue and makes Ruby 1.8.7 compatible
|
118
|
+
* **0.1.0** Adds travis-ci. Bumped minor release version
|
118
119
|
* **0.0.6** Adds a factory that takes a size + error rate
|
119
120
|
* **0.0.5** Adds installer of JS file
|
120
121
|
* **0.0.4** Adds JS tests
|
data/Rakefile
CHANGED
@@ -8,6 +8,13 @@ task :test do
|
|
8
8
|
sh "bundle exec rspec spec"
|
9
9
|
end
|
10
10
|
|
11
|
+
task :travis do
|
12
|
+
["rake test", "rake jasmine:ci"].each do |cmd|
|
13
|
+
puts "Starting to run #{cmd}..."
|
14
|
+
system("export DISPLAY=:99.0 && bundle exec #{cmd}")
|
15
|
+
raise "#{cmd} failed!" unless $?.exitstatus == 0
|
16
|
+
end
|
17
|
+
end
|
11
18
|
|
12
19
|
desc "Autobuild JS/SCSS"
|
13
20
|
task :watch do
|
@@ -17,12 +24,12 @@ task :watch do
|
|
17
24
|
monitor = FSSM::Monitor.new
|
18
25
|
|
19
26
|
monitor.path "coffee", "**/*.coffee" do
|
20
|
-
compile_block =
|
27
|
+
compile_block = lambda do |basename, filename|
|
21
28
|
puts "Compiling coffee to minified js..."
|
22
29
|
coffee_file = "coffee/#{filename}"
|
23
30
|
puts "\t#{coffee_file}"
|
24
|
-
Rake::Task["js:
|
25
|
-
Rake::Task["js:
|
31
|
+
Rake::Task["js:compile_cs"].tap(&:reenable).invoke
|
32
|
+
Rake::Task["js:minify_js"].tap(&:reenable).invoke
|
26
33
|
end
|
27
34
|
|
28
35
|
update &compile_block
|
@@ -59,7 +66,7 @@ namespace :js do
|
|
59
66
|
FileUtils.mkdir_p(directory_name) unless File.exists? directory_name
|
60
67
|
puts "\t\t->#{js_file}"
|
61
68
|
File.open(js_file, "w+") do |f|
|
62
|
-
f.print CoffeeScript.compile(coffee_script, no_wrap
|
69
|
+
f.print CoffeeScript.compile(coffee_script, :no_wrap => true)
|
63
70
|
end
|
64
71
|
end
|
65
72
|
|
data/coffee/bitarray.coffee
CHANGED
@@ -21,16 +21,16 @@ JsonBloomfilter.BitArray.prototype.set = (position, value) ->
|
|
21
21
|
aPos = @arrayPosition(position)
|
22
22
|
bChange = @bitChange(position)
|
23
23
|
if value == 1
|
24
|
-
@field[aPos]
|
24
|
+
@field[aPos] = @abs(@field[aPos] | bChange)
|
25
25
|
else if (@field[aPos] & bChange) != 0
|
26
|
-
@field[aPos]
|
26
|
+
@field[aPos] = @abs(@field[aPos] ^ bChange)
|
27
27
|
true
|
28
28
|
|
29
29
|
JsonBloomfilter.BitArray.prototype.get = (position) ->
|
30
30
|
throw new Error("BitArray index out of bounds") if position >= @size
|
31
31
|
aPos = @arrayPosition(position)
|
32
32
|
bChange = @bitChange(position)
|
33
|
-
if (@field[aPos] & bChange) > 0
|
33
|
+
if @abs(@field[aPos] & bChange) > 0
|
34
34
|
return 1
|
35
35
|
else
|
36
36
|
return 0
|
@@ -39,7 +39,11 @@ JsonBloomfilter.BitArray.prototype.arrayPosition = (position) ->
|
|
39
39
|
Math.floor(position / @ELEMENT_WIDTH)
|
40
40
|
|
41
41
|
JsonBloomfilter.BitArray.prototype.bitChange = (position) ->
|
42
|
-
|
42
|
+
@abs(1 << position % @ELEMENT_WIDTH)
|
43
|
+
|
44
|
+
JsonBloomfilter.BitArray.prototype.abs = (val) ->
|
45
|
+
val += 4294967295 if val < 0
|
46
|
+
val
|
43
47
|
|
44
48
|
JsonBloomfilter.BitArray.prototype.toString = ->
|
45
49
|
output = ""
|
data/js/json-bloomfilter.min.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
var JsonBloomfilter;JsonBloomfilter=function(options){var key,value;if(options==null){options={}}this.options={size:100,hashes:4,seed:new Date().getTime()/1000,bits:null};for(key in options){value=options[key];this.options[key]=value}this.bits=new JsonBloomfilter.BitArray(this.options.size,this.options.bits);return this};JsonBloomfilter.build=function(capacity,error_rate){var hashes,size;size=Math.ceil(capacity*Math.log(error_rate)/Math.log(1/Math.pow(2,Math.log(2))));hashes=Math.round(Math.log(2)*size/capacity);return new JsonBloomfilter({size:size,hashes:hashes})};JsonBloomfilter.prototype.add=function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];this.bits.add(index)}};JsonBloomfilter.prototype.test=function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];if(this.bits.get(index)===0){return false}}return true};JsonBloomfilter.prototype.clear=function(){this.bits=new JsonBloomfilter.BitArray(this.options.size)};JsonBloomfilter.prototype.toHash=function(){var hash,key,value,_ref;hash={};_ref=this.options;for(key in _ref){value=_ref[key];hash[key]=value}hash.bits=this.bits.field;return hash};JsonBloomfilter.prototype.toJson=function(){return JSON.stringify(this.toHash())};JsonBloomfilter.prototype.indexesFor=function(key){var index,indexes,_i,_ref;indexes=[];for(index=_i=0,_ref=this.options.hashes-1;0<=_ref?_i<=_ref:_i>=_ref;index=0<=_ref?++_i:--_i){indexes.push(JsonBloomfilter.Zlib.crc32(""+key+":"+(index+this.options.seed))%this.options.size)}return indexes};JsonBloomfilter.BitArray=function(size,field){var arrayLength,i,_i,_ref;if(field==null){field=null}if(!size){throw new Error("Missing argument: size")}this.ELEMENT_WIDTH=32;this.size=size;this.field=field||[];arrayLength=Math.floor(((size-1)/this.ELEMENT_WIDTH)+1);if(!field){for(i=_i=0,_ref=arrayLength-1;0<=_ref?_i<=_ref:_i>=_ref;i=0<=_ref?++_i:--_i){this.field[i]=0}}return this};JsonBloomfilter.BitArray.prototype.add=function(position){return this.set(position,1)};JsonBloomfilter.BitArray.prototype.remove=function(position){return this.set(position,0)};JsonBloomfilter.BitArray.prototype.set=function(position,value){var aPos,bChange;if(position>=this.size){throw new Error("BitArray index out of bounds")}aPos=this.arrayPosition(position);bChange=this.bitChange(position);if(value===1){this.field[aPos]
|
1
|
+
var JsonBloomfilter;JsonBloomfilter=function(options){var key,value;if(options==null){options={}}this.options={size:100,hashes:4,seed:new Date().getTime()/1000,bits:null};for(key in options){value=options[key];this.options[key]=value}this.bits=new JsonBloomfilter.BitArray(this.options.size,this.options.bits);return this};JsonBloomfilter.build=function(capacity,error_rate){var hashes,size;size=Math.ceil(capacity*Math.log(error_rate)/Math.log(1/Math.pow(2,Math.log(2))));hashes=Math.round(Math.log(2)*size/capacity);return new JsonBloomfilter({size:size,hashes:hashes})};JsonBloomfilter.prototype.add=function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];this.bits.add(index)}};JsonBloomfilter.prototype.test=function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];if(this.bits.get(index)===0){return false}}return true};JsonBloomfilter.prototype.clear=function(){this.bits=new JsonBloomfilter.BitArray(this.options.size)};JsonBloomfilter.prototype.toHash=function(){var hash,key,value,_ref;hash={};_ref=this.options;for(key in _ref){value=_ref[key];hash[key]=value}hash.bits=this.bits.field;return hash};JsonBloomfilter.prototype.toJson=function(){return JSON.stringify(this.toHash())};JsonBloomfilter.prototype.indexesFor=function(key){var index,indexes,_i,_ref;indexes=[];for(index=_i=0,_ref=this.options.hashes-1;0<=_ref?_i<=_ref:_i>=_ref;index=0<=_ref?++_i:--_i){indexes.push(JsonBloomfilter.Zlib.crc32(""+key+":"+(index+this.options.seed))%this.options.size)}return indexes};JsonBloomfilter.BitArray=function(size,field){var arrayLength,i,_i,_ref;if(field==null){field=null}if(!size){throw new Error("Missing argument: size")}this.ELEMENT_WIDTH=32;this.size=size;this.field=field||[];arrayLength=Math.floor(((size-1)/this.ELEMENT_WIDTH)+1);if(!field){for(i=_i=0,_ref=arrayLength-1;0<=_ref?_i<=_ref:_i>=_ref;i=0<=_ref?++_i:--_i){this.field[i]=0}}return this};JsonBloomfilter.BitArray.prototype.add=function(position){return this.set(position,1)};JsonBloomfilter.BitArray.prototype.remove=function(position){return this.set(position,0)};JsonBloomfilter.BitArray.prototype.set=function(position,value){var aPos,bChange;if(position>=this.size){throw new Error("BitArray index out of bounds")}aPos=this.arrayPosition(position);bChange=this.bitChange(position);if(value===1){this.field[aPos]=this.abs(this.field[aPos]|bChange)}else{if((this.field[aPos]&bChange)!==0){this.field[aPos]=this.abs(this.field[aPos]^bChange)}}return true};JsonBloomfilter.BitArray.prototype.get=function(position){var aPos,bChange;if(position>=this.size){throw new Error("BitArray index out of bounds")}aPos=this.arrayPosition(position);bChange=this.bitChange(position);if(this.abs(this.field[aPos]&bChange)>0){return 1}else{return 0}};JsonBloomfilter.BitArray.prototype.arrayPosition=function(position){return Math.floor(position/this.ELEMENT_WIDTH)};JsonBloomfilter.BitArray.prototype.bitChange=function(position){return this.abs(1<<position%this.ELEMENT_WIDTH)};JsonBloomfilter.BitArray.prototype.abs=function(val){if(val<0){val+=4294967295}return val};JsonBloomfilter.BitArray.prototype.toString=function(){var i,output,_i,_ref;output="";for(i=_i=0,_ref=this.size-1;0<=_ref?_i<=_ref:_i>=_ref;i=0<=_ref?++_i:--_i){output+=this.get(i)}return output};JsonBloomfilter.Zlib={CRC32_TABLE:new Array(0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918000,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117),crc32:function(string){var bytes,crc,i,iTop,n;bytes=this.bytesFor(string);crc=0;n=0;crc=crc^(-1);i=0;iTop=bytes.length;while(i<iTop){n=(crc^bytes[i])&255;crc=(crc>>>8)^this.CRC32_TABLE[n];i++}crc=crc^(-1);if(crc<0){crc+=4294967296}return crc},bytesFor:function(string){var bytes,i;bytes=[];i=0;while(i<string.length){bytes.push(string.charCodeAt(i));++i}return bytes}};
|
data/json-bloomfilter.gemspec
CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
+
s.add_dependency 'json'
|
22
|
+
|
21
23
|
s.add_development_dependency 'rspec'
|
22
24
|
s.add_development_dependency 'yui-compressor'
|
23
25
|
s.add_development_dependency 'therubyracer'
|
data/lib/json/bloomfilter.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require "json/bloomfilter/bitarray"
|
2
2
|
require "json"
|
3
3
|
|
4
4
|
class JsonBloomfilter
|
@@ -7,7 +7,7 @@ class JsonBloomfilter
|
|
7
7
|
def self.build capacity, error_rate
|
8
8
|
size = (capacity * Math.log(error_rate) / Math.log(1.0 / 2**Math.log(2))).ceil
|
9
9
|
hashes = (Math.log(2) * size / capacity).round
|
10
|
-
JsonBloomfilter.new size
|
10
|
+
JsonBloomfilter.new :size => size, :hashes => hashes
|
11
11
|
end
|
12
12
|
|
13
13
|
def initialize options = {}
|
Binary file
|
@@ -11,7 +11,7 @@ describe("JsonBloomfilter.BitArray", function() {
|
|
11
11
|
expect(ba.field).toBe(field);
|
12
12
|
});
|
13
13
|
|
14
|
-
it("should create the right size field"
|
14
|
+
it("should create the right size field", function() {
|
15
15
|
ba = new JsonBloomfilter.BitArray(100);
|
16
16
|
expect(ba.field.length).toBe(4);
|
17
17
|
});
|
@@ -4,8 +4,8 @@ describe JsonBloomfilter::BitArray do
|
|
4
4
|
|
5
5
|
describe "#initialize" do
|
6
6
|
it "should require a size" do
|
7
|
-
expect(
|
8
|
-
expect(
|
7
|
+
expect(lambda{JsonBloomfilter::BitArray.new}).to raise_error(ArgumentError)
|
8
|
+
expect(lambda{JsonBloomfilter::BitArray.new(100)}).not_to raise_error(ArgumentError)
|
9
9
|
end
|
10
10
|
it "should take an optional bit field" do
|
11
11
|
field = [0,0,0,2]
|
@@ -23,7 +23,7 @@ describe JsonBloomfilter::BitArray do
|
|
23
23
|
|
24
24
|
it "should throw an error on out of bound" do
|
25
25
|
ba = JsonBloomfilter::BitArray.new(10)
|
26
|
-
expect(
|
26
|
+
expect(lambda{ba.add(10)}).to raise_error
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -37,7 +37,7 @@ describe JsonBloomfilter::BitArray do
|
|
37
37
|
|
38
38
|
it "should throw an error on out of bound" do
|
39
39
|
ba = JsonBloomfilter::BitArray.new(10)
|
40
|
-
expect(
|
40
|
+
expect(lambda{ba.remove(10)}).to raise_error
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -51,7 +51,7 @@ describe JsonBloomfilter::BitArray do
|
|
51
51
|
|
52
52
|
it "should throw an error on out of bound" do
|
53
53
|
ba = JsonBloomfilter::BitArray.new(10)
|
54
|
-
expect(
|
54
|
+
expect(lambda{ba.get(10)}).to raise_error
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -13,7 +13,7 @@ describe JsonBloomfilter do
|
|
13
13
|
describe "#initialize" do
|
14
14
|
it "should take the appropriate options" do
|
15
15
|
seed = Time.now.to_i - 24*60*60
|
16
|
-
bf = JsonBloomfilter.new size
|
16
|
+
bf = JsonBloomfilter.new :size => 200, :hashes => 10, :seed => seed
|
17
17
|
expect(bf.to_hash["size"]).to be == 200
|
18
18
|
expect(bf.to_hash["hashes"]).to be == 10
|
19
19
|
expect(bf.to_hash["seed"]).to be == seed
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-bloomfilter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,6 +11,22 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2013-01-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rspec
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,6 +172,7 @@ files:
|
|
156
172
|
- pkg/json-bloomfilter-0.0.4.gem
|
157
173
|
- pkg/json-bloomfilter-0.0.5.gem
|
158
174
|
- pkg/json-bloomfilter-0.0.6.gem
|
175
|
+
- pkg/json-bloomfilter-0.1.0.gem
|
159
176
|
- spec/javascripts/bitarray_spec.js
|
160
177
|
- spec/javascripts/bloomfilter_spec.js
|
161
178
|
- spec/javascripts/support/jasmine.yml
|
@@ -184,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
201
|
version: '0'
|
185
202
|
segments:
|
186
203
|
- 0
|
187
|
-
hash:
|
204
|
+
hash: 2685704013220459587
|
188
205
|
requirements: []
|
189
206
|
rubyforge_project:
|
190
207
|
rubygems_version: 1.8.24
|