bloomfilter-rb-without-native 2.1.3

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea07d8c1212349fce6e2a2c7871ebac290026c76
4
+ data.tar.gz: c4b9d7ae7b93d0ea8f1d1ee6de5046869f69505b
5
+ SHA512:
6
+ metadata.gz: c40a4cda2246babd8e84a3727117833282fac07c24f2339a6dff3da71b77f0d73962ec6a5fc785909fa4a692a6249a310147f530f7c82188cd66eba4222e8335
7
+ data.tar.gz: 97172d03be304c79160a1754320151130606b4dd848973ebd6a9d91d563d7fa72781e309696815211466ec5dffe1c09fec05ad11c1f3b0d1e33b2b0e20c850f1
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.o
2
+ *.bundle
3
+ *.swp
4
+ .rvmrc
5
+ .DS_Store
6
+ ext/Makefile
7
+ lib/cbloomfilter.so
8
+ tmp
9
+ Gemfile.lock
10
+ pkg
data/.rspec ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ THIS IS A FORK OF https://github.com/igrigorik/bloomfilter-rb
2
+
3
+ # BloomFilter(s) in Ruby
4
+
5
+ - Redis-backed getbit/setbit non-counting bloom filter
6
+ - Redis-backed set-based counting (+TTL) bloom filter
7
+
8
+ Bloom filter is a space-efficient probabilistic data structure that is used to test whether an element is a member of a set. False positives are possible, but false negatives are not. For more detail, check the [wikipedia article](http://en.wikipedia.org/wiki/Bloom_filter). Instead of using k different hash functions, this implementation seeds the CRC32 hash with k different initial values (0, 1, ..., k-1). This may or may not give you a good distribution, it all depends on the data.
9
+
10
+ Performance of the Bloom filter depends on a number of variables:
11
+
12
+ - size of the bit array
13
+ - size of the counter bucket
14
+ - number of hash functions
15
+
16
+ ## Resources
17
+
18
+ - Determining parameters: [Scalable Datasets: Bloom Filters in Ruby](http://www.igvita.com/2008/12/27/scalable-datasets-bloom-filters-in-ruby/)
19
+ - Applications & reasons behind bloom filter: [Flow analysis: Time based bloom filter](http://www.igvita.com/2010/01/06/flow-analysis-time-based-bloom-filters/)
20
+
21
+ ***
22
+
23
+ ## Redis-backed setbit/getbit bloom filter
24
+
25
+ Uses [getbit](http://redis.io/commands/getbit)/[setbit](http://redis.io/commands/setbit) on Redis strings - efficient, fast, can be shared by multiple/concurrent processes.
26
+
27
+ ```ruby
28
+ bf = BloomFilter::Redis.new
29
+
30
+ bf.insert('test')
31
+ bf.include?('test') # => true
32
+ bf.include?('blah') # => false
33
+
34
+ bf.delete('test')
35
+ bf.include?('test') # => false
36
+ ```
37
+
38
+ ### Memory footprint
39
+
40
+ - 1.0% error rate for 1M items, 10 bits/item: *2.5 mb*
41
+ - 1.0% error rate for 150M items, 10 bits per item: *358.52 mb*
42
+ - 0.1% error rate for 150M items, 15 bits per item: *537.33 mb*
43
+
44
+ ***
45
+
46
+ ## Redis-backed counting bloom filter with TTL's
47
+ Uses regular Redis get/set counters to implement a counting filter with optional TTL expiry. Because each "bit" requires its own key in Redis, you do incur a much larger memory overhead.
48
+
49
+ ```ruby
50
+ bf = BloomFilter::CountingRedis.new(:ttl => 2)
51
+
52
+ bf.insert('test')
53
+ bf.include?('test') # => true
54
+
55
+ sleep(2)
56
+ bf.include?('test') # => false
57
+ ```
58
+
59
+ ## Credits
60
+
61
+ Tatsuya Mori <valdzone@gmail.com> (Original C implementation: http://vald.x0.com/sb/)
62
+
63
+ ## License
64
+
65
+ MIT License - Copyright (c) 2011 Ilya Grigorik
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+ require 'rspec'
4
+ require 'rspec/core/rake_task'
5
+
6
+ Bundler::GemHelper.install_tasks
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ Rake::Task[:spec].prerequisites << :clean
9
+ Rake::Task[:spec].prerequisites << :compile
@@ -0,0 +1,34 @@
1
+ $:<< 'lib'
2
+
3
+ require 'benchmark'
4
+ require 'bloomfilter-rb'
5
+
6
+ n = 10000
7
+
8
+ Benchmark.bm do |x|
9
+ r = BloomFilter::Redis.new
10
+
11
+ x.report("insert") do
12
+ n.times do
13
+ r.insert("a")
14
+ end
15
+ end
16
+
17
+ x.report("lookup present") do
18
+ n.times do
19
+ r.include?("a")
20
+ end
21
+ end
22
+
23
+ x.report("lookup missing") do
24
+ n.times do
25
+ r.include?("b")
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ # user system total real
32
+ # insert 1.000000 0.380000 1.380000 ( 1.942181)
33
+ # lookup present 1.030000 0.470000 1.500000 ( 2.577577)
34
+ # lookup missing 0.370000 0.160000 0.530000 ( 1.060429)
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "bloomfilter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "bloomfilter-rb-without-native"
7
+ s.version = BloomFilter::VERSION
8
+ s.authors = ["Garrett Thornburg"]
9
+ s.email = ["film42@gmail.com"]
10
+ s.homepage = "https://github.com/film42/bloomfilter-rb-without-native/"
11
+ s.summary = "Counting Bloom Filter implemented in Ruby (fork without native code)"
12
+ s.description = s.summary
13
+
14
+ s.add_dependency "redis"
15
+ s.add_development_dependency "rspec", ">= 3"
16
+ s.add_development_dependency "rake"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bloomfilter'
3
+
4
+ bf = BloomFilter::CountingRedis.new(:ttl => 2, :server => {:host => 'localhost'})
5
+
6
+ bf.insert('test')
7
+ puts bf.include?('test')
8
+
9
+ sleep(3)
10
+ puts bf.include?('test')
11
+
12
+ puts bf.stats
@@ -0,0 +1,52 @@
1
+ #
2
+ # Pure ruby implementation of a Bloom filter, just for kicks
3
+ #
4
+
5
+ require 'bitset'
6
+ require 'zlib'
7
+
8
+ class BloomFilter
9
+
10
+ def initialize(max_entries, num_hashes, seed)
11
+ @num_hashes = num_hashes
12
+ @size = max_entries.to_i
13
+ @bitmap = Bitset.new(@size)
14
+ @__mask = Bitset.new(@size)
15
+ @seed = seed
16
+ end
17
+
18
+ def insert(key)
19
+ mask = make_mask(key)
20
+ @bitmap |= mask
21
+ end
22
+
23
+ def new?(key)
24
+ mask = make_mask(key)
25
+ return ((@bitmap & mask) != mask);
26
+ end
27
+
28
+ def make_mask(key)
29
+ @__mask.clear
30
+ 0.upto(@num_hashes.to_i - 1) do |i|
31
+ hash = Zlib.crc32(key, i + @seed)
32
+ @__mask.set(hash % @size, 1)
33
+ end
34
+ return @__mask
35
+ end
36
+ end
37
+
38
+ def main
39
+ bf = BloomFilter.new(1000000, 4, 0)
40
+ num = 0
41
+ while line = ARGF.gets
42
+ data = line.chop
43
+
44
+ if bf.new?(data)
45
+ num += 1
46
+ bf.insert(data)
47
+ end
48
+ end
49
+ print "#element = #{num}\n"
50
+ end
51
+
52
+ main
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bloomfilter-rb'
3
+
4
+ WORDS = %w(duck penguin bear panda)
5
+ TEST = %w(penguin moose racooon)
6
+
7
+ bf = BloomFilter::Native.new(:size => 100, :hashes => 2, :seed => 1, :bucket => 3, :raise => false)
8
+
9
+ WORDS.each { |w| bf.insert(w) }
10
+ TEST.each do |w|
11
+ puts "#{w}: #{bf.include?(w)}"
12
+ end
13
+
14
+ bf.stats
15
+
16
+ # penguin: true
17
+ # moose: false
18
+ # racooon: false
19
+ #
20
+ # Number of filter buckets (m): 100
21
+ # Number of bits per buckets (b): 1
22
+ # Number of filter elements (n): 4
23
+ # Number of filter hashes (k) : 4
24
+ # Raise on overflow? (r) : false
25
+ # Predicted false positive rate = 0.05%
@@ -0,0 +1,31 @@
1
+ require 'set'
2
+ require 'lib/bloomfilter-rb'
3
+
4
+ items = 1_000_00
5
+ bits = 1
6
+
7
+ # p BloomFilter::Redis.new(:size => items*bits, :hashes => 7) # 2.5 mb
8
+ # p BloomFilter::Redis.new(:size => items*bits*5, :hashes => 7) # 13 mb
9
+ # p BloomFilter::Redis.new(:size => items*bits*30, :hashes => 7) # 73 mb
10
+
11
+ # 1% error rate for 5M items/day, 10 bits per item, for 30 days of data: 358.52 mb
12
+ # 0.1% error rate for 5M items/day, 15 bits per item, for 30 days of data: 537.33 mb
13
+
14
+ bf = BloomFilter::Redis.new(:size => items*bits, :hashes => 7) # 2.5 mb
15
+
16
+ seen = Set.new
17
+ err = 0
18
+ num = 100000
19
+
20
+ num.times do
21
+ item = rand(items)
22
+
23
+ if bf.include?(item) != seen.include?(item)
24
+ err += 1
25
+ end
26
+
27
+ seen << item
28
+ bf.insert(item)
29
+ end
30
+
31
+ p [:error_rate, (err.to_f / num) * 100]
@@ -0,0 +1,7 @@
1
+ require 'redis'
2
+ require 'zlib'
3
+
4
+ require 'bloomfilter/filter'
5
+ require 'bloomfilter/counting_redis'
6
+ require 'bloomfilter/redis'
7
+ require 'bloomfilter/version'
@@ -0,0 +1,7 @@
1
+ require 'redis'
2
+ require 'zlib'
3
+
4
+ require 'bloomfilter/filter'
5
+ require 'bloomfilter/counting_redis'
6
+ require 'bloomfilter/redis'
7
+ require 'bloomfilter/version'
@@ -0,0 +1 @@
1
+ require 'bloomfilter-rb-without-native'
@@ -0,0 +1,64 @@
1
+ module BloomFilter
2
+ class CountingRedis < Filter
3
+
4
+ def initialize(opts = {})
5
+ @opts = {
6
+ :identifier => 'rbloom',
7
+ :size => 100,
8
+ :hashes => 4,
9
+ :seed => Time.now.to_i,
10
+ :bucket => 3,
11
+ :ttl => false,
12
+ :server => {}
13
+ }.merge opts
14
+ @db = @opts.delete(:db) || ::Redis.new(@opts[:server])
15
+ end
16
+
17
+ def insert(key, ttl=nil)
18
+ ttl = @opts[:ttl] if ttl.nil?
19
+
20
+ indexes_for(key).each do |idx|
21
+ @db.incr idx
22
+ @db.expire(idx, ttl) if ttl
23
+ end
24
+ end
25
+ alias :[]= :insert
26
+
27
+ def delete(key)
28
+ indexes_for(key).each do |idx|
29
+ count = @db.decr(idx).to_i
30
+ if count <= 0
31
+ @db.del(idx)
32
+ @db.setbit(idx, 0) if count < 0
33
+ end
34
+ end
35
+ end
36
+
37
+ def include?(*keys)
38
+ indexes = keys.collect { |key| indexes_for(key) }
39
+ not @db.mget(*indexes.flatten).include? nil
40
+ end
41
+ alias :key? :include?
42
+
43
+ def num_set
44
+ @db.eval("return #redis.call('keys', '#{@opts[:identifier]}:*')")
45
+ end
46
+ alias :size :num_set
47
+
48
+ def clear
49
+ @db.flushdb
50
+ end
51
+
52
+ private
53
+
54
+ # compute index offsets for provided key
55
+ def indexes_for(key)
56
+ indexes = []
57
+ @opts[:hashes].times do |i|
58
+ indexes.push @opts[:identifier] + ":" + (Zlib.crc32("#{key}:#{i+@opts[:seed]}") % @opts[:size]).to_s
59
+ end
60
+
61
+ indexes
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,13 @@
1
+ module BloomFilter
2
+ class Filter
3
+ def stats
4
+ fp = ((1.0 - Math.exp(-(@opts[:hashes] * size).to_f / @opts[:size])) ** @opts[:hashes]) * 100
5
+ printf "Number of filter buckets (m): %d\n" % @opts[:size]
6
+ printf "Number of bits per buckets (b): %d\n" % @opts[:bucket]
7
+ printf "Number of filter elements (n): %d\n" % size
8
+ printf "Number of filter hashes (k) : %d\n" % @opts[:hashes]
9
+ printf "Raise on overflow? (r) : %s\n" % @opts[:raise].to_s
10
+ printf "Predicted false positive rate = %.2f%\n" % fp
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,76 @@
1
+ module BloomFilter
2
+ class Redis < Filter
3
+
4
+ def initialize(opts = {})
5
+ @opts = {
6
+ :size => 100,
7
+ :hashes => 4,
8
+ :seed => Time.now.to_i,
9
+ :namespace => 'redis',
10
+ :eager => false,
11
+ :server => {}
12
+ }.merge opts
13
+ @db = @opts.delete(:db) || ::Redis.new(@opts[:server])
14
+
15
+ if @opts[:eager]
16
+ @db.setbit @opts[:namespace], @opts[:size]+1, 1
17
+ end
18
+ end
19
+
20
+ def insert(key, ttl=nil)
21
+ @db.pipelined do
22
+ indexes_for(key) { |idx| @db.setbit @opts[:namespace], idx, 1 }
23
+ end
24
+ end
25
+ alias :[]= :insert
26
+
27
+ def include?(*keys)
28
+ keys.each do |key|
29
+ indexes = []
30
+ indexes_for(key) { |idx| indexes << idx }
31
+
32
+ return false if @db.getbit(@opts[:namespace], indexes.shift) == 0
33
+
34
+ result = @db.pipelined do
35
+ indexes.each do |idx|
36
+ @db.getbit(@opts[:namespace], idx)
37
+ end
38
+ end
39
+
40
+ return false if result.include?(0)
41
+ end
42
+
43
+ true
44
+ end
45
+ alias :key? :include?
46
+
47
+ def delete(key)
48
+ warn "Deletes are disabled on non-counting filter, see: https://github.com/igrigorik/bloomfilter-rb/issues/37. This method will be deprecated in a future release."
49
+ end
50
+
51
+ def clear
52
+ @db.set @opts[:namespace], 0
53
+ end
54
+
55
+ def num_set
56
+ @db.strlen @opts[:namespace]
57
+ end
58
+ alias :size :num_set
59
+
60
+ def stats
61
+ printf "Number of filter buckets (m): %d\n" % @opts[:size]
62
+ printf "Number of filter hashes (k) : %d\n" % @opts[:hashes]
63
+ end
64
+
65
+ private
66
+
67
+ # compute index offsets for provided key
68
+ def indexes_for(key)
69
+ indexes = []
70
+ @opts[:hashes].times do |i|
71
+ yield Zlib.crc32("#{key}:#{i+@opts[:seed]}") % @opts[:size]
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,3 @@
1
+ module BloomFilter
2
+ VERSION = "2.1.3"
3
+ end
@@ -0,0 +1,61 @@
1
+ require 'helper'
2
+
3
+ describe BloomFilter::CountingRedis do
4
+
5
+ it "should connect to remote redis server" do
6
+ expect { BloomFilter::CountingRedis.new }.not_to raise_error
7
+ end
8
+
9
+ it "should allow redis client instance to be passed in" do
10
+ redis_client = double("Redis")
11
+ bf = BloomFilter::CountingRedis.new(:db => redis_client)
12
+ expect(bf.instance_variable_get(:@db)).to be(redis_client)
13
+ end
14
+
15
+ context "a default CountingRedis instance" do
16
+ before do
17
+ # clear all redis databases
18
+ subject.instance_variable_get(:@db).flushall
19
+ end
20
+
21
+ it "should store data in Redis" do
22
+ subject.insert(:abcd)
23
+ subject.insert('test')
24
+
25
+ expect(subject.include?('test')).to be true
26
+ expect(subject.key?('test')).to be true
27
+
28
+ expect(subject.include?('test', 'test2')).to be false
29
+ expect(subject.include?('test', 'abcd')).to be true
30
+ expect(subject.include?('test', 'abcd', 'nada')).to be false
31
+ end
32
+
33
+ it "should delete keys from Redis" do
34
+ subject.insert('test')
35
+ expect(subject.include?('test')).to be true
36
+
37
+ subject.delete('test')
38
+ expect(subject.include?('test')).to be false
39
+ end
40
+
41
+ it "should output current stats" do
42
+ subject.insert('test')
43
+ expect(subject.size).to eq(4)
44
+ expect { subject.stats }.not_to raise_error
45
+ end
46
+ end
47
+
48
+ context "a TTL 1 instance" do
49
+ subject { BloomFilter::CountingRedis.new(:ttl => 1) }
50
+
51
+ it "should accept a TTL value for a key" do
52
+ subject.instance_variable_get(:@db).flushall
53
+
54
+ subject.insert('test')
55
+ expect(subject.include?('test')).to be true
56
+
57
+ sleep(2)
58
+ expect(subject.include?('test')).to be false
59
+ end
60
+ end
61
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/setup'
2
+ require 'bloomfilter-rb'
@@ -0,0 +1,62 @@
1
+ require 'helper'
2
+
3
+ describe BloomFilter::Redis do
4
+
5
+ context "use Redis bitstring for storage" do
6
+ before do
7
+ # clear all redis databases
8
+ subject.instance_variable_get(:@db).flushall
9
+ end
10
+
11
+ it "should store data in Redis" do
12
+ subject.insert(:abcd)
13
+ subject.insert('test')
14
+ expect(subject.include?('test')).to be true
15
+ expect(subject.key?('test')).to be true
16
+
17
+ expect(subject.include?('test', 'test2')).to be false
18
+ expect(subject.include?('test', 'abcd')).to be true
19
+ end
20
+
21
+ it "should not delete keys from Redis" do
22
+ subject.insert('test')
23
+ expect(subject.include?('test')).to be true
24
+
25
+ subject.delete('test')
26
+ expect(subject.include?('test')).to be true
27
+ end
28
+
29
+ it "should clear Redis filter" do
30
+ subject.insert('test')
31
+ expect(subject.include?('test')).to be true
32
+
33
+ subject.clear
34
+ expect(subject.include?('test')).to be false
35
+ end
36
+
37
+ it "should output current stats" do
38
+ subject.clear
39
+ subject.insert('test')
40
+ expect { subject.stats }.not_to raise_error
41
+ end
42
+
43
+ it "should connect to remote redis server" do
44
+ expect { BloomFilter::Redis.new }.not_to raise_error
45
+ end
46
+
47
+ it "should allow redis client instance to be passed in" do
48
+ redis_client = double("Redis")
49
+ bf = BloomFilter::Redis.new(:db => redis_client)
50
+ expect(bf.instance_variable_get(:@db)).to be redis_client
51
+ end
52
+
53
+ it "should allow namespaced BloomFilters" do
54
+ bf1 = BloomFilter::Redis.new(:namespace => :a)
55
+ bf2 = BloomFilter::Redis.new(:namespace => :b)
56
+
57
+ bf1.insert('test')
58
+ expect(bf1.include?('test')).to be true
59
+ expect(bf2.include?('test')).to be false
60
+ end
61
+ end
62
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bloomfilter-rb-without-native
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Garrett Thornburg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ name: redis
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '3'
33
+ name: rspec
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '3'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: rake
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Counting Bloom Filter implemented in Ruby (fork without native code)
56
+ email:
57
+ - film42@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - Gemfile
65
+ - README.md
66
+ - Rakefile
67
+ - benchmark/redis-bm.rb
68
+ - bloomfilter-rb-without-native.gemspec
69
+ - examples/counting-redis.rb
70
+ - examples/pure-ruby-bf.rb
71
+ - examples/simple-native.rb
72
+ - examples/simple-redis.rb
73
+ - lib/bloomfilter-rb-without-native.rb
74
+ - lib/bloomfilter-rb.rb
75
+ - lib/bloomfilter.rb
76
+ - lib/bloomfilter/counting_redis.rb
77
+ - lib/bloomfilter/filter.rb
78
+ - lib/bloomfilter/redis.rb
79
+ - lib/bloomfilter/version.rb
80
+ - spec/counting_redis_spec.rb
81
+ - spec/helper.rb
82
+ - spec/redis_spec.rb
83
+ homepage: https://github.com/film42/bloomfilter-rb-without-native/
84
+ licenses: []
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.2.2
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Counting Bloom Filter implemented in Ruby (fork without native code)
106
+ test_files:
107
+ - spec/counting_redis_spec.rb
108
+ - spec/helper.rb
109
+ - spec/redis_spec.rb