redis_object 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
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
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ repo_token: 8vq1j1WGB56M8h1zI6TeuK7x3HVJ1K8l4
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .DS_Store
3
4
  Gemfile.lock
4
5
  pkg/*
6
+ coverage/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ env:
5
+ - "TEST_DB=14"
data/Gemfile CHANGED
@@ -1,4 +1,8 @@
1
1
  source "http://rubygems.org"
2
2
 
3
+ gem 'rake'
4
+ gem 'rspec'
5
+ gem 'coveralls', require: false
6
+
3
7
  # Specify your gem's dependencies in redis_object.gemspec
4
8
  gemspec
data/README.markdown CHANGED
@@ -1,14 +1,20 @@
1
1
  # RedisObject
2
2
  RedisObject is a fast and simple-to-use object persistence layer for Ruby.
3
3
 
4
+ [![Build Status](https://travis-ci.org/remotezygote/RedisObject.png?branch=master)](https://travis-ci.org/remotezygote/RedisObject)
5
+ [![Coverage Status](https://coveralls.io/repos/remotezygote/RedisObject/badge.png?branch=master)](https://coveralls.io/r/remotezygote/RedisObject?branch=master)
6
+
4
7
  ## Prerequisites
5
- You'll need [Redis](http://redis.io).
8
+ You'll need [Redis](http://redis.io). Other storage adapters are in the works. Maybe.
6
9
 
7
10
 
8
11
  ## Installation
9
- It's hosted on [rubygems.org][rubygems].
10
12
 
11
- sudo gem install redis_object
13
+ gem install redis_object
14
+
15
+ Or, you can add it to your Gemfile:
16
+
17
+ gem 'redis_object'
12
18
 
13
19
 
14
20
  ## Usage
@@ -51,7 +57,7 @@ end
51
57
  ## 'Collections'
52
58
  Object relationships are stored in collections of objects attached to other objects. To 'collect' an object onto another, you simply call `reference` to reference the objects (also aliased to the concat operator `<<`).
53
59
 
54
- Collections are automatically created, and can be access by their plural, lower-case name to gather all of the items in a collection (returns and Enumerable `Collection` object), or by its singular lower-case name to just get one somewhat randomly (useful for 1 -> 1 style relationships).
60
+ Collections are automatically created, and can be access by their plural, lower-case name to gather all of the items in a collection (returns an Enumerable `Collection` object), or by its singular lower-case name to just get one somewhat randomly (useful for 1 -> 1 style relationships).
55
61
 
56
62
  Example:
57
63
 
@@ -82,19 +88,19 @@ john.address
82
88
  # }
83
89
  ```
84
90
 
85
- You may also notice that the type of object, its basic storage key, and some timestamps are also automatically created and updated appropriately.
91
+ You may notice that the type of object, its basic storage key, and some timestamps are automatically created and updated appropriately.
86
92
 
87
93
  It is important to note that collections inherit any indices of its underlying object type. See Indices below for examples.
88
94
 
89
95
  ## Types
90
96
  A few types of data can be specified for certain fields. The types supported are:
91
97
 
92
- Date
93
- Number
94
- Float
95
- Bool
96
- Array
97
- JSON (store any data that can be JSON-encoded - it will be automatically encoded/decoded when stored/accessed)
98
+ * Date
99
+ * Number
100
+ * Float
101
+ * Bool
102
+ * Array
103
+ * JSON (store any data that can be JSON-encoded - it will be automatically encoded/decoded when stored/accessed)
98
104
 
99
105
  These types are also used for scoring when keeping field indices. If no type is specified, String is used, and no scoring is possible at this time.
100
106
 
@@ -113,7 +119,7 @@ john.verified # false
113
119
 
114
120
  TODO: Add verified? and verified! -style methods automagically for boolean fields.
115
121
 
116
- You can also add your own custom types by defining filter methods for getting and setting a field, and can also define a scoring function if you would like to index fields of the type.
122
+ You can add your own custom types by defining filter methods for getting and setting a field, and can define a scoring function if you would like to index fields of your type.
117
123
 
118
124
  Example:
119
125
 
@@ -148,7 +154,7 @@ end
148
154
  TODO: Make defining custom formats easier - no need to define class methods for this - could have helper function for it like `custom_format :bool, :get => :format_boolean` or similar.
149
155
 
150
156
  ## Indices
151
- Any field that can be scored can store a sidecar index by that score. These indices can also be used to index items in a collection (internally, it is a simple Redis set intersection, so it is very fast). Timestamps are indexed by default for any object, so out of the box you can do:
157
+ Any field that can be scored can store a sidecar index by that score. These indices can be used to index items in a collection (internally, it is a simple Redis set intersection, so it is very fast). Timestamps are indexed by default for any object, so out of the box you can do:
152
158
 
153
159
  ```ruby
154
160
  Person.indexed(:created_at) # all Person objects, oldest first
@@ -160,11 +166,14 @@ Person.indexed(:updated_at, -1, true) do |person|
160
166
  end
161
167
  ```
162
168
 
163
- Accessing indexed items always returns an Enumerator, so first/last/each/count/etc. are always usable and will access items only when iterated.
169
+ Accessing indexed items always returns an Enumerator, so first/last/each/count/etc. are usable anywhere and will access objects only when iterated.
170
+
171
+ ## Named Views
172
+ `TODO: Add some damn View documentation.`
164
173
 
165
174
  ## Links
166
175
  Redis: [http://redis.io](http://redis.io)
167
176
  RedisObject Code: [https://github.com/remotezygote/RedisObject](https://github.com/remotezygote/RedisObject)
168
177
 
169
178
 
170
- [rubygems]: http://rubygems.org/gems/redis_object
179
+ [rubygems]: http://rubygems.org/gems/redis_object
data/Rakefile CHANGED
@@ -1,2 +1,10 @@
1
1
  require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :spec
5
+
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.pattern = './spec/*_spec.rb'
8
+ end
9
+
2
10
  Bundler::GemHelper.install_tasks
data/lib/redis_object.rb CHANGED
@@ -4,7 +4,9 @@ require 'yajl'
4
4
 
5
5
  require "redis_object/storage"
6
6
 
7
+ require "redis_object/ext/script_cache"
7
8
  require "redis_object/base"
9
+ require "redis_object/inheritance_tracking"
8
10
  require "redis_object/storage"
9
11
  require "redis_object/keys"
10
12
  require "redis_object/types"
@@ -12,20 +14,28 @@ require "redis_object/defaults"
12
14
  require "redis_object/collection"
13
15
  require "redis_object/indices"
14
16
  require "redis_object/timestamps"
15
- require "redis_object/history"
17
+ require "redis_object/experimental/history"
18
+ require "redis_object/ext/views"
19
+ require "redis_object/ext/view_caching"
16
20
  require "redis_object/ext/triggers"
21
+ require "redis_object/ext/filters"
17
22
  require "redis_object/ext/benchmark"
18
23
 
19
24
  module Seabright
20
25
  class RedisObject
21
26
 
27
+ include Seabright::Filters
22
28
  include Seabright::ObjectBase
29
+ include Seabright::InheritanceTracking
30
+ include Seabright::CachedScripts
23
31
  include Seabright::Storage
24
32
  include Seabright::Keys
25
33
  include Seabright::Types
26
34
  include Seabright::DefaultValues
27
35
  include Seabright::Collections
28
36
  include Seabright::Indices
37
+ include Seabright::Views
38
+ include Seabright::ViewCaching
29
39
  include Seabright::Timestamps
30
40
  include Seabright::History
31
41
  include Seabright::Triggers
@@ -3,11 +3,11 @@ module Seabright
3
3
 
4
4
  def initialize(ident={})
5
5
  if ident && (ident.class == String || (ident.class == Symbol && (ident = ident.to_s)))# && ident.gsub!(/.*:/,'') && ident.length > 0
6
- load(ident)
6
+ load(ident.dup)
7
7
  elsif ident && ident.class == Hash
8
8
  ident[id_sym] ||= generate_id
9
9
  if load(ident[id_sym])
10
- mset(ident)
10
+ mset(ident.dup)
11
11
  end
12
12
  end
13
13
  self
@@ -18,33 +18,17 @@ module Seabright
18
18
  end
19
19
 
20
20
  def generate_id
21
- v = new_id
22
- while self.class.exists?(v) do
23
- puts "[RedisObject] Collision at id: #{v}" if Debug.verbose?
24
- v = new_id
25
- end
26
- puts "[RedisObject] Reserving key: #{v}" if Debug.verbose?
27
- reserve(v)
28
- v
21
+ self.class.generate_id
29
22
  end
30
23
 
31
24
  def reserve(k)
32
- store.set(reserve_key(k),Time.now.to_s)
25
+ self.class.reserve(k)
33
26
  end
34
27
 
35
28
  def to_json
36
29
  Yajl::Encoder.encode(actual)
37
30
  end
38
31
 
39
- def dump
40
- require "utf8_utils"
41
- out = ["puts \"Creating: #{id}\""]
42
- s_id = id.gsub(/\W/,"_")
43
- out << "a#{s_id} = #{self.class.cname}.new(#{actual.to_s.tidy_bytes})"
44
- out << "a#{s_id}.save"
45
- out.join("\n")
46
- end
47
-
48
32
  def id
49
33
  @id || get(id_sym) || set(id_sym, generate_id)
50
34
  end
@@ -58,7 +42,7 @@ module Seabright
58
42
  set(:class, self.class.name)
59
43
  set(id_sym,id.gsub(/.*:/,''))
60
44
  set(:key, key)
61
- store.sadd(self.class.cname.pluralize, key)
45
+ store.sadd(self.class.plname, key)
62
46
  store.del(reserve_key)
63
47
  end
64
48
 
@@ -79,7 +63,7 @@ module Seabright
79
63
  def dereference_all!
80
64
 
81
65
  end
82
-
66
+
83
67
  def raw
84
68
  store.hgetall(hkey).inject({}) {|acc,(k,v)| acc[k.to_sym] = enforce_format(k,v); acc }
85
69
  end
@@ -87,74 +71,163 @@ module Seabright
87
71
  alias_method :actual, :raw
88
72
 
89
73
  def get(k)
90
- store.hget(hkey, k.to_s)
74
+ cached_hash_values[k.to_s] ||= Proc.new {|key|
75
+ if v = store.hget(hkey, key.to_s)
76
+ define_setter_getter(key)
77
+ end
78
+ v
79
+ }.call(k)
80
+ end
81
+
82
+ def [](k)
83
+ get(k)
91
84
  end
92
- alias_method :[], :get
93
85
 
94
86
  def is_set?(k)
95
87
  store.hexists(hkey, k.to_s)
96
88
  end
97
89
 
98
90
  def mset(dat)
99
- # dat.each do |k,v|
100
- # set(k,v)
101
- # end
102
91
  store.hmset(hkey, *(dat.inject([]){|acc,(k,v)| acc + [k,v] }))
92
+ cached_hash_values.merge!(dat)
93
+ dat.each do |k,v|
94
+ define_setter_getter(k)
95
+ end
103
96
  dat
104
97
  end
105
98
 
99
+ def define_setter_getter(key)
100
+ define_access(key) do
101
+ get(key)
102
+ end
103
+ define_access("#{key.to_s}=") do |val|
104
+ set(key,val)
105
+ end
106
+ end
107
+
108
+ def undefine_setter_getter(key)
109
+ undefine_access(key)
110
+ undefine_access("#{key.to_s}=")
111
+ end
112
+
106
113
  def set(k,v)
107
- store.hset(hkey, k.to_s.gsub(/\=$/,''), v)
114
+ store.hset(hkey, k.to_s, v.to_s)
115
+ cached_hash_values[k.to_s] = v
116
+ define_setter_getter(k)
108
117
  v
109
118
  end
110
- alias_method :[]=, :set
111
119
 
112
- def unset(k)
113
- store.hdel(hkey, k.to_s)
120
+ def setnx(k,v)
121
+ if success = store.hsetnx(hkey, k.to_s, v.to_s)
122
+ cached_hash_values[k.to_s] = v
123
+ define_setter_getter(k)
124
+ end
125
+ success
126
+ end
127
+
128
+ def []=(k,v)
129
+ set(k,v)
114
130
  end
115
131
 
116
132
  def unset(*k)
117
- store.hdel(hkey,*k)
133
+ store.hdel(hkey, k.map(&:to_s))
134
+ k.each do |ky|
135
+ cached_hash_values.delete ky.to_s
136
+ undefine_setter_getter(ky)
137
+ end
118
138
  end
119
- # alias_method :delete, :unset
120
139
 
121
140
  private
122
141
 
142
+ SetPattern = /=$/.freeze
143
+
123
144
  def method_missing(sym, *args, &block)
124
- sym.to_s =~ /=$/ ? set(sym,*args) : get(sym)
145
+ super if sym == :class
146
+ if sym.to_s =~ SetPattern
147
+ return super if args.size > 1
148
+ set(sym.to_s.gsub(SetPattern,'').to_sym,*args)
149
+ else
150
+ return super if !args.empty?
151
+ get(sym)
152
+ end
153
+ end
154
+
155
+ def id_sym(cls=self.class.cname)
156
+ "#{cls.split('::').last.downcase}_id".to_sym
125
157
  end
126
158
 
127
- def id_sym(cls=nil)
128
- "#{(cls || self.class.cname).split('::').last.downcase}_id".to_sym
159
+ def load_all_hash_values
160
+ @cached_hash_values = store.hgetall(hkey)
161
+ cached_hash_values.keys.dup.each do |key|
162
+ next if key == "class"
163
+ define_setter_getter(key)
164
+ end
165
+ end
166
+
167
+ def cached_hash_values
168
+ @cached_hash_values ||= {}
169
+ end
170
+
171
+ def define_access(key,&block)
172
+ return if self.respond_to?(key.to_sym)
173
+ metaclass = class << self; self; end
174
+ metaclass.send(:define_method, key.to_sym, &block)
175
+ end
176
+
177
+ def undefine_access(key)
178
+ return unless self.respond_to?(key.to_sym)
179
+ metaclass = class << self; self; end
180
+ metaclass.send(:remove_method, key.to_sym)
129
181
  end
130
182
 
131
183
  module ClassMethods
132
184
 
185
+ def generate_id
186
+ v = new_id
187
+ while exists?(v) do
188
+ puts "[RedisObject] Collision at id: #{v}" if Debug.verbose?
189
+ v = new_id
190
+ end
191
+ puts "[RedisObject] Reserving key: #{v}" if Debug.verbose?
192
+ reserve(v)
193
+ v
194
+ end
195
+
196
+ def reserve(k)
197
+ store.set(reserve_key(k),Time.now.to_s)
198
+ end
199
+
133
200
  def new_id(complexity = 8)
134
201
  rand(36**complexity).to_s(36)
135
202
  end
136
203
 
137
204
  def cname
138
- @cname = self.name.split('::').last
205
+ self.name
139
206
  end
140
207
 
141
208
  def plname
142
- @plname ||= cname.pluralize
209
+ cname.pluralize
143
210
  end
144
211
 
145
212
  def all
146
213
  Enumerator.new do |y|
147
214
  store.smembers(plname).each do |member|
148
- if a = RedisObject.find_by_key(hkey(member))
215
+ if a = find_by_key(hkey(member))
149
216
  y << a
150
217
  else
151
218
  puts "[#{name}] Object listed but not found: #{member}" if DEBUG
152
- # store.srem(plname,member)
219
+ store.srem(plname,member)
153
220
  end
154
221
  end
155
222
  end
156
223
  end
157
224
 
225
+ def recollect!
226
+ store.keys("#{name}:*_h").each do |ky|
227
+ store.sadd(plname,ky.gsub(/_h$/,''))
228
+ end
229
+ end
230
+
158
231
  def first
159
232
  if m = store.smembers(plname)
160
233
  self.grab(m.first)
@@ -169,25 +242,95 @@ module Seabright
169
242
  end
170
243
  end
171
244
 
245
+ RedisObject::ScriptSources::Matcher = "local itms = redis.call('SMEMBERS',KEYS[1])
246
+ local out = {}
247
+ local val
248
+ local pattern
249
+ for i, v in ipairs(itms) do
250
+ val = redis.call('HGET',v..'_h',ARGV[1])
251
+ if ARGV[2]:find('^pattern:') then
252
+ pattern = ARGV[2]:gsub('^pattern:','')
253
+ if val:match(pattern) ~= nil then
254
+ table.insert(out,itms[i])
255
+ end
256
+ else
257
+ if val == ARGV[2] then
258
+ table.insert(out,itms[i])
259
+ end
260
+ end
261
+ end
262
+ return out".gsub(/\t/,'').freeze
263
+
264
+ RedisObject::ScriptSources::MultiMatcher = "local itms = redis.call('SMEMBERS',KEYS[1])
265
+ local out = {}
266
+ local matchers = {}
267
+ local matcher = {}
268
+ local mod
269
+ for i=1,#ARGV do
270
+ mod = i % 2
271
+ if mod == 1 then
272
+ matcher[1] = ARGV[i]
273
+ else
274
+ matcher[2] = ARGV[i]
275
+ table.insert(matchers,matcher)
276
+ matcher = {}
277
+ end
278
+ end
279
+ local val
280
+ local good
281
+ local pattern
282
+ for i, v in ipairs(itms) do
283
+ good = true
284
+ for n=1,#matchers do
285
+ val = redis.call('HGET',v..'_h',matchers[n][1])
286
+ if val then
287
+ if matchers[n][2]:find('^pattern:') then
288
+ pattern = matchers[n][2]:gsub('^pattern:','')
289
+ if val:match(pattern) then
290
+ good = good
291
+ else
292
+ good = false
293
+ end
294
+ else
295
+ if val ~= matchers[n][2] then
296
+ good = false
297
+ end
298
+ end
299
+ else
300
+ good = false
301
+ end
302
+ end
303
+ if good == true then
304
+ table.insert(out,itms[i])
305
+ end
306
+ end
307
+ return out".gsub(/\t/,'').freeze
308
+
172
309
  def match(pkt)
173
310
  Enumerator.new do |y|
174
- each do |i|
175
- if pkt.map {|hk,va| i.get(hk)==va }.all?
176
- y << i
177
- end
311
+ run_script(pkt.keys.count > 1 ? :MultiMatcher : :Matcher,[plname],pkt.flatten.map{|i| i.is_a?(Regexp) ? convert_regex_to_lua(i) : i.to_s }).each do |k|
312
+ y << find(k)
178
313
  end
179
314
  end
180
315
  end
181
316
 
317
+ def convert_regex_to_lua(reg)
318
+ "pattern:#{reg.source.gsub("\\","")}"
319
+ end
320
+
182
321
  def grab(ident)
183
- if ident.class == String
184
- return store.exists(self.hkey(ident)) ? self.new(ident) : nil
185
- elsif ident.class == Hash
322
+ case ident
323
+ when String, Symbol
324
+ return store.exists(self.hkey(ident.to_s)) ? self.new(ident.to_s) : nil
325
+ when Hash
186
326
  return match(ident)
187
327
  end
188
328
  nil
189
329
  end
190
- alias_method :find, :grab
330
+
331
+ def find(ident)
332
+ grab(ident)
333
+ end
191
334
 
192
335
  def exists?(k)
193
336
  store.exists(self.hkey(k)) || store.exists(self.reserve_key(k))
@@ -199,13 +342,13 @@ module Seabright
199
342
  obj
200
343
  end
201
344
 
202
- def dump
203
- out = []
204
- each do |obj|
205
- out << obj.dump
206
- end
207
- out.join("\n")
208
- end
345
+ # def dump
346
+ # out = []
347
+ # each do |obj|
348
+ # out << obj.dump
349
+ # end
350
+ # out.join("\n")
351
+ # end
209
352
 
210
353
  def use_dbnum(db=0)
211
354
  @dbnum = db
@@ -217,8 +360,7 @@ module Seabright
217
360
 
218
361
  def find_by_key(k)
219
362
  if store.exists(k) && (cls = store.hget(k,:class))
220
- o_id = store.hget(k,id_sym(cls))
221
- return deep_const_get(cls.to_sym).new(o_id)
363
+ return deep_const_get(cls.to_sym).new(store.hget(k,id_sym(cls)))
222
364
  end
223
365
  nil
224
366
  end
@@ -244,8 +386,16 @@ module Seabright
244
386
  true
245
387
  end
246
388
 
247
- def id_sym(cls=nil)
248
- "#{(cls || cname).split('::').last.downcase}_id".to_sym
389
+ def id_sym(cls=cname)
390
+ "#{cls.split('::').last.downcase}_id".to_sym
391
+ end
392
+
393
+ def describe
394
+ all_keys.inject({}) do |acc,(k,v)|
395
+ acc[k.to_sym] ||= [:string, 0]
396
+ acc[k.to_sym][1] += 1
397
+ acc
398
+ end
249
399
  end
250
400
 
251
401
  end
@@ -255,4 +405,4 @@ module Seabright
255
405
  end
256
406
 
257
407
  end
258
- end
408
+ end