redis_object 0.5.0 → 1.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.
Files changed (103) hide show
  1. data/.gitignore +0 -2
  2. data/Gemfile +0 -4
  3. data/README.markdown +15 -24
  4. data/Rakefile +0 -8
  5. data/doc/Object.html +185 -0
  6. data/doc/Seabright.html +181 -0
  7. data/doc/Seabright/Adapter.html +442 -0
  8. data/doc/Seabright/Collection.html +797 -0
  9. data/doc/Seabright/Collections.html +635 -0
  10. data/doc/Seabright/Collections/ClassMethods.html +212 -0
  11. data/doc/Seabright/ExternalIndex.html +217 -0
  12. data/doc/Seabright/History.html +382 -0
  13. data/doc/Seabright/History/ClassMethods.html +276 -0
  14. data/doc/Seabright/Indices.html +324 -0
  15. data/doc/Seabright/Indices/ClassMethods.html +348 -0
  16. data/doc/Seabright/Keys.html +314 -0
  17. data/doc/Seabright/Keys/ClassMethods.html +276 -0
  18. data/doc/Seabright/ObjectBase.html +852 -0
  19. data/doc/Seabright/ObjectBase/ClassMethods.html +677 -0
  20. data/doc/Seabright/RedisObject.html +230 -0
  21. data/doc/Seabright/References.html +280 -0
  22. data/doc/Seabright/Storage.html +252 -0
  23. data/doc/Seabright/Storage/ClassMethods.html +276 -0
  24. data/doc/Seabright/Storage/MySQL.html +442 -0
  25. data/doc/Seabright/Storage/Redis.html +218 -0
  26. data/doc/Seabright/Template.html +212 -0
  27. data/doc/Seabright/Template/ClassMethods.html +166 -0
  28. data/doc/Seabright/Timestamps.html +292 -0
  29. data/doc/Seabright/Timestamps/ClassMethods.html +214 -0
  30. data/doc/Seabright/Types.html +410 -0
  31. data/doc/Seabright/Types/ClassMethods.html +308 -0
  32. data/doc/created.rid +17 -0
  33. data/doc/images/add.png +0 -0
  34. data/doc/images/brick.png +0 -0
  35. data/doc/images/brick_link.png +0 -0
  36. data/doc/images/bug.png +0 -0
  37. data/doc/images/bullet_black.png +0 -0
  38. data/doc/images/bullet_toggle_minus.png +0 -0
  39. data/doc/images/bullet_toggle_plus.png +0 -0
  40. data/doc/images/date.png +0 -0
  41. data/doc/images/delete.png +0 -0
  42. data/doc/images/find.png +0 -0
  43. data/doc/images/loadingAnimation.gif +0 -0
  44. data/doc/images/macFFBgHack.png +0 -0
  45. data/doc/images/package.png +0 -0
  46. data/doc/images/page_green.png +0 -0
  47. data/doc/images/page_white_text.png +0 -0
  48. data/doc/images/page_white_width.png +0 -0
  49. data/doc/images/plugin.png +0 -0
  50. data/doc/images/ruby.png +0 -0
  51. data/doc/images/tag_blue.png +0 -0
  52. data/doc/images/tag_green.png +0 -0
  53. data/doc/images/transparent.png +0 -0
  54. data/doc/images/wrench.png +0 -0
  55. data/doc/images/wrench_orange.png +0 -0
  56. data/doc/images/zoom.png +0 -0
  57. data/doc/index.html +125 -0
  58. data/doc/js/darkfish.js +153 -0
  59. data/doc/js/jquery.js +18 -0
  60. data/doc/js/navigation.js +142 -0
  61. data/doc/js/search.js +94 -0
  62. data/doc/js/search_index.js +1 -0
  63. data/doc/js/searcher.js +228 -0
  64. data/doc/rdoc.css +543 -0
  65. data/doc/table_of_contents.html +394 -0
  66. data/lib/redis_object.rb +1 -11
  67. data/lib/redis_object/base.rb +60 -210
  68. data/lib/redis_object/collection.rb +100 -130
  69. data/lib/redis_object/defaults.rb +8 -21
  70. data/lib/redis_object/ext/filters.rb +16 -34
  71. data/lib/redis_object/ext/triggers.rb +13 -75
  72. data/lib/redis_object/{experimental/history.rb → history.rb} +0 -0
  73. data/lib/redis_object/indices.rb +39 -44
  74. data/lib/redis_object/keys.rb +4 -4
  75. data/lib/redis_object/storage.rb +1 -30
  76. data/lib/redis_object/storage/adapter.rb +3 -6
  77. data/lib/redis_object/storage/redis.rb +3 -98
  78. data/lib/redis_object/timestamps.rb +21 -42
  79. data/lib/redis_object/types.rb +30 -172
  80. data/lib/redis_object/version.rb +1 -1
  81. data/redis_object.gemspec +0 -1
  82. data/spec/base_spec.rb +6 -41
  83. data/spec/spec_helper.rb +1 -32
  84. metadata +116 -111
  85. data/.coveralls.yml +0 -1
  86. data/.travis.yml +0 -5
  87. data/lib/redis_object/ext/script_cache.rb +0 -92
  88. data/lib/redis_object/ext/shardable.rb +0 -18
  89. data/lib/redis_object/ext/view_caching.rb +0 -258
  90. data/lib/redis_object/ext/views.rb +0 -102
  91. data/lib/redis_object/inheritance_tracking.rb +0 -23
  92. data/spec/adapter_spec.rb +0 -43
  93. data/spec/benchmark_spec.rb +0 -46
  94. data/spec/collections_spec.rb +0 -144
  95. data/spec/defaults_spec.rb +0 -56
  96. data/spec/filters_spec.rb +0 -29
  97. data/spec/indices_spec.rb +0 -45
  98. data/spec/rename_class_spec.rb +0 -96
  99. data/spec/timestamp_spec.rb +0 -28
  100. data/spec/trigger_spec.rb +0 -51
  101. data/spec/types_spec.rb +0 -103
  102. data/spec/view_caching_spec.rb +0 -130
  103. data/spec/views_spec.rb +0 -72
