rhubarb 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/rhubarb/classmixins.rb +62 -15
- data/lib/rhubarb/persistence.rb +11 -2
- data/lib/rhubarb/persisting.rb +5 -0
- data/lib/rhubarb/util.rb +17 -8
- data/rhubarb.gemspec +66 -0
- data/ruby-rhubarb.spec.in +12 -3
- data/test/test_rhubarb.rb +49 -10
- metadata +7 -7
- data/.gitignore +0 -21
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/rhubarb/classmixins.rb
CHANGED
@@ -13,10 +13,19 @@
|
|
13
13
|
require 'rhubarb/mixins/freshness'
|
14
14
|
|
15
15
|
module Rhubarb
|
16
|
+
# Forward declaration
|
17
|
+
module Persistence; end
|
18
|
+
|
16
19
|
# Methods mixed in to the class object of a persisting class
|
17
|
-
module PersistingClassMixins
|
18
|
-
|
19
|
-
|
20
|
+
module PersistingClassMixins
|
21
|
+
if ::Rhubarb::Persistence::sqlite_13
|
22
|
+
PCM_INPUT_TRANSFORMERS = {:blob=>Util.blobify_proc, :zblob=>Util.zblobify_proc, :object=>Util.swizzle_object_proc, :boolean=>Util.truthify_proc}
|
23
|
+
PCM_OUTPUT_TRANSFORMERS = {:object=>Util.deswizzle_object_proc, :zblob=>Util.dezblobify_proc, :string=>Proc.new {|v| v.to_s}}
|
24
|
+
else
|
25
|
+
PCM_INPUT_TRANSFORMERS = {:blob=>Util.blobify_proc, :zblob=>Util.zblobify_proc, :object=>Util.swizzle_object_proc}
|
26
|
+
PCM_OUTPUT_TRANSFORMERS = {:object=>Util.deswizzle_object_proc, :zblob=>Util.dezblobify_proc}
|
27
|
+
end
|
28
|
+
|
20
29
|
# Returns the name of the database table modeled by this class.
|
21
30
|
# Defaults to the name of the class (sans module names)
|
22
31
|
def table_name(quoted=false)
|
@@ -56,16 +65,38 @@ module Rhubarb
|
|
56
65
|
|
57
66
|
alias find_by_id find
|
58
67
|
|
59
|
-
def
|
68
|
+
def find_by_sqlite13(arg_hash)
|
60
69
|
results = []
|
61
70
|
arg_hash = arg_hash.dup
|
62
71
|
valid_cols = self.colnames.intersection arg_hash.keys
|
63
72
|
select_criteria = valid_cols.map {|col| "#{col.to_s} = #{col.inspect}"}.join(" AND ")
|
64
|
-
arg_hash.each
|
73
|
+
arg_hash.each do |key,val|
|
74
|
+
arg_hash[key] = val.row_id if val.respond_to? :row_id
|
75
|
+
xform = PCM_INPUT_TRANSFORMERS[colkinds[key]]
|
76
|
+
arg_hash[key] = xform.call(val) if xform
|
77
|
+
end
|
78
|
+
db.do_query("select * from #{quoted_table_name} where #{select_criteria} order by row_id", arg_hash) {|tup| results << self.new(tup) }
|
79
|
+
results
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_by_sqlite12(arg_hash)
|
83
|
+
results = []
|
84
|
+
arg_hash = arg_hash.dup
|
85
|
+
valid_cols = self.colnames.intersection arg_hash.keys
|
86
|
+
select_criteria = valid_cols.map {|col| "#{col.to_s} = #{col.inspect}"}.join(" AND ")
|
87
|
+
arg_hash.each do |key,val|
|
88
|
+
arg_hash[key] = val.row_id if val.respond_to? :row_id
|
89
|
+
end
|
65
90
|
db.do_query("select * from #{quoted_table_name} where #{select_criteria} order by row_id", arg_hash) {|tup| results << self.new(tup) }
|
66
91
|
results
|
67
92
|
end
|
68
93
|
|
94
|
+
if ::Rhubarb::Persistence::sqlite_13
|
95
|
+
alias find_by find_by_sqlite13
|
96
|
+
else
|
97
|
+
alias find_by find_by_sqlite12
|
98
|
+
end
|
99
|
+
|
69
100
|
# Does what it says on the tin. Since this will allocate an object for each row, it isn't recomended for huge tables.
|
70
101
|
def find_all
|
71
102
|
results = []
|
@@ -147,16 +178,32 @@ module Rhubarb
|
|
147
178
|
# add a find for this column (a class method)
|
148
179
|
klass = (class << self; self end)
|
149
180
|
klass.class_eval do
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
181
|
+
if ::Rhubarb::Persistence::sqlite_13
|
182
|
+
define_method find_method_name do |arg|
|
183
|
+
results = []
|
184
|
+
arg = Util.rhubarb_fk_identity(arg)
|
185
|
+
db.do_query(find_query, arg) {|row| results << self.new(row)}
|
186
|
+
results
|
187
|
+
end
|
188
|
+
|
189
|
+
define_method find_first_method_name do |arg|
|
190
|
+
result = nil
|
191
|
+
arg = Util.rhubarb_fk_identity(arg)
|
192
|
+
db.do_query(find_query, arg) {|row| result = self.new(row) ; break }
|
193
|
+
result
|
194
|
+
end
|
195
|
+
else
|
196
|
+
define_method find_method_name do |arg|
|
197
|
+
results = []
|
198
|
+
db.do_query(find_query, arg) {|row| results << self.new(row)}
|
199
|
+
results
|
200
|
+
end
|
201
|
+
|
202
|
+
define_method find_first_method_name do |arg|
|
203
|
+
result = nil
|
204
|
+
db.do_query(find_query, arg) {|row| result = self.new(row) ; break }
|
205
|
+
result
|
206
|
+
end
|
160
207
|
end
|
161
208
|
end
|
162
209
|
|
data/lib/rhubarb/persistence.rb
CHANGED
@@ -51,7 +51,7 @@ module Rhubarb
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
if @use_prepared_stmts
|
54
|
+
if @use_prepared_stmts && Rhubarb::Persistence::prepared_ok
|
55
55
|
class << db
|
56
56
|
include UsePreparedStatements
|
57
57
|
end
|
@@ -65,6 +65,15 @@ module Rhubarb
|
|
65
65
|
|
66
66
|
@dbs = DbCollection.new
|
67
67
|
|
68
|
+
def self.prepared_ok
|
69
|
+
!!sqlite_13
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.sqlite_13
|
73
|
+
result = SQLite3.constants.include?("VERSION") && SQLite3::VERSION =~ /1\.3\.[0-9]+/
|
74
|
+
!!result
|
75
|
+
end
|
76
|
+
|
68
77
|
def self.open(filename, which=:default, usePrepared=true)
|
69
78
|
dbs.use_prepared_stmts = usePrepared
|
70
79
|
dbs[which] = SQLite3::Database.new(filename)
|
@@ -91,4 +100,4 @@ module Rhubarb
|
|
91
100
|
@dbs
|
92
101
|
end
|
93
102
|
end
|
94
|
-
end
|
103
|
+
end
|
data/lib/rhubarb/persisting.rb
CHANGED
@@ -55,6 +55,11 @@ module Rhubarb
|
|
55
55
|
@backed = true
|
56
56
|
@tuple = tup
|
57
57
|
mark_fresh
|
58
|
+
|
59
|
+
unless @tuple.is_a?(Hash)
|
60
|
+
@tuple = Hash[*self.class.columns.map{|c| c.name}.zip(tup).flatten]
|
61
|
+
end
|
62
|
+
|
58
63
|
@row_id = @tuple["row_id"]
|
59
64
|
@created = @tuple["created"]
|
60
65
|
@updated = @tuple["updated"]
|
data/lib/rhubarb/util.rb
CHANGED
@@ -24,7 +24,11 @@ module Rhubarb
|
|
24
24
|
|
25
25
|
# Identity for objects that may be used as foreign keys
|
26
26
|
def self.rhubarb_fk_identity(object)
|
27
|
-
(object.
|
27
|
+
(object.class.ancestors.include?(Persisting) || object.class.ancestors.include?(Rhubarb::Persisting)) ? object.row_id : object
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.truthify_proc
|
31
|
+
@truthify_proc ||= Proc.new {|obj| !!(obj) ? "true" : "false"}
|
28
32
|
end
|
29
33
|
|
30
34
|
def self.blobify_proc
|
@@ -37,8 +41,11 @@ module Rhubarb
|
|
37
41
|
|
38
42
|
def self.dezblobify_proc
|
39
43
|
@dezblobify_proc ||= Proc.new do |obj|
|
40
|
-
|
41
|
-
|
44
|
+
if obj.nil? || obj == ""
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
Zlib::Inflate.inflate(obj)
|
48
|
+
end
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
@@ -51,11 +58,13 @@ module Rhubarb
|
|
51
58
|
|
52
59
|
def self.deswizzle_object_proc
|
53
60
|
@deswizzle_object_proc ||= Proc.new do |zy_obj|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
61
|
+
if zy_obj.nil? || zy_obj == ""
|
62
|
+
nil
|
63
|
+
else
|
64
|
+
obj = YAML.load(Zlib::Inflate.inflate(zy_obj))
|
65
|
+
obj.freeze
|
66
|
+
end
|
58
67
|
end
|
59
68
|
end
|
60
69
|
end
|
61
|
-
end
|
70
|
+
end
|
data/rhubarb.gemspec
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rhubarb}
|
8
|
+
s.version = "0.4.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["William Benton"]
|
12
|
+
s.date = %q{2011-07-06}
|
13
|
+
s.description = %q{Rhubarb is a simple object-graph persistence library implemented as a mixin. It also works with the SPQR library for straightforward object publishing over QMF.}
|
14
|
+
s.email = %q{willb@redhat.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc",
|
18
|
+
"TODO"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
"CHANGES",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"TODO",
|
27
|
+
"VERSION",
|
28
|
+
"lib/rhubarb/classmixins.rb",
|
29
|
+
"lib/rhubarb/column.rb",
|
30
|
+
"lib/rhubarb/mixins/freshness.rb",
|
31
|
+
"lib/rhubarb/persistence.rb",
|
32
|
+
"lib/rhubarb/persisting.rb",
|
33
|
+
"lib/rhubarb/reference.rb",
|
34
|
+
"lib/rhubarb/rhubarb.rb",
|
35
|
+
"lib/rhubarb/util.rb",
|
36
|
+
"rhubarb.gemspec",
|
37
|
+
"ruby-rhubarb.spec.in",
|
38
|
+
"test/helper.rb",
|
39
|
+
"test/test_rhubarb.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://git.fedorahosted.org/git/grid/rhubarb.git}
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.3.7}
|
44
|
+
s.summary = %q{Rhubarb: object graph persistence, easy as pie}
|
45
|
+
s.test_files = [
|
46
|
+
"test/helper.rb",
|
47
|
+
"test/test_rhubarb.rb"
|
48
|
+
]
|
49
|
+
|
50
|
+
if s.respond_to? :specification_version then
|
51
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
52
|
+
s.specification_version = 3
|
53
|
+
|
54
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
56
|
+
s.add_runtime_dependency(%q<sqlite3-ruby>, [">= 1.2.2"])
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
59
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.2"])
|
60
|
+
end
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
63
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 1.2.2"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/ruby-rhubarb.spec.in
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
%{!?ruby_sitelib: %global ruby_sitelib %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"] ')}
|
2
|
-
%define rel
|
2
|
+
%define rel 3
|
3
3
|
|
4
4
|
Summary: Simple versioned object-graph persistence layer
|
5
5
|
Name: ruby-rhubarb
|
@@ -29,8 +29,8 @@ instances of specially-declared Ruby classes in a SQLite3 database
|
|
29
29
|
rm -rf %{buildroot}
|
30
30
|
mkdir -p %{buildroot}/%{ruby_sitelib}/rhubarb
|
31
31
|
mkdir -p %{buildroot}/%{ruby_sitelib}/rhubarb/mixins
|
32
|
-
cp -f lib/rhubarb/mixins/*.rb %{buildroot}/%{ruby_sitelib}/rhubarb/mixins
|
33
|
-
cp -f lib/rhubarb/*.rb %{buildroot}/%{ruby_sitelib}/rhubarb
|
32
|
+
cp -p -f lib/rhubarb/mixins/*.rb %{buildroot}/%{ruby_sitelib}/rhubarb/mixins
|
33
|
+
cp -p -f lib/rhubarb/*.rb %{buildroot}/%{ruby_sitelib}/rhubarb
|
34
34
|
|
35
35
|
%clean
|
36
36
|
rm -rf %{buildroot}
|
@@ -48,6 +48,15 @@ rm -rf %{buildroot}
|
|
48
48
|
%{ruby_sitelib}/rhubarb/persistence.rb
|
49
49
|
|
50
50
|
%changelog
|
51
|
+
* Mon Jun 6 2011 willb <willb@redhat> - 0.3.0-3
|
52
|
+
- installation now preserves file modification times
|
53
|
+
|
54
|
+
* Mon Mar 14 2011 willb <willb@redhat> - 0.3.0-2
|
55
|
+
- fix for object output transformers
|
56
|
+
|
57
|
+
* Tue Feb 15 2011 willb <willb@redhat> - 0.3.0-1
|
58
|
+
- fixed bzs 674432, 674433, 677807
|
59
|
+
|
51
60
|
* Wed Sep 15 2010 willb <willb@redhat> - 0.2.7-1
|
52
61
|
- Updated to version 0.2.7
|
53
62
|
- fixed problems with hash-valued params in custom queries
|
data/test/test_rhubarb.rb
CHANGED
@@ -15,7 +15,16 @@ require 'helper'
|
|
15
15
|
require 'fileutils'
|
16
16
|
|
17
17
|
Customer = Struct.new(:name, :address)
|
18
|
+
SQLITE_13 = ::Rhubarb::Persistence::sqlite_13
|
19
|
+
CONSTRAINT_EXCEPTION = SQLITE_13 ? SQLite3::ConstraintException : SQLite3::SQLException
|
18
20
|
|
21
|
+
BFB_MAX = 512
|
22
|
+
|
23
|
+
class ParityTest
|
24
|
+
include Rhubarb::Persisting
|
25
|
+
declare_column :number, :integer
|
26
|
+
declare_column :parity, :boolean
|
27
|
+
end
|
19
28
|
|
20
29
|
class TestClass
|
21
30
|
include Rhubarb::Persisting
|
@@ -138,13 +147,13 @@ class Order
|
|
138
147
|
declare_column :group, :int
|
139
148
|
end
|
140
149
|
|
141
|
-
class
|
150
|
+
class NoPreparedStmtBackendTests < Test::Unit::TestCase
|
142
151
|
def dbfile
|
143
152
|
ENV['RHUBARB_TEST_DB'] || ":memory:"
|
144
153
|
end
|
145
154
|
|
146
155
|
def use_prepared
|
147
|
-
|
156
|
+
false
|
148
157
|
end
|
149
158
|
|
150
159
|
def setup
|
@@ -168,7 +177,7 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
|
|
168
177
|
klasses << ObjectTestTable
|
169
178
|
klasses << RhubarbNamespace::NMTC
|
170
179
|
klasses << RhubarbNamespace::NMTC2
|
171
|
-
|
180
|
+
klasses << ParityTest
|
172
181
|
klasses.each { |klass| klass.create_table }
|
173
182
|
|
174
183
|
@flist = []
|
@@ -178,6 +187,34 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
|
|
178
187
|
Rhubarb::Persistence::close()
|
179
188
|
end
|
180
189
|
|
190
|
+
def test_boolean_find_by
|
191
|
+
# believe me, I chuckled while writing this
|
192
|
+
bit_parity = Proc.new do |k|
|
193
|
+
k.to_s(2).split("0").join.size.even?
|
194
|
+
end
|
195
|
+
|
196
|
+
expected_numbers = Set.new
|
197
|
+
|
198
|
+
BFB_MAX.times do |i|
|
199
|
+
ParityTest.create(:number=>i, :parity=>bit_parity.call(i))
|
200
|
+
expected_numbers << i
|
201
|
+
end
|
202
|
+
|
203
|
+
even = ParityTest.find_by(:parity=>true)
|
204
|
+
odd = ParityTest.find_by(:parity=>false)
|
205
|
+
|
206
|
+
assert_equal(BFB_MAX, even.size+odd.size)
|
207
|
+
{even=>true, odd=>false}.each do |collection, par|
|
208
|
+
collection.each do |pt|
|
209
|
+
assert_equal(bit_parity.call(pt.number), pt.parity)
|
210
|
+
assert_equal(par, pt.parity)
|
211
|
+
expected_numbers.delete(pt.number)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
assert_equal(0, expected_numbers.size)
|
216
|
+
end
|
217
|
+
|
181
218
|
def test_reserved_word_table
|
182
219
|
assert_nothing_raised do
|
183
220
|
Create.create_table
|
@@ -514,9 +551,9 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
|
|
514
551
|
|
515
552
|
result = TestClass.find_by_foo(2)
|
516
553
|
tc = result[0]
|
517
|
-
|
518
|
-
|
519
|
-
|
554
|
+
assert_equal(1, result.size, "TestClass.find_by_foo(2) should return exactly one result")
|
555
|
+
assert_equal(2, tc.foo, "tc.foo (found by foo) should have the value 2")
|
556
|
+
assert_equal("argh", tc.bar, "tc.bar (found by foo) should have the value \"argh\"")
|
520
557
|
end
|
521
558
|
|
522
559
|
def test_create_and_find_first_by_foo
|
@@ -653,7 +690,7 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
|
|
653
690
|
end
|
654
691
|
|
655
692
|
def test_referential_integrity
|
656
|
-
assert_raise
|
693
|
+
assert_raise CONSTRAINT_EXCEPTION do
|
657
694
|
FromRef.create(:t => 42)
|
658
695
|
end
|
659
696
|
|
@@ -981,8 +1018,10 @@ class PreparedStmtBackendTests < Test::Unit::TestCase
|
|
981
1018
|
end
|
982
1019
|
end
|
983
1020
|
|
984
|
-
|
985
|
-
|
986
|
-
|
1021
|
+
unless SQLITE_13
|
1022
|
+
class PreparedStmtBackendTests < NoPreparedStmtBackendTests
|
1023
|
+
def use_prepared
|
1024
|
+
true
|
1025
|
+
end
|
987
1026
|
end
|
988
1027
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rhubarb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- William Benton
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-07-06 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -62,7 +62,6 @@ extra_rdoc_files:
|
|
62
62
|
- TODO
|
63
63
|
files:
|
64
64
|
- .document
|
65
|
-
- .gitignore
|
66
65
|
- CHANGES
|
67
66
|
- LICENSE
|
68
67
|
- README.rdoc
|
@@ -77,6 +76,7 @@ files:
|
|
77
76
|
- lib/rhubarb/reference.rb
|
78
77
|
- lib/rhubarb/rhubarb.rb
|
79
78
|
- lib/rhubarb/util.rb
|
79
|
+
- rhubarb.gemspec
|
80
80
|
- ruby-rhubarb.spec.in
|
81
81
|
- test/helper.rb
|
82
82
|
- test/test_rhubarb.rb
|
@@ -85,8 +85,8 @@ homepage: http://git.fedorahosted.org/git/grid/rhubarb.git
|
|
85
85
|
licenses: []
|
86
86
|
|
87
87
|
post_install_message:
|
88
|
-
rdoc_options:
|
89
|
-
|
88
|
+
rdoc_options: []
|
89
|
+
|
90
90
|
require_paths:
|
91
91
|
- lib
|
92
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|