redis_object 1.0 → 1.1

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.
Files changed (103) hide show
  1. data/.coveralls.yml +1 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +4 -0
  5. data/README.markdown +24 -15
  6. data/Rakefile +8 -0
  7. data/lib/redis_object.rb +11 -1
  8. data/lib/redis_object/base.rb +210 -60
  9. data/lib/redis_object/collection.rb +130 -100
  10. data/lib/redis_object/defaults.rb +21 -8
  11. data/lib/redis_object/{history.rb → experimental/history.rb} +0 -0
  12. data/lib/redis_object/ext/filters.rb +34 -16
  13. data/lib/redis_object/ext/script_cache.rb +92 -0
  14. data/lib/redis_object/ext/shardable.rb +18 -0
  15. data/lib/redis_object/ext/triggers.rb +75 -13
  16. data/lib/redis_object/ext/view_caching.rb +258 -0
  17. data/lib/redis_object/ext/views.rb +102 -0
  18. data/lib/redis_object/indices.rb +44 -39
  19. data/lib/redis_object/inheritance_tracking.rb +23 -0
  20. data/lib/redis_object/keys.rb +4 -4
  21. data/lib/redis_object/storage.rb +30 -1
  22. data/lib/redis_object/storage/adapter.rb +6 -3
  23. data/lib/redis_object/storage/redis.rb +98 -3
  24. data/lib/redis_object/timestamps.rb +42 -21
  25. data/lib/redis_object/types.rb +172 -30
  26. data/lib/redis_object/version.rb +1 -1
  27. data/redis_object.gemspec +1 -0
  28. data/spec/adapter_spec.rb +43 -0
  29. data/spec/base_spec.rb +41 -6
  30. data/spec/benchmark_spec.rb +46 -0
  31. data/spec/collections_spec.rb +144 -0
  32. data/spec/defaults_spec.rb +56 -0
  33. data/spec/filters_spec.rb +29 -0
  34. data/spec/indices_spec.rb +45 -0
  35. data/spec/rename_class_spec.rb +96 -0
  36. data/spec/spec_helper.rb +32 -1
  37. data/spec/timestamp_spec.rb +28 -0
  38. data/spec/trigger_spec.rb +51 -0
  39. data/spec/types_spec.rb +103 -0
  40. data/spec/view_caching_spec.rb +130 -0
  41. data/spec/views_spec.rb +72 -0
  42. metadata +111 -116
  43. data/doc/Object.html +0 -185
  44. data/doc/Seabright.html +0 -181
  45. data/doc/Seabright/Adapter.html +0 -442
  46. data/doc/Seabright/Collection.html +0 -797
  47. data/doc/Seabright/Collections.html +0 -635
  48. data/doc/Seabright/Collections/ClassMethods.html +0 -212
  49. data/doc/Seabright/ExternalIndex.html +0 -217
  50. data/doc/Seabright/History.html +0 -382
  51. data/doc/Seabright/History/ClassMethods.html +0 -276
  52. data/doc/Seabright/Indices.html +0 -324
  53. data/doc/Seabright/Indices/ClassMethods.html +0 -348
  54. data/doc/Seabright/Keys.html +0 -314
  55. data/doc/Seabright/Keys/ClassMethods.html +0 -276
  56. data/doc/Seabright/ObjectBase.html +0 -852
  57. data/doc/Seabright/ObjectBase/ClassMethods.html +0 -677
  58. data/doc/Seabright/RedisObject.html +0 -230
  59. data/doc/Seabright/References.html +0 -280
  60. data/doc/Seabright/Storage.html +0 -252
  61. data/doc/Seabright/Storage/ClassMethods.html +0 -276
  62. data/doc/Seabright/Storage/MySQL.html +0 -442
  63. data/doc/Seabright/Storage/Redis.html +0 -218
  64. data/doc/Seabright/Template.html +0 -212
  65. data/doc/Seabright/Template/ClassMethods.html +0 -166
  66. data/doc/Seabright/Timestamps.html +0 -292
  67. data/doc/Seabright/Timestamps/ClassMethods.html +0 -214
  68. data/doc/Seabright/Types.html +0 -410
  69. data/doc/Seabright/Types/ClassMethods.html +0 -308
  70. data/doc/created.rid +0 -17
  71. data/doc/images/add.png +0 -0
  72. data/doc/images/brick.png +0 -0
  73. data/doc/images/brick_link.png +0 -0
  74. data/doc/images/bug.png +0 -0
  75. data/doc/images/bullet_black.png +0 -0
  76. data/doc/images/bullet_toggle_minus.png +0 -0
  77. data/doc/images/bullet_toggle_plus.png +0 -0
  78. data/doc/images/date.png +0 -0
  79. data/doc/images/delete.png +0 -0
  80. data/doc/images/find.png +0 -0
  81. data/doc/images/loadingAnimation.gif +0 -0
  82. data/doc/images/macFFBgHack.png +0 -0
  83. data/doc/images/package.png +0 -0
  84. data/doc/images/page_green.png +0 -0
  85. data/doc/images/page_white_text.png +0 -0
  86. data/doc/images/page_white_width.png +0 -0
  87. data/doc/images/plugin.png +0 -0
  88. data/doc/images/ruby.png +0 -0
  89. data/doc/images/tag_blue.png +0 -0
  90. data/doc/images/tag_green.png +0 -0
  91. data/doc/images/transparent.png +0 -0
  92. data/doc/images/wrench.png +0 -0
  93. data/doc/images/wrench_orange.png +0 -0
  94. data/doc/images/zoom.png +0 -0
  95. data/doc/index.html +0 -125
  96. data/doc/js/darkfish.js +0 -153
  97. data/doc/js/jquery.js +0 -18
  98. data/doc/js/navigation.js +0 -142
  99. data/doc/js/search.js +0 -94
  100. data/doc/js/search_index.js +0 -1
  101. data/doc/js/searcher.js +0 -228
  102. data/doc/rdoc.css +0 -543
  103. data/doc/table_of_contents.html +0 -394
