frivol 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ FAKE_REDIS = true
2
+
1
3
  class Redis
2
4
  def initialize(config)
3
5
  @storage = {}
@@ -21,45 +23,68 @@ class Redis
21
23
  @storage.delete key
22
24
  @expires.delete key
23
25
  end
24
-
26
+
25
27
  def incr(key)
26
28
  # puts "incr #{key}"
29
+ @storage[key] ||= 0
27
30
  @storage[key] += 1
28
31
  end
29
-
32
+
33
+ def incrby(key, amount)
34
+ # puts "incr #{key}"
35
+ @storage[key] ||= 0
36
+ @storage[key] += amount
37
+ end
38
+
39
+ def decr(key)
40
+ # puts "decr #{key}"
41
+ @storage[key] ||= 0
42
+ @storage[key] -= 1
43
+ end
44
+
45
+ def decrby(key, amount)
46
+ # puts "decr #{key}"
47
+ @storage[key] ||= 0
48
+ @storage[key] -= amount
49
+ end
50
+
30
51
  def expire(key, time)
31
52
  begin
32
- t = Integer(time)
33
- rescue
53
+ t = Integer(time)
54
+ rescue
34
55
  raise RuntimeError.new("-ERR value is not an integer")
35
56
  end
36
57
  @expires[key] = Time.now + t
37
58
  end
38
-
59
+
39
60
  def exists(key)
40
61
  @storage.key? key
41
62
  end
42
-
63
+
43
64
  def ttl(key)
44
65
  # puts "ttl #{key}"
45
66
  return -1 if @expires[key].nil? || @expires[key] < Time.now
46
67
  (@expires[key] - Time.now).to_i
47
68
  end
48
-
69
+
49
70
  def multi(&block)
50
71
  yield(self)
51
72
  end
52
-
73
+
53
74
  def flushdb
54
75
  @storage = {}
55
76
  end
56
-
77
+
57
78
  # Help with debugging
58
79
  def inspect
59
- @storage.keys.sort.map do |key|
80
+ @storage.keys.sort.map do |key|
60
81
  result = "\n#{key} => #{@storage[key].inspect}"
61
82
  result << "\n\texpires at #{@expires[key]}" if @expires.key?(key)
62
83
  result
63
84
  end
64
85
  end
65
- end
86
+
87
+ def method_missing(meth, *args, &block)
88
+ puts "Missing method: #{meth} called with #{args.inspect}"
89
+ end
90
+ end
@@ -1,30 +1,35 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
- require 'shoulda'
4
- require 'mocha'
5
3
 
6
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
8
6
  require 'frivol'
9
7
 
10
8
  class Test::Unit::TestCase
9
+ def setup
10
+ fake_redis # Comment out this line to test against a real live Redis
11
+ Frivol::Config.redis_config = { :db => 10 } # This will connect to a default Redis setup, otherwise set to { :host => "localhost", :port => 6379 }, for example
12
+ Frivol::Config.redis.flushdb
13
+ end
14
+
15
+ def teardown
16
+ # puts Frivol::Config.redis.inspect
17
+ Frivol::Config.redis.flushdb
18
+ end
19
+
11
20
  def fake_redis
12
21
  require 'fake_redis'
13
22
  end
23
+
24
+ def ruby_one_eight?
25
+ @ruby_one_eight || `ruby -v`.include?('1.8')
26
+ end
14
27
  end
15
28
 
16
29
  class TestClass
17
30
  include Frivol
18
-
31
+
19
32
  def id
20
33
  1
21
34
  end
22
-
23
- def save
24
- store :value => "value"
25
- end
26
-
27
- def load
28
- retrieve :value => "default"
29
- end
30
35
  end
