rhubarb 0.3.0 → 0.4.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.
- 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
|