@@ -2,34 +2,54 @@ module Seabright
2
2
  module Timestamps
3
3
 
4
4
  def update_timestamps
5
- return if @@time_irrelevant
5
+ # return unless self.class.time_matters?
6
6
  set(:created_at, Time.now) if !is_set?(:created_at)
7
7
  set(:updated_at, Time.now)
8
8
  end
9
9
 
10
- def mset(dat)
11
- super(dat)
12
- set(:updated_at, Time.now)
13
- end
14
-
15
- def set(k,v)
16
- super(k,v)
17
- set(:updated_at, Time.now) unless k.to_sym == :updated_at
18
- end
19
-
20
- def save
21
- super
22
- update_timestamps
23
- end
24
-
25
10
  module ClassMethods
26
11
 
27
- def time_matters_not!
28
- @@time_irrelevant = true
29
- @@sort_indices.delete(:created_at)
30
- @@sort_indices.delete(:updated_at)
12
+ def intercept_sets_for_timestamps!
13
+ return if @intercepted_sets_for_timestamps
14
+ self.class_eval do
15
+ alias_method :untimestamped_set, :set unless method_defined?(:untimestamped_set)
16
+ def set(k,v)
17
+ ret = untimestamped_set(k,v)
18
+ set(:updated_at, Time.now) unless k.to_sym == :updated_at
19
+ ret
20
+ end
21
+ alias_method :untimestamped_mset, :mset unless method_defined?(:untimestamped_mset)
22
+ def mset(dat)
23
+ ret = untimestamped_mset(dat)
24
+ set(:updated_at, Time.now)
25
+ ret
26
+ end
27
+ alias_method :untimestamped_setnx, :setnx unless method_defined?(:untimestamped_setnx)
28
+ def setnx(k,v)
29
+ ret = untimestamped_setnx(k,v)
30
+ set(:updated_at, Time.now) unless k.to_sym == :updated_at
31
+ ret
32
+ end
33
+ alias_method :untimestamped_save, :save unless method_defined?(:untimestamped_save)
34
+ def save
35
+ ret = untimestamped_save()
36
+ update_timestamps
37
+ ret
38
+ end
39
+ end
40
+ @intercepted_sets_for_timestamps = true
31
41
  end
32
42
 
43
+ # def time_matters?
44
+ # @time_irrelevant != true
45
+ # end
46
+ #
47
+ # def time_matters_not!
48
+ # @time_irrelevant = true
49
+ # sort_indices.delete(:created_at)
50
+ # sort_indices.delete(:updated_at)
51
+ # end
52
+ #
33
53
  def recently_created(num=5)
34
54
  self.indexed(:created_at,num,true)
35
55
  end
@@ -41,12 +61,13 @@ module Seabright
41
61
  end
42
62
 
43
63
  def self.included(base)
44
- @@time_irrelevant = false
64
+ # @time_irrelevant = false
45
65
  base.send(:sort_by,:created_at)
46
66
  base.send(:sort_by,:updated_at)
47
67
  base.send(:register_format,:created_at, :date)
48
68
  base.send(:register_format,:updated_at, :date)
49
69
  base.extend(ClassMethods)