@@ -0,0 +1,53 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestBuckets < Test::Unit::TestCase
4
+ def test_be_able_to_create_and_use_buckets
5
+ t = Class.new(TestClass) { storage_bucket :blue }.new
6
+
7
+ assert t.respond_to?(:store_blue)
8
+ assert t.respond_to?(:retrieve_blue)
9
+ end
10
+
11
+ def test_store_different_values_in_different_buckets
12
+ t = Class.new(TestClass) { storage_bucket :blue }.new
13
+
14
+ t.store :value => 'value'
15
+ t.store_blue :value => 'blue value'
16
+
17
+ assert_equal "value", t.retrieve(:value => 'default')
18
+ assert_equal "blue value", t.retrieve_blue(:value => 'default')
19
+ end
20
+
21
+ def test_be_able_to_delete_storage_for_a_bucket
22
+ t = Class.new(TestClass) { storage_bucket :silver }.new
23
+ t.store_silver :value => 'value'
24
+ assert_equal "value", t.retrieve_silver(:value => 'default')
25
+ t.delete_silver
26
+ assert_equal "default", t.retrieve_silver(:value => 'default')
27
+ end
28
+
29
+ def test_have_different_expiry_times_for_different_buckets
30
+ klass = Class.new(TestClass) do
31
+ storage_bucket :blue, :expires_in => 1
32
+ storage_expires_in 2
33
+ end
34
+
35
+ assert_equal 1, klass.storage_expiry(:blue)
36
+ assert_equal 2, klass.storage_expiry
37
+ end
38
+
39
+ def test_expire_data_in_buckets
40
+ klass = Class.new(TestClass) do
41
+ storage_bucket :blue, :expires_in => -1
42
+ storage_expires_in 1
43
+ end
44
+
45
+ t = klass.new
46
+ t.store :value => 'value'
47
+ t.store_blue :value => 'value'
48
+
49
+ t = klass.new # get a new instance so @frivol_data is empty
50
+ assert_equal "value", t.retrieve(:value => 'default')
51
+ assert_equal "blue default", t.retrieve_blue(:value => 'blue default')
52
+ end
53
+ end
@@ -0,0 +1,43 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestCondition < Test::Unit::TestCase
4
+ def test_stores_if_CONDITION_method_evaluates_to_truthy
5
+ klass = Class.new(TestClass) do
6
+ storage_bucket :stars, :condition => :something_truthy
7
+
8
+ def something_truthy(*args)
9
+ 'Wax museum'
10
+ end
11
+ end
12
+ t = klass.new
13
+
14
+ t.store_stars :value => 88
15
+ assert_equal 88, t.retrieve_stars(:value => 0)
16
+ end
17
+
18
+ def test_stores_with_positive_CONDITION_proc
19
+ t = Class.new(TestClass) { storage_bucket :stars, :condition => Proc.new{true} }.new
20
+ t.store_stars :value => 77
21
+ assert_equal 77, t.retrieve_stars(:value => 0)
22
+ end
23
+
24
+ def test_stores_positive_CONDITION_proc_which_takes_an_instance
25
+ klass = Class.new(TestClass) do
26
+ storage_bucket :stars, :condition => Proc.new{ |instance, frivol_method, *args| instance.something_truthy }
27
+
28
+ def something_truthy(*args)
29
+ 'Wax museum'
30
+ end
31
+ end
32
+ t = klass.new
33
+
34
+ t.store_stars :value => 66
35
+ assert_equal 66, t.retrieve_stars(:value => 0)
36
+ end
37
+
38
+ def test_does_not_store_with_negative_CONDITION
39
+ t = Class.new(TestClass) { storage_bucket :stars, :condition => Proc.new{false} }.new
40
+ t.store_stars :value => 55
41
+ assert_equal 0, t.retrieve_stars(:value => 0)
42
+ end
43
+ end
@@ -0,0 +1,90 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestConditionCounters < Test::Unit::TestCase
4
+ def test_increments_a_counter_with_no_conditions
5
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true }.new
6
+ t.increment_stars
7
+ assert_equal 1, t.retrieve_stars(0)
8
+ end
9
+
10
+ def test_increments_a_counter_if_condition_evaluates_to_true
11
+ klass = Class.new(TestClass) do
12
+ storage_bucket :stars, :counter => true, :condition => :something_truthy
13
+
14
+ def something_truthy(frivol_method, *args)
15
+ 'Wax museum'
16
+ end
17
+ end
18
+ t = klass.new
19
+
20
+ t.increment_stars
21
+ assert_equal 1, t.retrieve_stars(0)
22
+ end
23
+
24
+ def test_increments_a_counter_with_positive_condition
25
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => Proc.new{true} }.new
26
+ t.increment_stars
27
+ assert_equal 1, t.retrieve_stars(0)
28
+ end
29
+
30
+ def test_increments_a_counter_when_condition_is_a_proc
31
+ klass = Class.new(TestClass) do
32
+ storage_bucket :stars, :counter => true, :condition => Proc.new{ |instance, frivol_method, *args| instance.something_truthy }
33
+
34
+ def something_truthy
35
+ 'Wax museum'
36
+ end
37
+ end
38
+ t = klass.new
39
+
40
+ t.increment_stars
41
+ assert_equal 1, t.retrieve_stars(0)
42
+ end
43
+
44
+ def test_does_not_increment_a_counter_with_negative_condition
45
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => Proc.new{false} }.new
46
+ t.increment_stars
47
+ assert_equal 0, t.retrieve_stars(0)
48
+ end
49
+
50
+ def test_does_not_increment_a_counter_when_condition_is_false
51
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => false }.new
52
+ t.increment_stars
53
+ assert_equal 0, t.retrieve_stars(0)
54
+ end
55
+
56
+ def test_increment_by_does_not_increment_with_condition_is_false
57
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => false }.new
58
+ t.increment_stars_by(20)
59
+ assert_equal 0, t.retrieve_stars(0)
60
+ end
61
+
62
+ def test_store_does_not_set_the_value_if_condition_is_negative
63
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => Proc.new{ false } }.new
64
+ t.store_stars(20)
65
+ assert_equal 0, t.retrieve_stars(0)
66
+ end
67
+
68
+ def test_decrement_only_happens_if_condition_is_positive
69
+ condition_proc = proc do |instance, method_name, *args|
70
+ method_name != 'increment_stars'
71
+ end
72
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => condition_proc }.new
73
+ t.store_stars(20)
74
+ t.increment_stars
75
+ t.decrement_stars
76
+ assert_equal 19, t.retrieve_stars(0)
77
+ end
78
+
79
+ def test_decrement_by_only_happens_if_condition_is_positive
80
+ condition_proc = proc do |instance, method_name, *args|
81
+ method_name != 'increment_stars'
82
+ end
83
+
84
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => condition_proc }.new
85
+ t.store_stars(20)
86
+ t.increment_stars
87
+ t.decrement_stars_by 10
88
+ assert_equal 10, t.retrieve_stars(0)
89
+ end
90
+ end
@@ -0,0 +1,72 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestCounters < Test::Unit::TestCase
4
+ def test_be_able_to_create_counter_buckets
5
+ t = Class.new(TestClass) { storage_bucket :blue, :counter => true }.new
6
+
7
+ assert t.respond_to?(:store_blue)
8
+ assert t.respond_to?(:retrieve_blue)
9
+ assert t.respond_to?(:increment_blue)
10
+ end
11
+
12
+ def test_store_increment_and_retrieve_integers_in_a_counter
13
+ t = Class.new(TestClass) { storage_bucket :blue, :counter => true }.new
14
+ t.store_blue 10
15
+
16
+ assert_equal 10, t.retrieve_blue(0)
17
+ assert_equal 11, t.increment_blue
18
+ assert_equal 11, t.retrieve_blue(0)
19
+ end
20
+
21
+ def test_increment_by_and_retrieve_integers_in_a_counter
22
+ t = Class.new(TestClass) do
23
+ storage_bucket :cats, :counter => true
24
+
25
+ def kittens
26
+ increment_cats_by 5
27
+ end
28
+ end.new
29
+
30
+ t.store_cats 1
31
+ assert_equal 1, t.retrieve_cats(0)
32
+ t.kittens
33
+ assert_equal 6, t.retrieve_cats(0)
34
+ end
35
+
36
+ def test_store_decrement_and_retrieve_integers_in_a_counter
37
+ t = Class.new(TestClass) { storage_bucket :red, :counter => true }.new
38
+
39
+ assert_equal 0, t.retrieve_red(0)
40
+ t.store_red(10)
41
+ assert_equal 10, t.retrieve_red(0)
42
+ assert_equal 9, t.decrement_red
43
+ assert_equal 9, t.retrieve_red(0)
44
+ end
45
+
46
+ def test_decrement_by_and_retrieve_integers_in_a_counter
47
+ t = Class.new(TestClass) do
48
+ storage_bucket :money, :counter => true
49
+
50
+ def shopping
51
+ decrement_money_by 1000
52
+ end
53
+ end.new
54
+
55
+ t.store_money 2000
56
+ assert_equal 2000, t.retrieve_money(0)
57
+ t.shopping
58
+ assert_equal 1000, t.retrieve_money(0)
59
+ end
60
+
61
+ def test_set_expiry_on_counters
62
+ klass = Class.new(TestClass) { storage_bucket :sheep, :counter => true, :expires_in => 1 }
63
+ klass.new
64
+ assert_equal 1, klass.storage_expiry(:sheep)
65
+ end
66
+
67
+ def test_expire_a_counter_bucket
68
+ t = Class.new(TestClass) { storage_bucket :yellow, :counter => true, :expires_in => -1 }.new
69
+ t.store_yellow 10
70
+ assert_equal 0, t.retrieve_yellow(0)
71
+ end
72
+ end
@@ -0,0 +1,39 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestElseWithCounters < Test::Unit::TestCase
4
+ def test_given_CONDITION_evaluates_to_true_ELSE_is_not_performed
5
+ else_proc = Proc.new{raise StandardError.new('You\'ll never catch me!') }
6
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => Proc.new{true}, :else => else_proc }.new
7
+
8
+ assert_nothing_raised do
9
+ t.increment_stars
10
+ assert_equal 1, t.retrieve_stars(0)
11
+ end
12
+ end
13
+
14
+ def test_given_CONDITION_evaluates_to_false_ELSE_is_performed
15
+ else_proc = Proc.new{ |instance, method_name, *args| raise StandardError.new('You\'ll never catch me!') if method_name == 'increment_stars' }
16
+ t = Class.new(TestClass) { storage_bucket :stars, :counter => true, :condition => Proc.new{false}, :else => else_proc }.new
17
+
18
+ assert_raises StandardError do
19
+ t.increment_stars
20
+ end
21
+
22
+ assert_equal 0, t.retrieve_stars(0)
23
+ end
24
+
25
+ def test_given_CONDITION_evaluates_to_false_ELSE_calls_a_method_on_the_object
26
+ klass = Class.new(TestClass) do
27
+ condition_proc = Proc.new{ |instance, method_name, *args| method_name != 'increment_stars'}
28
+ storage_bucket :stars, :counter => true, :condition => condition_proc, :else => :set_stars_to_20
29
+
30
+ def set_stars_to_20(frivol_method, *args)
31
+ store_stars 20
32
+ end
33
+ end
34
+ t = klass.new
35
+
36
+ t.increment_stars
37
+ assert_equal 20, t.retrieve_stars(0)
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper.rb"
2
+
3
+ class TestExtensions < Test::Unit::TestCase
4
+ require "#{File.join(File.expand_path(File.dirname(__FILE__)), '../lib/frivol/time_extensions')}"
5
+
6
+ def test_time
7
+ time = Time.local(2014, 3, 4, 17, 53, 29)
8
+
9
+ t = TestClass.new
10
+ t.store(:time => time)
11
+
12
+ t = TestClass.new
13
+ assert_equal time, t.retrieve(:time => nil)
14
+ end
15
+ end