poro 0.1.0 → 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.
- data/README.rdoc +25 -0
- data/lib/poro.rb +1 -0
- data/lib/poro/context.rb +5 -5
- data/lib/poro/context_factories/single_store/mongo_factory.rb +1 -1
- data/lib/poro/contexts/mongo_context.rb +76 -3
- data/lib/poro/version.rb +7 -0
- metadata +6 -5
data/README.rdoc
CHANGED
@@ -22,6 +22,11 @@ through whatever inferior homogenized API Poro may try to provide.
|
|
22
22
|
|
23
23
|
= Installation
|
24
24
|
|
25
|
+
At this time, Poro has only ever been tested on ruby 1.9.2. It is expected to
|
26
|
+
work on any 1.9.x, but may require some effort to make work on 1.8.6 or later.
|
27
|
+
By version 1.0 I hope to have 1.8.6 and 1.8.7 support, however the development
|
28
|
+
of a production worthy gem in 1.9.2 takes the priority.
|
29
|
+
|
25
30
|
Basic usage only requires the installation of the gem:
|
26
31
|
gem install poro
|
27
32
|
However to utilize any meaningful persistence data store, the underlying gems
|
@@ -155,6 +160,13 @@ mailto:jeff@paploo.net
|
|
155
160
|
|
156
161
|
= Version History
|
157
162
|
|
163
|
+
[0.1.1 - 2010-Sep-24] Minor Additions and Bug Fixes.
|
164
|
+
* MongoContext now can optionally encode Symbols as hashes
|
165
|
+
or just leave them as strings.
|
166
|
+
* MongoContext can have conversion to BSON::ObjectId turned off.
|
167
|
+
* MongoContext can save Sets in various formats.
|
168
|
+
* MongoContext handles namespaced models better.
|
169
|
+
* Context doesn't error when trying to find by id.
|
158
170
|
[0.1.0 - 2010-Sep-18] Initial public release.
|
159
171
|
* Major base functionality is complete, though is subject
|
160
172
|
to big changes as it is used in the real world.
|
@@ -167,7 +179,18 @@ mailto:jeff@paploo.net
|
|
167
179
|
|
168
180
|
The following are the primary TODO items, roughly in priority order:
|
169
181
|
|
182
|
+
* YAML Connection Configuration:
|
183
|
+
* Make a Util module that is able to use a rails-compatible YAML
|
184
|
+
file--given by path--to get the elements needed for configuration of a
|
185
|
+
SingleStore factory.
|
186
|
+
* Modify SingleStore to use this file for configuration when appropriate.
|
170
187
|
* Modelify: Break into modules for each piece of functionality.
|
188
|
+
* Modelify: Add callback functionality to Modelify (e.g. before/after save, after initialize).
|
189
|
+
* Add the callbacks to the Context first.
|
190
|
+
* Mongo Context: Add option to encode Sets as one of:
|
191
|
+
* A Set with the raw internal Hash.
|
192
|
+
* A Set with the internal Hash as an Array.
|
193
|
+
* An Array (which will have to be manually turned back into a Set).
|
171
194
|
* Specs: Add specs for Context Find methods.
|
172
195
|
* Check that private methods are private. (Should do on subclasses too.)
|
173
196
|
* Check that the two main find methods pass through to the correct underlying
|
@@ -176,6 +199,8 @@ The following are the primary TODO items, roughly in priority order:
|
|
176
199
|
* Mongo Context: Split into modules in separate files.
|
177
200
|
* Context: Split out modules into files.
|
178
201
|
* Contexts: Add SQL Context.
|
202
|
+
* Ruby: Verify support for ruby 1.9.x.
|
203
|
+
* Ruby: Evaluate adding support for ruby 1.8.6 and 1.8.7.
|
179
204
|
|
180
205
|
= License
|
181
206
|
|
data/lib/poro.rb
CHANGED
data/lib/poro/context.rb
CHANGED
@@ -316,7 +316,7 @@ module Poro
|
|
316
316
|
#
|
317
317
|
# Subclasses SHOULD override this method.
|
318
318
|
#
|
319
|
-
# By default, this method aggregates separate calls to
|
319
|
+
# By default, this method aggregates separate calls to fetch. For
|
320
320
|
# most data stores this makes N calls to the server, decreasing performance.
|
321
321
|
#
|
322
322
|
# When possible, this method should be overriden by subclasses to be more
|
@@ -324,7 +324,7 @@ module Poro
|
|
324
324
|
# filtered by the <tt>clean_id</tt> private method.
|
325
325
|
def find_with_ids(*ids)
|
326
326
|
ids = ids.flatten
|
327
|
-
return ids.map {|id|
|
327
|
+
return ids.map {|id| fetch(id)}
|
328
328
|
end
|
329
329
|
|
330
330
|
end
|
@@ -423,7 +423,7 @@ module Poro
|
|
423
423
|
elsif( arg.respond_to?(:map) )
|
424
424
|
return find_with_ids(arg)
|
425
425
|
else
|
426
|
-
return
|
426
|
+
return fetch(arg)
|
427
427
|
end
|
428
428
|
end
|
429
429
|
|
@@ -440,9 +440,9 @@ module Poro
|
|
440
440
|
# * :first or :one
|
441
441
|
def data_store_find(first_or_all, *args, &block)
|
442
442
|
if(first_or_all == :all || first_or_all == :many)
|
443
|
-
return data_store_find_all(*
|
443
|
+
return data_store_find_all(*args, &block)
|
444
444
|
elsif( first_or_all == :first || first_or_all == :one)
|
445
|
-
return data_store_find_first(*
|
445
|
+
return data_store_find_first(*args, &block)
|
446
446
|
else
|
447
447
|
raise ArgumentError, "#{__method__} expects the first argument to be one of :all, :many, :first, or :one."
|
448
448
|
end
|
@@ -22,7 +22,7 @@ module Poro
|
|
22
22
|
raise ArgumentError, "No mongo connection was supplied to #{self.class.name}." if @connection.nil?
|
23
23
|
|
24
24
|
super() do |klass|
|
25
|
-
collection_name = Util::Inflector.pluralize(Util::Inflector.underscore(klass.name.to_s))
|
25
|
+
collection_name = Util::Inflector.pluralize(Util::Inflector.underscore(klass.name.to_s)).gsub('/', '_')
|
26
26
|
context = Contexts::MongoContext.new(klass)
|
27
27
|
context.data_store = @connection[collection_name]
|
28
28
|
yield(klass, context) if block_given?
|
@@ -45,6 +45,12 @@ module Poro
|
|
45
45
|
@persistent_attributes_whitelist = nil
|
46
46
|
@persistent_attributes_blacklist = nil
|
47
47
|
|
48
|
+
# Some configuration variables
|
49
|
+
@encode_symbols = false
|
50
|
+
@attempt_id_conversion = true
|
51
|
+
@set_encoding_method = :embedded_array
|
52
|
+
|
53
|
+
|
48
54
|
# Initialize
|
49
55
|
super(klass)
|
50
56
|
end
|
@@ -62,6 +68,27 @@ module Poro
|
|
62
68
|
attr_reader :persistent_attributes_blacklist
|
63
69
|
attr_writer :persistent_attributes_blacklist
|
64
70
|
|
71
|
+
# If true, it encodes Symbol as a hash with a class name property, and
|
72
|
+
# then decodes them back into Symbol. If false, it converts them to
|
73
|
+
# String for storage. Defaults to false.
|
74
|
+
#
|
75
|
+
# While one would think they want to preserve the type of the saved element,
|
76
|
+
# the change in storage method makes it harder to write Mongo queries on the
|
77
|
+
# data. Thus it is normally best to save symbols as strings for storage.
|
78
|
+
attr_reader :encode_symbols
|
79
|
+
attr_writer :encode_symbols
|
80
|
+
|
81
|
+
# Normally, one uses BSON::ObjectId instances for the IDs on a stored
|
82
|
+
# Mongo object. However, one can design a database to use many different
|
83
|
+
# values as sthe primary key.
|
84
|
+
#
|
85
|
+
# When this is set to true, fetch tries to convert the given ID into a
|
86
|
+
# BSON::ObjectId before doing a fetch. If the conversion fails, it tries using
|
87
|
+
# the raw value given. If this is set to false, then it always passes
|
88
|
+
# along the raw value, skipping the conversion step.
|
89
|
+
attr_reader :attempt_id_conversion
|
90
|
+
attr_writer :attempt_id_conversion
|
91
|
+
|
65
92
|
def fetch(id)
|
66
93
|
data = data_store.find_one( clean_id(id) )
|
67
94
|
return convert_to_plain_object(data)
|
@@ -94,9 +121,8 @@ module Poro
|
|
94
121
|
private
|
95
122
|
|
96
123
|
def clean_id(id)
|
97
|
-
#TODO: Make the attempted transform configurable; mongo doesn't require an ObjectId as the key.
|
98
124
|
# Attempt to convert to an ObjectID if it looks like it should be.
|
99
|
-
if( !(id.kind_of?(BSON::ObjectId)) && BSON::ObjectId.legal?(id.to_s) )
|
125
|
+
if( self.attempt_id_conversion && !(id.kind_of?(BSON::ObjectId)) && BSON::ObjectId.legal?(id.to_s) )
|
100
126
|
id = BSON::ObjectId.from_string(id.to_s)
|
101
127
|
end
|
102
128
|
return id
|
@@ -123,6 +149,7 @@ module Poro
|
|
123
149
|
obj.kind_of?(Float) ||
|
124
150
|
obj.kind_of?(String) ||
|
125
151
|
obj.kind_of?(Time) ||
|
152
|
+
(self.encode_symbols && obj.kind_of?(Symbol)) ||
|
126
153
|
obj==true ||
|
127
154
|
obj==false ||
|
128
155
|
obj.nil? ||
|
@@ -178,6 +205,10 @@ module Poro
|
|
178
205
|
return encode_array(obj)
|
179
206
|
elsif( obj.kind_of?(Class) )
|
180
207
|
return encode_class(obj)
|
208
|
+
elsif( obj.kind_of?(Set) )
|
209
|
+
return encode_set(obj)
|
210
|
+
elsif( !self.encode_symbols && obj.kind_of?(Symbol) )
|
211
|
+
return encode_symbol(obj)
|
181
212
|
elsif( Context.managed_class?(obj.class) && Context.fetch(obj.class).kind_of?(self.class) )
|
182
213
|
return encode_mongo_managed_object(obj)
|
183
214
|
elsif( Context.managed_class?(obj.class))
|
@@ -207,6 +238,23 @@ module Poro
|
|
207
238
|
return {'_class_name' => klass.class, 'name' => klass.name}
|
208
239
|
end
|
209
240
|
|
241
|
+
# Encodes a symbol.
|
242
|
+
def encode_symbol(sym)
|
243
|
+
return {'_class_name' => 'Symbol', 'value' => sym.to_s}
|
244
|
+
end
|
245
|
+
|
246
|
+
# Encodes a Set as either :raw, :embedded_array, :array.
|
247
|
+
def encode_set(set)
|
248
|
+
method = @set_encoding_method
|
249
|
+
if( method == :raw )
|
250
|
+
return encode_unmanaged_object(set)
|
251
|
+
elsif( method == :embedded_array )
|
252
|
+
return {'_class_name' => 'Set', 'values' => self.convert_to_data(set.to_a, :embedded => true)}
|
253
|
+
else
|
254
|
+
return self.convert_to_data(set.to_a, :embedded => true)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
210
258
|
# Encode a hash that came from a DBRef dereferenced and decoded by this context.
|
211
259
|
#
|
212
260
|
# This will save the hash when its owning object is saved!
|
@@ -294,6 +342,10 @@ module Poro
|
|
294
342
|
class_name = data['_class_name'].to_s
|
295
343
|
if( class_name == 'Class' )
|
296
344
|
return decode_class(data)
|
345
|
+
elsif( class_name == 'Symbol' )
|
346
|
+
return decode_symbol(data)
|
347
|
+
elsif( class_name == 'Set' )
|
348
|
+
return decode_set(data)
|
297
349
|
elsif( class_name == self.klass.to_s )
|
298
350
|
return decode_self_managed_object(data)
|
299
351
|
elsif( class_name && data['managed'] )
|
@@ -321,6 +373,27 @@ module Poro
|
|
321
373
|
return Util::ModuleFinder.find(class_data['name'])
|
322
374
|
end
|
323
375
|
|
376
|
+
# Decode a symbol reference. If this users of the Context expect a Symbol
|
377
|
+
# to be encoded as a Symbol, then decode it as a Symbol. Otherwise the
|
378
|
+
# users of the Context wil be expecting a String.
|
379
|
+
def decode_symbol(symbol_data)
|
380
|
+
if self.encode_symbols
|
381
|
+
return symbol_data['value'].to_sym
|
382
|
+
else
|
383
|
+
return symbol_data['value'].to_s
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
# Decode the set depending on if it was encoded as an array or as a raw
|
388
|
+
# object.
|
389
|
+
def decode_set(set_data)
|
390
|
+
if( set_data.include?['values'] )
|
391
|
+
return Set.new(set_data['values'])
|
392
|
+
else
|
393
|
+
return decode_unmanaged_object(set_data)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
324
397
|
# Decode a BSON::DBRef. If there is a context for the reference, it is
|
325
398
|
# wrapped in that object type. If there is no context, it is left as
|
326
399
|
# a DBRef so that it will re-save as a DBRef (otherwise it'll save as a
|
@@ -438,7 +511,7 @@ module Poro
|
|
438
511
|
end
|
439
512
|
|
440
513
|
def data_store_find_all(*args, &block)
|
441
|
-
return data_store.find(*args, &block).to_a.map {|
|
514
|
+
return data_store.find(*args, &block).to_a.map {|doc| self.convert_to_plain_object(doc)}
|
442
515
|
end
|
443
516
|
|
444
517
|
def data_store_find_first(*args, &block)
|
data/lib/poro/version.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Poro is a lightweight persistence engine that can use many different data stores
|
2
|
+
# to persist information. Poro takes a hands-off approach, attempting to change
|
3
|
+
# existing plain ol' ruby objects as little as possible. For more information
|
4
|
+
# see README.rdoc.
|
5
|
+
module Poro
|
6
|
+
VERSION = '0.1.1'
|
7
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jeff Reinecke
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-09-
|
17
|
+
date: 2010-09-24 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -47,6 +47,7 @@ files:
|
|
47
47
|
- lib/poro/util/inflector.rb
|
48
48
|
- lib/poro/util/module_finder.rb
|
49
49
|
- lib/poro/util.rb
|
50
|
+
- lib/poro/version.rb
|
50
51
|
- lib/poro.rb
|
51
52
|
- spec/context_factory_spec.rb
|
52
53
|
- spec/context_spec.rb
|
@@ -60,7 +61,7 @@ files:
|
|
60
61
|
has_rdoc: true
|
61
62
|
homepage: http://www.github.com/paploo/poro
|
62
63
|
licenses:
|
63
|
-
-
|
64
|
+
- BSD
|
64
65
|
post_install_message:
|
65
66
|
rdoc_options: []
|
66
67
|
|
@@ -90,6 +91,6 @@ rubyforge_project:
|
|
90
91
|
rubygems_version: 1.3.7
|
91
92
|
signing_key:
|
92
93
|
specification_version: 3
|
93
|
-
summary: A lightweight thin persistence engine that can utilize many different persistence
|
94
|
+
summary: A lightweight thin persistence engine that can utilize many different persistence data stores.
|
94
95
|
test_files: []
|
95
96
|
|