veneer 0.1.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/.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
|