70
+ base.intercept_sets_for_timestamps!
50
71
  end
51
72
 
52
73
  end
@@ -22,7 +22,12 @@ module Seabright
22
22
  end
23
23
 
24
24
  def format_date(val)
25
- val.instance_of?(DateTime) ? val : DateTime.parse(val)
25
+ begin
26
+ val.is_a?(DateTime) || val.is_a?(Date) || val.is_a?(Time) ? val : ( val.is_a?(String) ? DateTime.parse(val) : nil )
27
+ rescue StandardError => e
28
+ puts "Could not parse value as date using Date.parse. Returning nil instead. Value: #{val.inspect}\nError: #{e.inspect}" if DEBUG
29
+ nil
30
+ end
26
31
  end
27
32
 
28
33
  def score_date(val)
@@ -30,7 +35,11 @@ module Seabright
30
35
  end
31
36
 
32
37
  def format_array(val)
33
- eval val
38
+ Yajl::Parser.new(:symbolize_keys => true).parse(val)
39
+ end
40
+
41
+ def save_array(val)
42
+ Yajl::Encoder.encode(val)
34
43
  end
35
44
 
36
45
  def format_number(val)
@@ -58,72 +67,205 @@ module Seabright
58
67
  val=="true"
59
68
  end
60
69
 
61
- def score_boolean(val)
62
- val ? 1 : 0
63
- end
64
-
65
- def get(k)
66
- enforce_format(k,super(k))
70
+ def save_boolean(val)
71
+ val === true ? "true" : "false"
67
72
  end
68
73
 
69
- def mset(dat)
70
- dat.merge!(dat) {|k,v1,v2| save_format(k,v1) }
71
- super(dat)
72
- end
73
-
74
- def set(k,v)
75
- super(k,save_format(k,v))
74
+ def score_boolean(val)
75
+ val ? 1 : 0
76
76
  end
77
77
 
78
78
  module ClassMethods
79
79
 
80
80
  def date(k)
81
- field_formats[k] = :format_date
82
- score_formats[k] = :score_date
81
+ set_field_format(k, :format_date)
82
+ set_score_format(k, :score_date)
83
83
  end
84
84
 
85
85
  def number(k)
86
- field_formats[k] = :format_number
87
- score_formats[k] = :score_number
86
+ set_field_format(k, :format_number)
87
+ set_score_format(k, :score_number)
88
88
  end
89
89
  alias_method :int, :number
90
90
 
91
91
  def float(k)
92
- field_formats[k] = :format_float
93
- score_formats[k] = :score_float
92
+ set_field_format(k, :format_float)
93
+ set_score_format(k, :score_float)
94
94
  end
95
95
 
96
96
  def bool(k)
97
- field_formats[k] = :format_boolean
98
- score_formats[k] = :score_boolean
97
+ set_field_format(k, :format_boolean)
98
+ set_score_format(k, :score_boolean)
99
+ set_save_format(k, :save_boolean)
99
100
  end
100
101
  alias_method :boolean, :bool
101
102
 
102
103
  def array(k)
103
- field_formats[k] = :format_array
104
+ set_field_format(k, :format_array)
105
+ set_save_format(k, :save_array)
104
106
  end
105
107
 
106
108
  def json(k)
107
- field_formats[k] = :format_json
108
- save_formats[k] = :save_json
109
+ set_field_format(k, :format_json)
110
+ set_save_format(k, :save_json)
109
111
  end
110
112
 
111
113
  def field_formats
112
- @@field_formats ||= {}
114
+ @field_formats_hash ||= (defined?(superclass.field_formats) ? superclass.field_formats.clone : {})
113
115
  end
114
116
 
115
117
  def score_formats
116
- @@score_formats ||= {}
118
+ @score_formats_hash ||= (defined?(superclass.score_formats) ? superclass.score_formats.clone : {})
117
119
  end
118
120
 
119
121
  def save_formats
