frivol 0.2.0 → 0.3.0

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.
@@ -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