redis-file 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e596eb446bbf827dad2d9251d6802817d9b3763f
4
+ data.tar.gz: 5491961a1adce14639bc37f9acaeae6b6ebece98
5
+ SHA512:
6
+ metadata.gz: 787696710e82958c2a07a55fdb2b81973f2260d045ffe8277cc6afde71f2e92eef378ee388e9d76f1450e5fb8c4c87664dc2677d0b983382992d0fecd9562dc6
7
+ data.tar.gz: 8104ba9421bf5a7bbd58368bc98a75e8c152a03308194ac2c767f7092bfcfdaa69246c0b05b47d87551fdc33c8a433f3b8079f697f123f5f893f500a38776171
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ *.rbc
7
+ db.redis
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -b -fn --color
@@ -0,0 +1,8 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - ree
7
+ - jruby
8
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rake'
4
+ gem 'rdoc'
5
+
6
+ # Specify your gem's dependencies in redis-file.gemspec
7
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2013 Daniel Loureiro
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,86 @@
1
+ # redis-file [![Build Status](https://secure.travis-ci.org/loureirorg/redis-file.png)](http://travis-ci.org/loureirorg/redis-file)
2
+ This a Ruby implementation of redis-rb for machines without Redis or development/test environments
3
+
4
+
5
+ ## Installation
6
+
7
+ Install the gem:
8
+
9
+ gem install redis-file
10
+
11
+ Add it to your Gemfile:
12
+
13
+ gem "redis-file"
14
+
15
+
16
+ ## Versions
17
+
18
+ redis-file currently supports redis-rb v3.0.0 or later, if you are using
19
+ redis-rb v2.2.x install the version 0.3.x:
20
+
21
+ gem install redis-file -v "~> 0.3.0"
22
+
23
+ or use the branch 0-3-x on your Gemfile:
24
+
25
+ gem "redis-file", :git => "git://github.com/loureirorg/redis-file.git", :branch => "0-3-x"
26
+
27
+
28
+ ## Usage
29
+
30
+ You can use redis-file without any changes:
31
+
32
+ require "redis-file"
33
+
34
+ redis = Redis.new
35
+
36
+ >> redis.set "foo", "bar"
37
+ => "OK"
38
+
39
+ >> redis.get "foo"
40
+ => "bar"
41
+
42
+ Read [redis-rb](https://github.com/ezmobius/redis-rb) documentation and
43
+ [Redis](http://redis.io) homepage for more info about commands
44
+
45
+ ## Usage with RSpec
46
+
47
+ Require this either in your Gemfile or in RSpec's support scripts. So either:
48
+
49
+ # Gemfile
50
+ group :test do
51
+ gem "rspec"
52
+ gem "redis-file", :require => "redis-file/rspec"
53
+ end
54
+
55
+ Or:
56
+
57
+ # spec/support/redis-file.rb
58
+ require 'redis-file/rspec'
59
+
60
+ ## Acknowledgements
61
+
62
+ * [dim](https://github.com/dim)
63
+ * [czarneckid](https://github.com/czarneckid)
64
+ * [obrie](https://github.com/obrie)
65
+ * [jredville](https://github.com/jredville)
66
+ * [redsquirrel](https://github.com/redsquirrel)
67
+ * [dpick](https://github.com/dpick)
68
+ * [caius](https://github.com/caius)
69
+ * [Travis-CI](http://travis-ci.org/)
70
+
71
+
72
+ ## Contributing to redis-file
73
+
74
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
75
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
76
+ * Fork the project
77
+ * Start a feature/bugfix branch
78
+ * Commit and push until you are happy with your contribution
79
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
80
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
81
+
82
+
83
+ ## Copyright
84
+
85
+ Copyleft 2013 Daniel Loureiro (based on work of Guillermo Iguaran). See LICENSE for
86
+ further details.
@@ -0,0 +1,27 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ $:.push File.expand_path("../lib", __FILE__)
5
+ require "redis-file/version"
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ require 'rspec/core'
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec) do |spec|
12
+ spec.pattern = FileList['spec/**/*_spec.rb']
13
+ spec.ruby_opts="-w"
14
+ end
15
+
16
+ task :default => :spec
17
+
18
+ require 'rdoc/task'
19
+ Rake::RDocTask.new do |rdoc|
20
+ version = RedisFile::VERSION
21
+
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = "redis-file #{version}"
24
+ rdoc.rdoc_files.include('README*')
25
+ rdoc.rdoc_files.include('lib/**/*.rb')
26
+ end
27
+
@@ -0,0 +1,6 @@
1
+ require 'redis'
2
+ require 'redis/connection/file'
3
+
4
+ module RedisFile
5
+ Redis = ::Redis
6
+ end
@@ -0,0 +1,70 @@
1
+ module RedisFile
2
+ # Represents a normal hash with some additional expiration information
3
+ # associated with each key
4
+ class ExpiringHash < Hash
5
+ attr_reader :expires
6
+
7
+ def initialize(*)
8
+ super
9
+ @expires = {}
10
+ end
11
+
12
+ def [](key)
13
+ key = normalize key
14
+ delete(key) if expired?(key)
15
+ super
16
+ end
17
+
18
+ def []=(key, val)
19
+ key = normalize key
20
+ expire(key)
21
+ super
22
+ end
23
+
24
+ def delete(key)
25
+ key = normalize key
26
+ expire(key)
27
+ super
28
+ end
29
+
30
+ def expire(key)
31
+ key = normalize key
32
+ expires.delete(key)
33
+ end
34
+
35
+ def expired?(key)
36
+ key = normalize key
37
+ expires.include?(key) && expires[key] < Time.now
38
+ end
39
+
40
+ def key?(key)
41
+ key = normalize key
42
+ delete(key) if expired?(key)
43
+ super
44
+ end
45
+
46
+ def values_at(*keys)
47
+ keys.each do |key|
48
+ key = normalize(key)
49
+ delete(key) if expired?(key)
50
+ end
51
+ super
52
+ end
53
+
54
+ def keys
55
+ super.select do |key|
56
+ key = normalize(key)
57
+ if expired?(key)
58
+ delete(key)
59
+ false
60
+ else
61
+ true
62
+ end
63
+ end
64
+ end
65
+
66
+ def normalize key
67
+ key.to_s
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,23 @@
1
+ # Require this either in your Gemfile or in RSpec's
2
+ # support scripts. Examples:
3
+ #
4
+ # # Gemfile
5
+ # group :test do
6
+ # gem "rspec"
7
+ # gem "redis-file", :require => "redis-file/rspec"
8
+ # end
9
+ #
10
+ # # spec/support/redis-file.rb
11
+ # require 'redis-file/rspec'
12
+ #
13
+
14
+ require 'rspec/core'
15
+ require 'redis-file'
16
+
17
+ RSpec.configure do |c|
18
+
19
+ c.before do
20
+ Redis::Connection::File.reset_all_databases
21
+ end
22
+
23
+ end
@@ -0,0 +1,74 @@
1
+ module RedisFile
2
+ # Takes in the variable length array of arguments for a zinterstore/zunionstore method
3
+ # and parses them into a few attributes for the method to access.
4
+ #
5
+ # Handles throwing errors for various scenarios (matches redis):
6
+ # * Custom weights specified, but not enough or too many given
7
+ # * Invalid aggregate value given
8
+ # * Multiple aggregate values given
9
+ class SortedSetArgumentHandler
10
+ # [Symbol] The aggregate method to use for the output values. One of %w(sum min max) expected
11
+ attr_reader :aggregate
12
+ # [Integer] Number of keys in the argument list
13
+ attr_accessor :number_of_keys
14
+ # [Array] The actual keys in the argument list
15
+ attr_accessor :keys
16
+ # [Array] integers for weighting the values of each key - one number per key expected
17
+ attr_accessor :weights
18
+
19
+ # Used internally
20
+ attr_accessor :type
21
+
22
+ # Expects all the argments for the method to be passed as an array
23
+ def initialize args
24
+ # Pull out known lengths of data
25
+ self.number_of_keys = args.shift
26
+ self.keys = args.shift(number_of_keys)
27
+ # Handle the variable lengths of data (WEIGHTS/AGGREGATE)
28
+ args.inject(self) {|handler, item| handler.handle(item) }
29
+
30
+ # Defaults for unspecified things
31
+ self.weights ||= Array.new(number_of_keys) { 1 }
32
+ self.aggregate ||= :sum
33
+
34
+ # Validate values
35
+ raise(Redis::CommandError, "ERR syntax error") unless weights.size == number_of_keys
36
+ raise(Redis::CommandError, "ERR syntax error") unless [:min, :max, :sum].include?(aggregate)
37
+ end
38
+
39
+ # Only allows assigning a value *once* - raises Redis::CommandError if a second is given
40
+ def aggregate=(str)
41
+ raise(Redis::CommandError, "ERR syntax error") if (defined?(@aggregate) && @aggregate)
42
+ @aggregate = str.to_s.downcase.to_sym
43
+ end
44
+
45
+ # Decides how to handle an item, depending on where we are in the arguments
46
+ def handle(item)
47
+ case item
48
+ when "WEIGHTS"
49
+ self.type = :weights
50
+ self.weights = []
51
+ when "AGGREGATE"
52
+ self.type = :aggregate
53
+ when nil
54
+ # This should never be called, raise a syntax error if we manage to hit it
55
+ raise(Redis::CommandError, "ERR syntax error")
56
+ else
57
+ send "handle_#{type}", item
58
+ end
59
+ self
60
+ end
61
+
62
+ def handle_weights(item)
63
+ self.weights << item
64
+ end
65
+
66
+ def handle_aggregate(item)
67
+ self.aggregate = item
68
+ end
69
+
70
+ def inject_block
71
+ lambda { |handler, item| handler.handle(item) }
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,80 @@
1
+ module RedisFile
2
+ class SortedSetStore
3
+ attr_accessor :data, :weights, :aggregate, :keys
4
+
5
+ def initialize params, data
6
+ self.data = data
7
+ self.weights = params.weights
8
+ self.aggregate = params.aggregate
9
+ self.keys = params.keys
10
+ end
11
+
12
+ def hashes
13
+ @hashes ||= keys.map do |src|
14
+ case data[src]
15
+ when ::Set
16
+ # Every value has a score of 1
17
+ Hash[data[src].map {|k,v| [k, 1]}]
18
+ when Hash
19
+ data[src]
20
+ else
21
+ {}
22
+ end
23
+ end
24
+ end
25
+
26
+ # Apply the weightings to the hashes
27
+ def computed_values
28
+ unless defined?(@computed_values) && @computed_values
29
+ # Do nothing if all weights are 1, as n * 1 is n
30
+ @computed_values = hashes if weights.all? {|weight| weight == 1 }
31
+ # Otherwise, multiply the values in each hash by that hash's weighting
32
+ @computed_values ||= hashes.each_with_index.map do |hash, index|
33
+ weight = weights[index]
34
+ Hash[hash.map {|k, v| [k, (v * weight)]}]
35
+ end
36
+ end
37
+ @computed_values
38
+ end
39
+
40
+ def aggregate_sum out
41
+ selected_keys.each do |key|
42
+ out[key] = computed_values.inject(0) do |n, hash|
43
+ n + (hash[key] || 0)
44
+ end
45
+ end
46
+ end
47
+
48
+ def aggregate_min out
49
+ selected_keys.each do |key|
50
+ out[key] = computed_values.map {|h| h[key] }.compact.min
51
+ end
52
+ end
53
+
54
+ def aggregate_max out
55
+ selected_keys.each do |key|
56
+ out[key] = computed_values.map {|h| h[key] }.compact.max
57
+ end
58
+ end
59
+
60
+ def selected_keys
61
+ raise NotImplemented, "subclass needs to implement #selected_keys"
62
+ end
63
+
64
+ def call
65
+ ZSet.new.tap {|out| send("aggregate_#{aggregate}", out) }
66
+ end
67
+ end
68
+
69
+ class SortedSetIntersectStore < SortedSetStore
70
+ def selected_keys
71
+ @values ||= hashes.inject([]) { |r, h| r.empty? ? h.keys : (r & h.keys) }
72
+ end
73
+ end
74
+
75
+ class SortedSetUnionStore < SortedSetStore
76
+ def selected_keys
77
+ @values ||= hashes.map(&:keys).flatten.uniq
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module RedisFile
2
+ VERSION = "0.4.2"
3
+ end
@@ -0,0 +1,29 @@
1
+ module RedisFile
2
+ class ZSet < Hash
3
+
4
+ def []=(key, val)
5
+ super(key, _floatify(val))
6
+ end
7
+
8
+ # Increments the value of key by val
9
+ def increment(key, val)
10
+ self[key] += _floatify(val)
11
+ end
12
+
13
+ def select_by_score min, max
14
+ min = _floatify(min)
15
+ max = _floatify(max)
16
+ reject {|_,v| v < min || v > max }
17
+ end
18
+
19
+ # Originally lifted from redis-rb
20
+ def _floatify(str)
21
+ if (( inf = str.to_s.match(/^([+-])?inf/i) ))
22
+ (inf[1] == "-" ? -1.0 : 1.0) / 0.0
23
+ else
24
+ Float str
25
+ end
26
+ end
27
+
28
+ end
29
+ end