120
- @@save_formats ||= {}
122
+ @save_formats_hash ||= (defined?(superclass.save_formats) ? superclass.save_formats.clone : {})
123
+ end
124
+
125
+ def set_field_format(k, v)
126
+ field_formats_set_locally.add(k)
127
+ field_formats[k] = v
128
+ update_child_class_field_formats(k, v)
129
+ intercept_for_typing!
130
+ end
131
+
132
+ def field_formats_set_locally
133
+ @field_formats_set_locally_set ||= Set.new
134
+ end
135
+
136
+ def inherit_field_format(k, v)
137
+ unless fields_formats_set_locally.include? k
138
+ field_formats[k] = v
139
+ update_child_class_field_formats(k, v)
140
+ end
141
+ intercept_for_typing!
142
+ end
143
+
144
+ def update_child_class_field_formats(k, v)
145
+ child_classes.each do |child_class|
146
+ child_class.inherit_field_format(k, v)
147
+ end
148
+ end
149
+
150
+ def set_score_format(k, v)
151
+ score_formats_set_locally.add(k)
152
+ score_formats[k] = v
153
+ update_child_class_score_formats(k, v)
154
+ intercept_for_typing!
155
+ end
156
+
157
+ def score_formats_set_locally
158
+ @score_formats_set_locally_set ||= Set.new
159
+ end
160
+
161
+ def inherit_score_format(k, v)
162
+ unless scores_formats_set_locally.include? k
163
+ score_formats[k] = v
164
+ update_child_class_score_formats(k, v)
165
+ end
166
+ intercept_for_typing!
167
+ end
168
+
169
+ def update_child_class_score_formats(k, v)
170
+ child_classes.each do |child_class|
171
+ child_class.inherit_score_format(k, v)
172
+ end
173
+ end
174
+
175
+ def set_save_format(k, v)
176
+ save_formats_set_locally.add(k)
177
+ save_formats[k] = v
178
+ update_child_class_save_formats(k, v)
179
+ intercept_for_typing!
180
+ end
181
+
182
+ def save_formats_set_locally
183
+ @save_formats_set_locally_set ||= Set.new
184
+ end
185
+
186
+ def inherit_save_format(k, v)
187
+ unless save_formats_set_locally.include? k
188
+ save_formats[k] = v
189
+ update_child_class_save_formats(k, v)
190
+ end
191
+ intercept_for_typing!
192
+ end
193
+
194
+ def update_child_class_save_formats(k, v)
195
+ child_classes.each do |child_class|
196
+ child_class.inherit_save_format(k, v)
197
+ end
121
198
  end
122
199
 
123
200
  def register_format(k,fmt)
124
201
  send(fmt, k)
125
202
  end
126
203
 
204
+ def describe
205
+ all_keys.inject({}) do |acc,(k,v)|
206
+ if field_formats[k.to_sym]
207
+ acc[k.to_sym] ||= [field_formats[k.to_sym].to_s.gsub(/^format_/,'').to_sym, 0]
208
+ else
209
+ acc[k.to_sym] ||= [:string, 0]
210
+ end
211
+ acc[k.to_sym][1] += 1
212
+ acc
213
+ end
214
+ end
215
+
216
+ def dump_schema(file)
217
+ child_classes_set.sort {|a,b| a.name <=> b.name}.each do |child|
218
+ file.puts "# #{child.name}"
219
+ # sort fields by number of instances found
220
+ child.describe.sort {|a,b| b[1][1] <=> a[1][1]}.each do |field,(type, count)|
221
+ file.puts "#{field}: #{type} (#{count})"
222
+ end
223
+ file.puts
224
+ end
225
+ end
226
+
227
+ def intercept_for_typing!
228
+ return if @intercepted_for_typing
229
+ self.class_eval do
230
+
231
+ alias_method :untyped_get, :get unless method_defined?(:untyped_get)
232
+ def get(k)
233
+ enforce_format(k,untyped_get(k))
234
+ end
235
+
236
+ alias_method :untyped_mset, :mset unless method_defined?(:untyped_mset)
237
+ def mset(dat)
238
+ dat.merge!(dat) {|k,v1,v2| save_format(k,v1) }
239
+ untyped_mset(dat)
240
+ end
241
+
242
+ alias_method :untyped_set, :set unless method_defined?(:untyped_set)
243
+ def set(k,v)
244
+ untyped_set(k,save_format(k,v))
245
+ end
246
+
247
+ alias_method :untyped_setnx, :setnx unless method_defined?(:untyped_setnx)
248
+ def setnx(k,v)
249
+ untyped_setnx(k,save_format(k,v))
250
+ end
251
+
252
+ end
253
+ @intercepted_for_typing = true
254
+ end
255
+
256
+ private
257
+
258
+ def all_keys(limit=100)
259
+ steps = 0
260
+ all.inject([]) do |acc,obj|
261
+ store.hkeys(obj.hkey).each do |k|
262
+ acc << k.to_sym
263
+ end
264
+ steps += 1
265
+ return acc if steps >= limit
266
+ acc
267
+ end
268
+ end
127
269
  end
128
270
 
129
271
  def self.included(base)
@@ -131,4 +273,4 @@ module Seabright
131
273
  end
132
274
 
133
275
  end
134
- end
276
+ end
@@ -1,5 +1,5 @@
1
1
  module Seabright