@@ -1 +0,0 @@
1
- repo_token: 8vq1j1WGB56M8h1zI6TeuK7x3HVJ1K8l4
@@ -1,5 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.3
4
- env:
5
- - "TEST_DB=14"
@@ -1,92 +0,0 @@
1
- $ScriptSHAMap = {}
2
-
3
- module Seabright
4
-
5
- class RedisObject
6
- module ScriptSources; end
7
- end
8
-
9
- module CachedScripts
10
-
11
- def run_script(name,keys=[],args=[],source=nil)
12
- self.class.run_script(name,keys,args,source,store)
13
- end
14
-
15
- module ClassMethods
16
-
17
- NoScriptError = "NOSCRIPT No matching script. Please use EVAL.".freeze
18
-
19
- def run_script(name,keys=[],args=[],source=nil,stor=nil)
20
- @tmp_store = stor if stor
21
- @rescue_recurse ||= 0
22
- begin
23
- out = (@tmp_store || store).evalsha(get_script_sha(name,source),keys,args)
24
- rescue Redis::CommandError => e
25
- if e.message == NoScriptError && @rescue_recurse < 3
26
- puts "Rescuing NOSCRIPT error for #{name} - running again..." if DEBUG
27
- untrack_script name
28
- @rescue_recurse += 1
29
- out = (@tmp_store || store).evalsha(get_script_sha(name,source),keys,args)
30
- else
31
- @rescue_recurse = 0
32
- raise e
33
- end
34
- end
35
- @rescue_recurse = 0
36
- remove_instance_variable(:@tmp_store) if @tmp_store
37
- out
38
- end
39
-
40
- def get_script_sha(name,source=nil)
41
- $ScriptSHAMap[name] ||= (script_sha_from_key(name) || store_script(name,source))
42
- end
43
-
44
- def script_sha_from_key(name)
45
- (@tmp_store || store).get(script_sha_key(name))
46
- end
47
-
48
- class SourceNotFoundError < RuntimeError
49
- def initialize
50
- super("Could not locate script source")
51
- end
52
- end
53
-
54
- def store_script(name,source=nil)
55
- source ||= script_source_from_const(name)
56
- raise SourceNotFoundError unless source
57
- sha = (@tmp_store || store).script(:load,source)
58
- (@tmp_store || store).set(script_sha_key(name),sha)
59
- sha
60
- end
61
-
62
- def untrack_script(name)
63
- ScriptSHAMap.delete name
64
- (@tmp_store || store).del(script_sha_key(name))
65
- end
66
-
67
- def script_source_from_const(name)
68
- (self.const_defined?(name.to_sym) && self.const_get(name.to_sym)) || (RedisObject::ScriptSources.const_defined?(name.to_sym) && RedisObject::ScriptSources.const_get(name.to_sym)) || nil
69
- end
70
-
71
- SCRIPT_KEY_PREFIX = "ScriptCache::SHA::".freeze
72
-
73
- def expire_all_script_shas(store_name=nil)
74
- store_obj = store_name.is_a?(String) || store_name.is_a?(Symbol) ? store(store_name.to_sym) : store_name
75
- store_obj.keys(script_sha_key("*")).each do |k|
76
- store_obj.del k
77
- end
78
- end
79
-
80
- def script_sha_key(name)
81
- "#{SCRIPT_KEY_PREFIX}#{name.to_s}"
82
- end
83
-
84
- end
85
-
86
- def self.included(base)
87
- base.extend(ClassMethods)
88
- end
89
-
90
- end
91
-
92
- end
@@ -1,18 +0,0 @@
1
- module Seabright
2
- module Shardable
3
-
4
- # Intention is to override any methods needed so that the underlying data can be safely sharded
5
-
6
- module ClassMethods
7
-
8
- # same here
9
-
10
- end
11
-
12
- def self.included(base)
13
- base.extend(ClassMethods)
14
- end
15
-
16
- end
17
- RedisObject.send(:include,Shardable)
18
- end
@@ -1,258 +0,0 @@
1
- # View Caching
2
- #
3
- # Cache a named view:
4
- # cache_named_view :admin_view
5
- #
6
- # Invalidate all cached views when the I receive notification that something I reference or have been referenced by has changed:
7
- # invalidate_caches_from_upstream_updates!
8
- #
9
- # Notify some objects that reference me when I am updated: (objects of these classes)
10
- # invalidate_upstream Property, Application, PaymentRequest, PaymentResponse
11
- #
12
- # Notify some objects in my collections when I am updated: (objects in these collections)
13
- # invalidate_downstream :properties, :applications, :payment_requests, :payment_responses
14
- #
15
- # You can also set up hooks for when this object is updated by certain types of objects by defining the following:
16
- # def invalidated_by(obj,chain)
17
- # invalidate_cached_view :blah
18
- # end
19
- #
20
- # def invalidated_by_user(obj,chain)
21
- # invalidate_cached_view :users
22
- # end
23
- #
24
-
25
- module Seabright
26
- module ViewCaching
27
-
28
- CachedViewInvalidator = "
29
- for i=1,#ARGV do
30
- redis.call('HDEL', KEYS[1], ARGV[i])
31
- end".gsub(/\t/,'').freeze
32
-
33
- module ClassMethods
34
-
35
- def cache_view(name,opts=true)
36
- cached_views[name.to_sym] = opts
37
- intercept_views_for_caching!
38
- set_up_invalidation!
39
- end
40
- alias_method :cache_named_view, :cache_view
41
-
42
- def intercept_views_for_caching!
43
- return if @cached_views_intercepted
44
- self.class_eval do
45
-
46
- alias_method :uncached_view_as_hash, :view_as_hash unless method_defined?(:uncached_view_as_hash)
47
- def view_as_hash(name)
48
- return uncached_view_as_hash(name) unless self.class.view_should_be_cached?(name)
49
- if v = view_from_cache(name)
50
- puts " Got view from cache: #{name}" if DEBUG
51
- Yajl::Parser.parse(v)
52
- else
53
- puts " View cache miss: #{name}" if DEBUG
54
- cache_view_content(name)[0]
55
- end
56
- end
57
-
58
- alias_method :uncached_view_as_json, :view_as_json unless method_defined?(:uncached_view_as_json)
59
- def view_as_json(name)
60
- return uncached_view_as_json(name) unless self.class.view_should_be_cached?(name)
61
- if v = view_from_cache(name)
62
- puts " Got view from cache: #{name}" if DEBUG
63
- v
64
- else
65
- puts " View cache miss: #{name}" if DEBUG
66
- cache_view_content(name)[1]
67
- end
68
- end
69
-
70
- def cache_view_content(name,content=nil)
71
- content ||= uncached_view_as_hash(name)
72
- json = Yajl::Encoder.encode(content)
73
- store.hset(cached_view_key,name,json)
74
- [content,json]
75
- end
76
-
77
- def view_from_cache(name)
78
- if v = store.hget(cached_view_key,name)
79
- v
80
- else
81
- nil
82
- end
83
- end
84
-
85
- def view_is_cached?(name)
86
- store.hexists(cached_view_key, name)
87
- end
88
-
89
- def cached_view_key
90
- "#{hkey}::ViewCache"
91
- end
92
-
93
- def regenerate_cached_views(*names)
94
- names.each do |name|
95
- cache_view_content name
96
- end
97
- end
98
-
99
- def regenerate_cached_views!
100
- regenerate_cached_views(*self.class.cached_views.map {|name,opts| name })
101
- end
102
-
103
- end
104
- @cached_views_intercepted = true
105
- end
106
-
107
- def set_up_invalidation!
108
- return if @invalidation_set_up
109
- self.class_eval do
110
-
111
- def invalidate_cached_views(*names)
112
- puts "Invalidating cached views: #{names.join(", ")}" if Debug.verbose?
113
- run_script(:CachedViewInvalidator, [cached_view_key], names, CachedViewInvalidator)
114
- self.class.cache_invalidation_hooks do |hook|
115
- hook.call(names)
116
- end
117
- end
118
- alias_method :invalidate_cached_view, :invalidate_cached_views
119
-
120
- def invalidate_cached_views!
121
- invalidate_cached_views(*self.class.cached_views.map {|name,opts| name })
122
- end
123
-
124
- def invalidate_downstream!
125
- return unless self.class.downstream_invalidations && (self.class.downstream_invalidations.size > 0)
126
- puts "Invalidating downstream: #{self.class.downstream_invalidations.inspect}" if Debug.verbose?
127
- self.class.downstream_invalidations.each do |col|
128
- if has_collection?(col) && (colctn = get_collection(col))
129
- colctn.each do |obj|
130
- obj.invalidated_by_other(self,invalidation_chain + [self.hkey])
131
- end
132
- end
133
- end
134
- end
135
-
136
- def invalidate_upstream!
137
- return unless self.class.upstream_invalidations && (self.class.upstream_invalidations.size > 0)
138
- puts "Invalidating upstream: #{self.class.upstream_invalidations.inspect}" if Debug.verbose?
139
- backreferences.each do |obj|
140
- next unless self.class.upstream_invalidations.include?(obj.class.name.split("::").last.to_sym) #|| self.class.invalidate_everything_upstream?
141
- obj.invalidated_by_other(self,invalidation_chain + [self.hkey]) if obj.respond_to?(:invalidated_by_other)
142
- end
143
- end
144
-
145
- def invalidated_by_update!(*args)
146
- Thread.new do
147
- invalidate_cached_views!
148
- invalidate_up_and_down!
149
- end
150
- end
151
-
152
- def invalidated_by_reference!(*args)
153
- invalidated_by_update!
154
- end
155
-
156
- def invalidation_chain
157
- @invalidation_chain ||= []
158
- end
159
-
160
- def invalidate_up_and_down!
161
- unless invalidation_chain.include?(self)
162
- invalidate_downstream!
163
- invalidate_upstream!
164
- end
165
- end
166
-
167
- def invalidated_by_other(obj,chain)
168
- unless chain.include?(self.hkey)
169
- puts "#{self.class.name}:#{self.id}'s view caches were invalidated by upstream object: #{obj.class.name}:#{obj.id} (chain:#{chain.inspect})" if Debug.verbose?
170
- @invalidation_chain = chain
171
- [:invalidated_by,"invalidated_by_#{obj.class.name.underscore}".to_sym].each do |meth_sym|
172
- send(meth_sym,obj,chain) if respond_to?(meth_sym)
173
- end
174
- invalidate_up_and_down!
175
- end
176
- end
177
-
178
- trigger_on_update :invalidated_by_update!
179
- trigger_on_reference :invalidated_by_reference!
180
-
181
- end
182
- @invalidation_set_up = true
183
- end
184
-
185
- def invalidate_caches_from_upstream_updates!
186
- self.class_eval do
187
-
188
- def invalidated_by(obj,chain)
189
- invalidate_cached_views!
190
- end
191
-
192
- end
193
- end
194
-
195
- def on_cache_invalidation(&block)
196
- cache_invalidation_hooks << block
197
- end
198
-
199
- def cache_invalidation_hooks
200
- @cache_invalidation_hooks ||= []
201
- end
202
-
203
- def invalidate_upstream(*args)
204
- @upstream_invalidations = (@upstream_invalidations || []) + args
205
- set_up_invalidation!
206
- end
207
-
208
- def upstream_invalidations
209
- @upstream_invalidations ||= []
210
- end
211
-
212
- # def invalidate_everything_upstream!
213
- # @invalidate_everything_upstream = true
214
- # end
215
- #
216
- # def invalidate_everything_upstream?
217
- # @invalidate_everything_upstream
218
- # end
219
-
220
- def invalidate_downstream(*args)
221
- @downstream_invalidations = (@downstream_invalidations || []) + args
222
- set_up_invalidation!
223
- end
224
-
225
- def downstream_invalidations
226
- @downstream_invalidations ||= []
227
- end
228
-
229
- # def invalidate_everything_downstream!
230
- # @invalidate_everything_downstream = true
231
- # end
232
- #
233
- # def invalidate_everything_downstream?
234
- # @invalidate_everything_downstream
235
- # end
236
-
237
- def view_should_be_cached?(name)
238
- !!cached_views[name.to_sym]
239
- end
240
-
241
- def cached_views
242
- @cached_view ||= {}
243
- end
244
-
245
- def cache_named_views!
246
- named_views.each do |name,view|
247
- cache_view name
248
- end
249
- end
250
-
251
- end
252
-
253
- def self.included(base)
254
- base.extend(ClassMethods)
255
- end
256
-
257
- end
258
- end
@@ -1,102 +0,0 @@
1
- module Seabright
2
- module Views
3
-
4
- ViewFieldGetter = "local out = {}
5
- local key
6
- local val
7
- for i=1,#ARGV do
8
- key = ARGV[i]
9
- val = redis.call('HGET',KEYS[1],key)
10
- if val then
11
- table.insert(out,key)
12
- table.insert(out,val)
13
- end
14
- end
15
- return out".gsub(/\t/,'').freeze
16
-
17
- def view_as_hash(name)
18
- out = {}
19
- if requested_set = self.class.named_views[name]
20
- if requested_set.is_a?(Symbol) and self.respond_to?(requested_set)
21
- out = send(requested_set)
22
- else
23
- methods = requested_set[:fields].select {|f| self.respond_to?(f.to_sym) }
24
- if methods.count > 0
25
- methods.each do |m|
26
- out[m.to_s] = send(m.to_sym)
27
- end
28
- end
29
- if requested_set[:fields] && (flds = requested_set[:fields].select {|f| !out.keys.include?(f.to_s) }.map {|f| f.to_s }) && flds.count > 0
30
- res = Hash[*store.eval(ViewFieldGetter, [hkey], flds)]
31
- out.merge!(res)
32
- end
33
- if requested_set[:procs]
34
- requested_set[:procs].each do |k,proc|
35
- out[k.to_s] = proc.call(self)
36
- end
37
- end
38
- if requested_set[:hashes]
39
- requested_set[:hashes].each do |k,v|
40
- case v
41
- when String, Symbol
42
- out[k.to_s] = get(v)
43
- end
44
- end
45
- end
46
- end
47
- end
48
- out
49
- end
50
-
51
- def view_as_json(name)
52
- Yajl::Encoder.encode(view_as_hash(name))
53
- end
54
-
55
- module ClassMethods
56
-
57
- def named_view(name,*fields)
58
- named_views[name] = normalize_field_options(fields)
59
- end
60
-
61
- def named_views
62
- @named_views ||= {}
63
- end
64
-
65
- def normalize_field_options(fields)
66
- fields.flatten!
67
- fields.uniq!
68
-
69
- options = {}
70
- if fields.last.is_a?(Hash) # assume an option hash
71
- options.merge!(fields.slice!(fields.size - 1, 1)[0])
72
- end
73
-
74
- # assign a the method as a symbol to be exclusively invoked on view
75
- # so instead of returning a hash on view, it will return only what was
76
- # produced by calling the method.
77
- if options.keys.size > 0 and options[:method]
78
- out = options[:method].to_sym
79
- else
80
- hash = fields.select {|f| f.is_a?(Hash) }.inject({},:merge)
81
- out = {}
82
- if (h = hash.select {|k,v| !v.is_a?(Proc) }) && h.count > 0
83
- out[:hashes] = h
84
- end
85
- if (h = hash.select {|k,v| v.is_a?(Proc) }) && h.count > 0
86
- out[:procs] = h
87
- end
88
- if (h = fields.select {|o| o.is_a?(String) || o.is_a?(Symbol) }) && h.count > 0
89
- out[:fields] = h
90
- end
91
- end
92
- out
93
- end
94
-
95
- end
96
-
97
- def self.included(base)
98
- base.extend(ClassMethods)
99
- end
100
-
101
- end
102
- end