veneer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.textile +138 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/datamapper_setup.rb +2 -0
- data/lib/veneer.rb +35 -0
- data/lib/veneer/adapters/activerecord.rb +2 -0
- data/lib/veneer/adapters/activerecord/class_wrapper.rb +90 -0
- data/lib/veneer/adapters/activerecord/instance_wrapper.rb +11 -0
- data/lib/veneer/adapters/datamapper.rb +2 -0
- data/lib/veneer/adapters/datamapper/class_wrapper.rb +54 -0
- data/lib/veneer/adapters/datamapper/instance_wrapper.rb +23 -0
- data/lib/veneer/base/class_wrapper.rb +53 -0
- data/lib/veneer/base/conditional.rb +77 -0
- data/lib/veneer/base/instance_wrapper.rb +38 -0
- data/lib/veneer/core_ext/kernel.rb +17 -0
- data/lib/veneer/errors.rb +9 -0
- data/lib/veneer/proxy.rb +4 -0
- data/test/macros/class_wrapper/create_macro.rb +54 -0
- data/test/macros/class_wrapper/delete_macro.rb +31 -0
- data/test/macros/class_wrapper/find_macro.rb +112 -0
- data/test/macros/instance_wrapper/destroy_macro.rb +36 -0
- data/test/macros/instance_wrapper/new_record_macro.rb +35 -0
- data/test/macros/instance_wrapper/save_macro.rb +55 -0
- data/test/macros/veneer_constants_interface.rb +26 -0
- data/test/support/helpers.rb +18 -0
- data/test/test_helper.rb +16 -0
- data/test/veneer/adapters/active_record/active_record_setup.rb +28 -0
- data/test/veneer/adapters/active_record/class_wrapper_test.rb +21 -0
- data/test/veneer/adapters/active_record/instance_wrapper_test.rb +21 -0
- data/test/veneer/adapters/datamapper/class_wrapper_test.rb +22 -0
- data/test/veneer/adapters/datamapper/datamapper_setup.rb +25 -0
- data/test/veneer/adapters/datamapper/instance_wrapper_test.rb +21 -0
- data/test/veneer/base/conditonal_test.rb +118 -0
- data/test/veneer/proxy_test.rb +190 -0
- data/veneer.gemspec +95 -0
- metadata +109 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Daniel Neighman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
h1. veneer
|
2
|
+
|
3
|
+
Veneer is an interface that sits above Data Sources.
|
4
|
+
It differs from ActiveModel in that it doesn't require errors or validations or anything like that.
|
5
|
+
Veneer instead aims to provide a simple interface for
|
6
|
+
* querying
|
7
|
+
* creating
|
8
|
+
* saving
|
9
|
+
* deleting
|
10
|
+
|
11
|
+
h2. Creating and Saving an instance
|
12
|
+
|
13
|
+
To create an instance of an object wrap the class in a vaneer call and create or get a new instance.
|
14
|
+
|
15
|
+
<pre><code>obj = Veneer(MyModel).new(:some => "attribute")
|
16
|
+
obj.save
|
17
|
+
|
18
|
+
# OR
|
19
|
+
|
20
|
+
obj = Veneer(MyModel).create(:some => "attribute")
|
21
|
+
</code></pre>
|
22
|
+
|
23
|
+
There are also version that will raise exceptions
|
24
|
+
|
25
|
+
<pre><code>obj = Veneer(MyModel).new(:some => "attribute").save!
|
26
|
+
|
27
|
+
# OR
|
28
|
+
|
29
|
+
obj = Veneer(MyModel).create!(:some => "attribute")
|
30
|
+
</code></pre>
|
31
|
+
|
32
|
+
h2. Deleting
|
33
|
+
|
34
|
+
You can delete all the instances of a model or a single instance.
|
35
|
+
|
36
|
+
<pre><code>Veneer(MyModel).destroy_all # delete all instances
|
37
|
+
|
38
|
+
@some_veneer_model.destroy
|
39
|
+
</code></pre>
|
40
|
+
|
41
|
+
h2. Queries
|
42
|
+
|
43
|
+
Veneer lets you query models with a simple interface. Only simple queries are supported.
|
44
|
+
|
45
|
+
You can query a single object, or multiple objects.
|
46
|
+
|
47
|
+
<pre><code>Veneer(MyModel).all(:conditions => {:name => "foo"})
|
48
|
+
|
49
|
+
Veneer(MyModel).all(:conditions => {"age gte" => 18}, :limit => 5)
|
50
|
+
</code></pre>
|
51
|
+
|
52
|
+
The supported options are:
|
53
|
+
|
54
|
+
* :limit
|
55
|
+
* :offset
|
56
|
+
* :order
|
57
|
+
* :conditions
|
58
|
+
|
59
|
+
h3. Limit & Offset
|
60
|
+
|
61
|
+
The :limit option will limit the number of returned results.
|
62
|
+
|
63
|
+
The :offset option, when set to an integer x will begin the results at the xth result.
|
64
|
+
|
65
|
+
h3. Order
|
66
|
+
|
67
|
+
Ordering should be set as a string. By default, the order is decending.
|
68
|
+
|
69
|
+
The format of the string is:
|
70
|
+
|
71
|
+
<pre><code>"<field> (<directon>), <field> (direction), ..."
|
72
|
+
|
73
|
+
# eg
|
74
|
+
Veneer(MyModel).all(:order => "name, age desc")
|
75
|
+
</code></pre>
|
76
|
+
|
77
|
+
h3. Conditions
|
78
|
+
|
79
|
+
Conditions are a very simple set of conditions on the fields of the model. The for of the conditions are:
|
80
|
+
|
81
|
+
<pre><code>:conditions => {"field operator" => value}</code></pre>
|
82
|
+
|
83
|
+
The supported operators are
|
84
|
+
|
85
|
+
* eql
|
86
|
+
* not
|
87
|
+
* lt (less than)
|
88
|
+
* lte (less than or equal to)
|
89
|
+
* gt (greater than)
|
90
|
+
* gte (greater than or equal to)
|
91
|
+
* in (in an array)
|
92
|
+
|
93
|
+
By default, the operator is set to eql
|
94
|
+
|
95
|
+
<pre><code>
|
96
|
+
Veneer(MyModel).all(:conditions => {"name in" => ["fred", "barney"], "age gte" => 18})
|
97
|
+
Veneer(MyModel).first(:conditions => {:name => "fred"})
|
98
|
+
</code></pre>
|
99
|
+
|
100
|
+
The results of a query are all wrapped as Veneer instances.
|
101
|
+
|
102
|
+
h3. All Together
|
103
|
+
|
104
|
+
<pre><code>Veneer(MyModel).all(:order => "name, age asc", :limit => 5, :offset => 15, :conditions => {"name not" => "betty", "age lt" => 18})
|
105
|
+
</code></pre>
|
106
|
+
|
107
|
+
h2. Object methods
|
108
|
+
|
109
|
+
All methods that aren't found on the adapter, are passed through to the instance. So to access any attributes on the actual model instance, just call the method on it.
|
110
|
+
|
111
|
+
h2. Current Support
|
112
|
+
|
113
|
+
Veneer currently has built in support for ActiveRecord and DataMapper.
|
114
|
+
|
115
|
+
Veneer works on a VeneerInterface inner module though so you can easily impelment you're adapter without requireing it to be in the veneer repo (although pull requests are welcome)
|
116
|
+
|
117
|
+
To use DataMapper or ActiveRecord
|
118
|
+
|
119
|
+
<pre><code>
|
120
|
+
require 'veneer/adapters/activerecord'
|
121
|
+
require 'veneer/adapters/datamapper'
|
122
|
+
</code></pre>
|
123
|
+
|
124
|
+
|
125
|
+
== Note on Patches/Pull Requests
|
126
|
+
|
127
|
+
* Fork the project.
|
128
|
+
* Make your feature addition or bug fix.
|
129
|
+
* Add tests for it. This is important so I don't break it in a
|
130
|
+
future version unintentionally.
|
131
|
+
* Commit, do not mess with rakefile, version, or history.
|
132
|
+
(if you want to have your own version, that is fine but
|
133
|
+
bump version in a commit by itself I can ignore when I pull)
|
134
|
+
* Send me a pull request. Bonus points for topic branches.
|
135
|
+
|
136
|
+
== Copyright
|
137
|
+
|
138
|
+
Copyright (c) 2009 Daniel Neighman. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "veneer"
|
8
|
+
gem.summary = %Q{A thin veneer over data stores}
|
9
|
+
gem.description = %Q{Veneer provides basic querying, saving, deleteing and creating of data stores.}
|
10
|
+
gem.email = "has.sox@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/hassox/veneer"
|
12
|
+
gem.authors = ["Daniel Neighman"]
|
13
|
+
gem.rubyforge_project = "veneer"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
17
|
+
rubyforge.doc_task = "rdoc"
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
#require 'spec/rake/spectask'
|
24
|
+
#Spec::Rake::SpecTask.new(:spec) do |spec|
|
25
|
+
# spec.libs << 'lib' << 'spec'
|
26
|
+
# spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
#end
|
28
|
+
#
|
29
|
+
#Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
# spec.libs << 'lib' << 'spec'
|
31
|
+
# spec.pattern = 'spec/**/*_spec.rb'
|
32
|
+
# spec.rcov = true
|
33
|
+
#end
|
34
|
+
#
|
35
|
+
#task :spec => :check_dependencies
|
36
|
+
#
|
37
|
+
#task :default => :spec
|
38
|
+
|
39
|
+
task :default => [:test_units]
|
40
|
+
require 'rake/testtask'
|
41
|
+
desc "Run test suite."
|
42
|
+
Rake::TestTask.new("test"){ |test|
|
43
|
+
test.pattern = "test/*_test.rb"
|
44
|
+
test.verbose = true
|
45
|
+
test.warning = true
|
46
|
+
test.libs << "test"
|
47
|
+
test.test_files = FileList["test/test*.rb", "test/**/*_test.rb"]
|
48
|
+
}
|
49
|
+
|
50
|
+
task :test => :check_dependencies
|
51
|
+
|
52
|
+
require 'rake/rdoctask'
|
53
|
+
Rake::RDocTask.new do |rdoc|
|
54
|
+
if File.exist?('VERSION')
|
55
|
+
version = File.read('VERSION')
|
56
|
+
else
|
57
|
+
version = ""
|
58
|
+
end
|
59
|
+
|
60
|
+
rdoc.rdoc_dir = 'rdoc'
|
61
|
+
rdoc.title = "veneer #{version}"
|
62
|
+
rdoc.rdoc_files.include('README*')
|
63
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
64
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/datamapper_setup.rb
ADDED
data/lib/veneer.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/core_ext/hash'
|
2
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), "lib"))
|
3
|
+
|
4
|
+
require 'veneer/core_ext/kernel'
|
5
|
+
|
6
|
+
unless defined?(BasicObject)
|
7
|
+
begin
|
8
|
+
require 'blankslate'
|
9
|
+
::BasicObject = BlankSlate
|
10
|
+
class BasicObject
|
11
|
+
def ==(other)
|
12
|
+
object_id == other.object_id
|
13
|
+
end
|
14
|
+
|
15
|
+
def equal?(other)
|
16
|
+
object_id == other.object_id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
rescue => e
|
20
|
+
puts "Please install builder: gem install builder"
|
21
|
+
raise e.class, e.message, e.backtrace
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Veneer
|
26
|
+
autoload :Errors, 'veneer/errors'
|
27
|
+
autoload :Proxy, 'veneer/proxy'
|
28
|
+
autoload :Conditional, 'veneer/base/conditional'
|
29
|
+
|
30
|
+
module Base
|
31
|
+
autoload :ClassWrapper, 'veneer/base/class_wrapper'
|
32
|
+
autoload :InstanceWrapper, 'veneer/base/instance_wrapper'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
module VeneerInterface
|
4
|
+
class ClassWrapper < Veneer::Base::ClassWrapper
|
5
|
+
def new(opts = {})
|
6
|
+
::Kernel::Veneer(klass.new(opts))
|
7
|
+
end
|
8
|
+
|
9
|
+
def destroy_all
|
10
|
+
klass.destroy_all
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_first(conditional)
|
14
|
+
opts = conditional_to_ar_opts(conditional)
|
15
|
+
klass.find(:first, opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_many(conditional)
|
19
|
+
opts = conditional_to_ar_opts(conditional)
|
20
|
+
klass.find(:all,opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def conditional_to_ar_opts(c)
|
25
|
+
opts = {}
|
26
|
+
opts[:limit] = c.limit if c.limit
|
27
|
+
opts[:offset] = c.offset if c.offset
|
28
|
+
|
29
|
+
unless c.order.blank?
|
30
|
+
opts[:order] = c.order.inject([]) do |ary, cnd|
|
31
|
+
ary << "#{cnd.field} #{cnd.direction}"
|
32
|
+
end.join(",")
|
33
|
+
end
|
34
|
+
|
35
|
+
unless c.conditions.blank?
|
36
|
+
val_array = []
|
37
|
+
cnds = c.conditions.inject([]) do |ary, cd|
|
38
|
+
case cd.operator
|
39
|
+
when :eql
|
40
|
+
if cd.value.nil?
|
41
|
+
ary << "#{cd.field} IS ?"
|
42
|
+
else
|
43
|
+
ary << "#{cd.field} = ?"
|
44
|
+
end
|
45
|
+
val_array << cd.value
|
46
|
+
when :not
|
47
|
+
if cd.value.nil?
|
48
|
+
ary << "#{cd.field} IS NOT ?"
|
49
|
+
else
|
50
|
+
ary << "#{cd.field} <> ?"
|
51
|
+
end
|
52
|
+
val_array << cd.value
|
53
|
+
when :gt
|
54
|
+
ary << "#{cd.field} > ?"
|
55
|
+
val_array << cd.value
|
56
|
+
when :gte
|
57
|
+
ary << "#{cd.field} >= ?"
|
58
|
+
val_array << cd.value
|
59
|
+
when :lt
|
60
|
+
ary << "#{cd.field} < ?"
|
61
|
+
val_array << cd.value
|
62
|
+
when :lte
|
63
|
+
ary << "#{cd.field} <= ?"
|
64
|
+
val_array << cd.value
|
65
|
+
when :in
|
66
|
+
ary << "#{cd.field} IN ( ? )"
|
67
|
+
val_array << cd.value
|
68
|
+
end
|
69
|
+
ary
|
70
|
+
end
|
71
|
+
opts[:conditions] = [cnds.join(" AND "), *val_array]
|
72
|
+
end
|
73
|
+
opts
|
74
|
+
end
|
75
|
+
end # ClassWrapper
|
76
|
+
|
77
|
+
class InstanceWrapper < Veneer::Base::InstanceWrapper
|
78
|
+
def save!
|
79
|
+
instance.save!
|
80
|
+
rescue ActiveRecord::RecordInvalid => e
|
81
|
+
raise ::Veneer::Errors::NotSaved
|
82
|
+
end
|
83
|
+
|
84
|
+
def save
|
85
|
+
instance.save
|
86
|
+
end
|
87
|
+
end # InstanceWrapper
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
module VeneerInterface
|
4
|
+
class InstanceWrapper < Veneer::Base::InstanceWrapper
|
5
|
+
def update(attributes = {})
|
6
|
+
instance.update_attributes(attributes)
|
7
|
+
end
|
8
|
+
end # InstanceWrapper
|
9
|
+
end # VeneerInterface
|
10
|
+
end # Base
|
11
|
+
end # ActiveRecord
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Resource
|
3
|
+
module VeneerInterface
|
4
|
+
class ClassWrapper < ::Veneer::Base::ClassWrapper
|
5
|
+
def new(opts = {})
|
6
|
+
::Kernel.Veneer(klass.new(opts))
|
7
|
+
end
|
8
|
+
|
9
|
+
def destroy_all
|
10
|
+
klass.all.destroy
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_first(conditional)
|
14
|
+
opts = opts_from_conditional_for_dm(conditional)
|
15
|
+
klass.first(opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_many(conditional)
|
19
|
+
opts = opts_from_conditional_for_dm(conditional)
|
20
|
+
klass.all(opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def opts_from_conditional_for_dm(c)
|
25
|
+
opts = {}
|
26
|
+
|
27
|
+
opts[:limit] = c.limit if c.limit
|
28
|
+
opts[:offset] = c.offset if c.offset
|
29
|
+
|
30
|
+
unless c.order.empty?
|
31
|
+
opts[:order] = c.order.inject([]) do |ary, cnd|
|
32
|
+
ary << cnd.field.send(cnd.direction)
|
33
|
+
ary
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
unless c.conditions.empty?
|
38
|
+
c.conditions.each do |cd|
|
39
|
+
case cd.operator
|
40
|
+
when :eql
|
41
|
+
opts[cd.field] = cd.value
|
42
|
+
when :not, :gt, :gte, :lt, :lte
|
43
|
+
opts[cd.field.send(cd.operator)] = cd.value
|
44
|
+
when :in
|
45
|
+
opts[cd.field] = ::Array.new([cd.value].flatten.compact)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
opts
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|