2
2
  class RedisObject
3
- VERSION = "1.0"
3
+ VERSION = "1.1"
4
4
  end
5
5
  end
data/redis_object.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
  s.required_ruby_version = '>= 1.9.2'
22
+ s.add_dependency "utf8_utils"
22
23
  s.add_dependency "redis"
23
24
  s.add_dependency "yajl-ruby"
24
25
  s.add_dependency "activesupport"
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ module ObjectTests
4
+ class User < RedisObject
5
+ use_store :global
6
+ end
7
+ class Thingy < RedisObject
8
+
9
+ end
10
+ class Doodad < RedisObject
11
+
12
+ end
13
+ end
14
+
15
+ describe RedisObject do
16
+
17
+ it "can reconnect to redis" do
18
+ RedisObject.reconnect!
19
+ RedisObject.store.reconnect!
20
+ end
21
+
22
+ it "can dump to a file" do
23
+ obj = ObjectTests::User.create("test")
24
+ RedisObject.dump_stores_to_files("/tmp")
25
+ RedisObject.store.flushdb
26
+ end
27
+
28
+ it "can restore from a file" do
29
+ RedisObject.restore_stores_from_files("/tmp")
30
+ ObjectTests::User.find("test").should be_a(ObjectTests::User)
31
+ end
32
+
33
+ it "can get all stores" do
34
+ RedisObject.stores.count.should eq(1)
35
+ end
36
+
37
+ it "can reset stores" do
38
+ RedisObject.stores.each do |(name,store)|
39
+ store.reset
40
+ end
41
+ end
42
+
43
+ end
data/spec/base_spec.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
- DEBUG = false
4
-
5
3
  module ObjectTests
6
4
  class User < RedisObject
7
-
5
+ use_store :global
8
6
  end
9
7
  class Thingy < RedisObject
10
8
 
@@ -15,41 +13,78 @@ module ObjectTests
15
13
  end
16
14
 
17
15
  describe RedisObject do
16
+
18
17
  it "can be created" do
19
18
  obj = ObjectTests::User.new
20
19
  end
20
+
21
21
  it "can be created with an id" do
22
22
  obj = ObjectTests::User.new("test")
23
23
  obj.save
24
24
  end
25
+
26
+ it "can create an id" do
27
+ obj = ObjectTests::User.new("test")
28
+ obj.new_id
29
+ end
30
+
31
+ it "can reserve an id" do
32
+ obj = ObjectTests::User.new("test")
33
+ obj.reserve("test")
34
+ end
35
+
25
36
  it "should be found by id" do
26
37
  obj = ObjectTests::User.find("test")
27
38
  obj.should_not be_nil
28
39
  end
40
+
41
+ it "can recollect objects" do
42
+ ObjectTests::User.recollect!
43
+ end
44
+
45
+ it "get get the first object (random)" do
46
+ obj = ObjectTests::User.first
47
+ obj.should be_a(ObjectTests::User)
48
+ end
49
+
29
50
  it "should save stuff" do
30
51
  obj = ObjectTests::User.find("test")
31
52
  obj.stuff = "yay!"
32
- obj.stuff.should == "yay!"
53
+ obj[:stuff].should eq("yay!")
54
+ obj[:stuff] = "yayyay!"
55
+ obj.stuff.should eq("yayyay!")
56
+ obj.stuff = "yay!"
57
+ obj.stuff.should eq("yay!")
33
58
  end
59
+
34
60
  it "should retrieve stuff" do
35
61
  obj = ObjectTests::User.find("test")
36
- obj.stuff.should == "yay!"
62
+ obj.stuff.should eq("yay!")
37
63
  end
64
+
38
65
  it "can collect other objects" do
39
66
  obj = ObjectTests::User.find("test")
40
67
  obj2 = ObjectTests::Thingy.new("yay")
41
68
  obj << obj2
42
69
  obj.should have_collection(:thingies)
43
70
  end
71
+
44
72
  it "can reference other objects" do
45
73
  obj = ObjectTests::User.find("test")
46
74
  obj3 = ObjectTests::Doodad.new("woo")
47
75
  obj.reference obj3
48
76
  obj.should have_collection(:doodads)
49
77
  end
78
+
79
+ it "can convert raw to json" do
80
+ obj = ObjectTests::User.find("test")
81
+ obj.to_json.length.should > 0
82
+ end
83
+
50
84
  it "should be deletable" do
51
85
  obj = ObjectTests::User.find("test")
52
86
  obj.delete!
53
87
  ObjectTests::User.find("test").should be_nil
54
88
  end
55
- end
89
+
90
+ end