redis_object 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.coveralls.yml +1 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +8 -0
  5. data/README.markdown +179 -0
  6. data/Rakefile +10 -0
  7. data/lib/redis_object.rb +47 -0
  8. data/lib/redis_object/base.rb +408 -0
  9. data/lib/redis_object/collection.rb +388 -0
  10. data/lib/redis_object/defaults.rb +42 -0
  11. data/lib/redis_object/experimental/history.rb +49 -0
  12. data/lib/redis_object/ext/benchmark.rb +34 -0
  13. data/lib/redis_object/ext/cleaner.rb +14 -0
  14. data/lib/redis_object/ext/filters.rb +68 -0
  15. data/lib/redis_object/ext/script_cache.rb +92 -0
  16. data/lib/redis_object/ext/shardable.rb +18 -0
  17. data/lib/redis_object/ext/triggers.rb +101 -0
  18. data/lib/redis_object/ext/view_caching.rb +258 -0
  19. data/lib/redis_object/ext/views.rb +102 -0
  20. data/lib/redis_object/external_index.rb +25 -0
  21. data/lib/redis_object/indices.rb +97 -0
  22. data/lib/redis_object/inheritance_tracking.rb +23 -0
  23. data/lib/redis_object/keys.rb +37 -0
  24. data/lib/redis_object/storage.rb +93 -0
  25. data/lib/redis_object/storage/adapter.rb +46 -0
  26. data/lib/redis_object/storage/aws.rb +71 -0
  27. data/lib/redis_object/storage/mysql.rb +47 -0
  28. data/lib/redis_object/storage/redis.rb +119 -0
  29. data/lib/redis_object/timestamps.rb +74 -0
  30. data/lib/redis_object/tpl.rb +17 -0
  31. data/lib/redis_object/types.rb +276 -0
  32. data/lib/redis_object/validation.rb +89 -0
  33. data/lib/redis_object/version.rb +5 -0
  34. data/redis_object.gemspec +26 -0
  35. data/spec/adapter_spec.rb +43 -0
  36. data/spec/base_spec.rb +90 -0
  37. data/spec/benchmark_spec.rb +46 -0
  38. data/spec/collections_spec.rb +144 -0
  39. data/spec/defaults_spec.rb +56 -0
  40. data/spec/filters_spec.rb +29 -0
  41. data/spec/indices_spec.rb +45 -0
  42. data/spec/rename_class_spec.rb +96 -0
  43. data/spec/spec_helper.rb +38 -0
  44. data/spec/timestamp_spec.rb +28 -0
  45. data/spec/trigger_spec.rb +51 -0
  46. data/spec/types_spec.rb +103 -0
  47. data/spec/view_caching_spec.rb +130 -0
  48. data/spec/views_spec.rb +72 -0
  49. metadata +172 -0
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module DefaultSpec
4
+
5
+ TestValues = {
6
+ date: Date.today,
7
+ number: 27,
8
+ int: 356192,
9
+ float: 72.362517,
10
+ bool: true,
11
+ # boolean: false,
12
+ # array: [:test1,:test2],
13
+ json: {test1: true, test2: "false"}
14
+ }
15
+
16
+ TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
17
+
18
+ # Delicious pizza!
19
+ class DefaultedObject < RedisObject
20
+
21
+ TestValues.keys.each do |type|
22
+ send(type.to_sym,"a_#{type}".to_sym)
23
+ end
24
+ default_for :testy, "test"
25
+ default_for :a_number, 42
26
+
27
+ end
28
+
29
+ describe Seabright::DefaultValues do
30
+ before do
31
+ RedisObject.store.flushdb
32
+ end
33
+
34
+ it "returns default value" do
35
+
36
+ obj = DefaultedObject.create(TestData)
37
+
38
+ obj.testy.should eq("test")
39
+ obj.get(:a_number).should eq(27)
40
+ obj.unset(:a_number)
41
+ obj.get(:a_number).should eq(42)
42
+
43
+ end
44
+
45
+ it "returns default value after unset" do
46
+
47
+ obj = DefaultedObject.create(TestData)
48
+
49
+ obj.get(:a_number).should eq(27)
50
+ obj.unset(:a_number)
51
+ obj.get(:a_number).should eq(42)
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module FilterSpec
4
+
5
+ class FilteredObject < RedisObject
6
+
7
+ def double(k,v)
8
+ (k == :testy) && v ? [:testy,v*2] : [k,v]
9
+ end
10
+ set_filter :double
11
+
12
+ end
13
+
14
+ describe Seabright::Filters do
15
+ before do
16
+ RedisObject.store.flushdb
17
+ end
18
+
19
+ it "modifies set and gets correctly" do
20
+
21
+ obj = FilteredObject.create("test")
22
+
23
+ obj.set(:testy,"test")
24
+ obj.get(:testy).should eq("testtest")
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,45 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module IndexSpec
4
+
5
+ TestValues = {
6
+ date: Date.today,
7
+ number: 27,
8
+ int: 356192,
9
+ float: 72.362517,
10
+ bool: true,
11
+ # boolean: false,
12
+ # array: [:test1,:test2],
13
+ json: {test1: true, test2: "false"}
14
+ }
15
+
16
+ TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
17
+
18
+ # Delicious pizza!
19
+ class IndexedObject < RedisObject
20
+
21
+ TestValues.keys.each do |type|
22
+ send(type.to_sym,"a_#{type}".to_sym)
23
+ end
24
+
25
+ sort_by :a_number
26
+
27
+ end
28
+
29
+ describe Seabright::Indices do
30
+ before do
31
+ RedisObject.store.flushdb
32
+ end
33
+
34
+ it "indexes on integer field" do
35
+
36
+ 5.times do
37
+ obj = IndexedObject.create(a_number: Random.rand(100))
38
+ end
39
+
40
+ IndexedObject.indexed(:a_number,3,true).count.should eq(3)
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,96 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module RenameClassSpec
4
+ # Delicious pizza!
5
+ class Pizza < RedisObject; end
6
+ # We love toppings but our current name Topping is too ambiguous!
7
+ class Topping < RedisObject; end
8
+ # Let's change the class name to PizzaTopping!
9
+ class PizzaTopping < RedisObject; end
10
+
11
+ describe Seabright::Storage::Redis, "#rename_class" do
12
+ before do
13
+ RedisObject.store.flushdb
14
+
15
+ mozzarella = Topping.create(:mozzarella)
16
+ basil = Topping.create(:basil)
17
+ tomato = Topping.create(:tomato)
18
+ garlic = Topping.create(:garlic)
19
+ oregano = Topping.create(:oregano)
20
+ olive_oil = Topping.create(:olive_oil)
21
+
22
+ marinara = Pizza.create(:marinara)
23
+ [ tomato, garlic, oregano, olive_oil ].each{|topping| marinara << topping }
24
+
25
+ margherita = Pizza.create(:margherita)
26
+ [ tomato, mozzarella, basil, olive_oil ].each{|topping| margherita << topping }
27
+ end
28
+
29
+ it "setup works" do
30
+ margherita = Pizza.find(:margherita)
31
+ marinara = Pizza.find(:marinara)
32
+ mozzarella = Topping.find(:mozzarella)
33
+ basil = Topping.find(:basil)
34
+ tomato = Topping.find(:tomato)
35
+ garlic = Topping.find(:garlic)
36
+ oregano = Topping.find(:oregano)
37
+ olive_oil = Topping.find(:olive_oil)
38
+
39
+ [ mozzarella, basil, tomato, garlic, oregano, olive_oil ].each do |topping|
40
+ topping.get(:class).should == Topping.name
41
+ topping.get(:key).should == "RenameClassSpec::Topping:#{topping.id}"
42
+ topping.get(:topping_id).should == topping.id
43
+ end
44
+
45
+ Topping.indexed(:created_at).first.should_not be_nil
46
+ Topping.indexed(:created_at).count.should == 5
47
+
48
+ [margherita, marinara].each do |pizza|
49
+ pizza.pizza_toppings.should be_nil
50
+ pizza.toppings.count.should == 4
51
+ pizza.toppings.should include(tomato.hkey)
52
+ pizza.toppings.should include(olive_oil.hkey)
53
+ end
54
+
55
+ margherita.toppings.should include(basil.hkey)
56
+ margherita.toppings.should include(mozzarella.hkey)
57
+ marinara.toppings.should include(oregano.hkey)
58
+ marinara.toppings.should include(garlic.hkey)
59
+ end
60
+
61
+ it "renames a class" do
62
+ RedisObject.store.rename_class(:"RenameClassSpec::Topping", :"RenameClassSpec::PizzaTopping")
63
+
64
+ margherita = Pizza.find(:margherita)
65
+ marinara = Pizza.find(:marinara)
66
+ mozzarella = PizzaTopping.find(:mozzarella)
67
+ basil = PizzaTopping.find(:basil)
68
+ tomato = PizzaTopping.find(:tomato)
69
+ garlic = PizzaTopping.find(:garlic)
70
+ oregano = PizzaTopping.find(:oregano)
71
+ olive_oil = PizzaTopping.find(:olive_oil)
72
+
73
+ [ mozzarella, basil, tomato, garlic, oregano, olive_oil ].each do |topping|
74
+ topping.get(:class).should == PizzaTopping.name
75
+ topping.get(:key).should == "RenameClassSpec::PizzaTopping:#{topping.id}"
76
+ topping.get(:"renameclassspec::pizzatopping_id").should == topping.id
77
+ # topping.get(:topping_id).should == nil
78
+ end
79
+
80
+ [margherita, marinara].each do |pizza|
81
+ pizza.toppings.should be_nil
82
+ pizza.pizza_toppings.count.should == 4
83
+ pizza.pizza_toppings.should include(tomato.hkey)
84
+ pizza.pizza_toppings.should include(olive_oil.hkey)
85
+ end
86
+
87
+ margherita.pizza_toppings.should include(basil.hkey)
88
+ margherita.pizza_toppings.should include(mozzarella.hkey)
89
+ marinara.pizza_toppings.should include(oregano.hkey)
90
+ marinara.pizza_toppings.should include(garlic.hkey)
91
+
92
+ PizzaTopping.indexed(:created_at).first.should_not be_nil
93
+ PizzaTopping.indexed(:created_at).count.should == 5
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,38 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ $LOAD_PATH.unshift File.dirname(__FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'rspec'
7
+
8
+ require 'simplecov'
9
+ require 'coveralls'
10
+
11
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
12
+ SimpleCov::Formatter::HTMLFormatter,
13
+ Coveralls::SimpleCov::Formatter
14
+ ]
15
+ SimpleCov.start do
16
+ add_filter "_spec.rb"
17
+ add_filter "/experimental/"
18
+ add_group "Extensions", "lib/redis_object/ext/"
19
+ end
20
+
21
+ require 'redis_object'
22
+
23
+ class DebugMode
24
+ def initialize(o=nil); @opts = o; end
25
+ def verbose?; debug? && !!@opts[:verbose]; end
26
+ def debug?; !!@opts; end
27
+ end
28
+ Debug = if ENV['DEBUG']
29
+ require 'debugger'
30
+ DEBUG = true
31
+ DebugMode.new(verbose:true)
32
+ else
33
+ DEBUG = false
34
+ DebugMode.new
35
+ end
36
+
37
+ raise 'must specify TEST_DB' unless ENV['TEST_DB']
38
+ RedisObject.configure_store({adapter:'Redis', db:ENV['TEST_DB']},:global,:alias)
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module TriggerSpec
4
+
5
+ class TimestampedObject < RedisObject;end
6
+
7
+ class UnTimestampedObject < RedisObject
8
+ # time_matters_not!
9
+ end
10
+
11
+ describe Seabright::Triggers do
12
+ before do
13
+ RedisObject.store.flushdb
14
+ end
15
+
16
+ it "should get recently created object" do
17
+
18
+ (1..5).each do |n|
19
+ TimestampedObject.create(n.to_s)
20
+ sleep Random.rand(1.0)
21
+ end
22
+
23
+ TimestampedObject.recently_created.first.id.should eq("5")
24
+
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module TriggerSpec
4
+
5
+ class TriggeredObject < RedisObject
6
+
7
+ int :raw_phone
8
+ bool :mailed_flag
9
+ bool :mail_was_sent_for_realz
10
+ date :srsly_updated
11
+
12
+ def track_phone_raw(k,v)
13
+ set(:raw_phone, v.gsub(/[^0-9]/,'').to_i)
14
+ end
15
+
16
+ trigger_on_set :phone, :track_phone_raw
17
+
18
+ def sent_mail(k,v)
19
+ set(:mail_was_sent_for_realz, true)
20
+ end
21
+
22
+ def updated_redundant(k,v)
23
+ set(:srsly_updated, Time.now)
24
+ end
25
+
26
+ trigger_on_set :mailed_flag, :sent_mail
27
+ trigger_on_update :updated_redundant
28
+
29
+ end
30
+
31
+ describe Seabright::Triggers do
32
+ before do
33
+ RedisObject.store.flushdb
34
+ end
35
+
36
+ it "triggers on a call" do
37
+
38
+ obj = TriggeredObject.create("trig")
39
+
40
+ obj.phone = "(970) 555-1212"
41
+ obj.raw_phone.should eq(9705551212)
42
+ success = obj.setnx(:mailed_flag,true)
43
+ success.should eq(true)
44
+ obj.mail_was_sent_for_realz.should eq(true)
45
+ success = obj.setnx(:mailed_flag,true)
46
+ success.should eq(false)
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module TypeSpec
4
+
5
+ TestValues = {
6
+ date: Date.today,
7
+ number: 27,
8
+ int: 356192,
9
+ float: 72.362517,
10
+ bool: true,
11
+ boolean: false,
12
+ array: ["test1","test2"],
13
+ json: {test1: true, test2: "false"}
14
+ }
15
+
16
+ TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
17
+
18
+ class TypedObject < RedisObject
19
+ TestValues.keys.each do |type|
20
+ send(type.to_sym,"a_#{type}".to_sym)
21
+ end
22
+ end
23
+
24
+ class TypedChild < TypedObject; end
25
+
26
+ describe Seabright::Types do
27
+ before do
28
+ RedisObject.store.flushdb
29
+ end
30
+
31
+ it "can be created via data packet" do
32
+
33
+ obj = TypedObject.create(TestData)
34
+
35
+ TestData.each do |k,v|
36
+ obj.get(k).should eq(v)
37
+ end
38
+
39
+ end
40
+
41
+ it "inherits types" do
42
+
43
+ obj = TypedChild.create(TestData)
44
+
45
+ TestData.each do |k,v|
46
+ obj.get(k).should eq(v)
47
+ end
48
+
49
+ end
50
+
51
+ it "can be instantiated (new) via data packet" do
52
+
53
+ obj = TypedObject.new(TestData)
54
+
55
+ TestData.each do |k,v|
56
+ obj.get(k).should eq(v)
57
+ end
58
+
59
+ end
60
+
61
+ it "can be created via individual sets" do
62
+
63
+ obj = TypedObject.new
64
+
65
+ TestData.each do |k,v|
66
+ obj.set(k,v)
67
+ obj.get(k).should eq(v)
68
+ end
69
+
70
+ end
71
+
72
+ it "gets correct values after being found" do
73
+
74
+ objc = TypedObject.create(TestData)
75
+ obj = TypedObject.find(objc.id)
76
+
77
+ TestData.each do |k,v|
78
+ obj.get(k).should eq(v)
79
+ end
80
+
81
+ end
82
+
83
+ it "nullifies non-date date value" do
84
+
85
+ obj = TypedObject.new
86
+
87
+ obj.a_date = "sjahfgasjfg"
88
+ obj.a_date.should eq(nil)
89
+
90
+ end
91
+
92
+ it "describes itself" do
93
+
94
+ obj = TypedObject.create(TestData)
95
+ objc = TypedChild.create(TestData)
96
+
97
+ desc = TypedObject.describe
98
+ TypedObject.dump_schema(File.open("/tmp/redisobject_dump_test","w"))
99
+
100
+ end
101
+
102
+ end
103
+ end