veneer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +138 -0
  5. data/Rakefile +64 -0
  6. data/VERSION +1 -0
  7. data/datamapper_setup.rb +2 -0
  8. data/lib/veneer.rb +35 -0
  9. data/lib/veneer/adapters/activerecord.rb +2 -0
  10. data/lib/veneer/adapters/activerecord/class_wrapper.rb +90 -0
  11. data/lib/veneer/adapters/activerecord/instance_wrapper.rb +11 -0
  12. data/lib/veneer/adapters/datamapper.rb +2 -0
  13. data/lib/veneer/adapters/datamapper/class_wrapper.rb +54 -0
  14. data/lib/veneer/adapters/datamapper/instance_wrapper.rb +23 -0
  15. data/lib/veneer/base/class_wrapper.rb +53 -0
  16. data/lib/veneer/base/conditional.rb +77 -0
  17. data/lib/veneer/base/instance_wrapper.rb +38 -0
  18. data/lib/veneer/core_ext/kernel.rb +17 -0
  19. data/lib/veneer/errors.rb +9 -0
  20. data/lib/veneer/proxy.rb +4 -0
  21. data/test/macros/class_wrapper/create_macro.rb +54 -0
  22. data/test/macros/class_wrapper/delete_macro.rb +31 -0
  23. data/test/macros/class_wrapper/find_macro.rb +112 -0
  24. data/test/macros/instance_wrapper/destroy_macro.rb +36 -0
  25. data/test/macros/instance_wrapper/new_record_macro.rb +35 -0
  26. data/test/macros/instance_wrapper/save_macro.rb +55 -0
  27. data/test/macros/veneer_constants_interface.rb +26 -0
  28. data/test/support/helpers.rb +18 -0
  29. data/test/test_helper.rb +16 -0
  30. data/test/veneer/adapters/active_record/active_record_setup.rb +28 -0
  31. data/test/veneer/adapters/active_record/class_wrapper_test.rb +21 -0
  32. data/test/veneer/adapters/active_record/instance_wrapper_test.rb +21 -0
  33. data/test/veneer/adapters/datamapper/class_wrapper_test.rb +22 -0
  34. data/test/veneer/adapters/datamapper/datamapper_setup.rb +25 -0
  35. data/test/veneer/adapters/datamapper/instance_wrapper_test.rb +21 -0
  36. data/test/veneer/base/conditonal_test.rb +118 -0
  37. data/test/veneer/proxy_test.rb +190 -0
  38. data/veneer.gemspec +95 -0
  39. metadata +109 -0
@@ -0,0 +1,23 @@
1
+ module DataMapper
2
+ module Resource
3
+ module VeneerInterface
4
+ class InstanceWrapper < ::Veneer::Base::InstanceWrapper
5
+
6
+ def save!
7
+ r = instance.save
8
+ raise ::Veneer::Errors::NotSaved unless r
9
+ r
10
+ end
11
+
12
+ def new_record?
13
+ instance.respond_to?(:new?) ? instance.new? : instance.new_record?
14
+ end
15
+
16
+ def destroy
17
+ instance.destroy
18
+ self
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ module Veneer
2
+ module Base
3
+ class ClassWrapper < BasicObject
4
+ attr_reader :klass, :opts
5
+ def initialize(klass, opts)
6
+ @klass, @opts = klass, opts
7
+ end
8
+
9
+ # @api public
10
+ def create!(opts = {})
11
+ instance = new(opts)
12
+ instance.save!
13
+ instance
14
+ end
15
+
16
+ # @api public
17
+ def create(opts = {})
18
+ instance = new(opts)
19
+ instance.save
20
+ instance
21
+ end
22
+
23
+ # @api implementor
24
+ def new(opts = {})
25
+ ::Kernel.raise Errors::NotImplemented
26
+ end
27
+
28
+ # @api public
29
+ def first(opts={})
30
+ conditional = ::Veneer::Conditional.from_hash(opts)
31
+ ::Kernel.Veneer(find_first(conditional))
32
+ end
33
+
34
+ # @api public
35
+ def all(opts={})
36
+ conditional = ::Veneer::Conditional.from_hash(opts)
37
+ find_many(conditional).map{|element| ::Kernel.Veneer(element)}
38
+ end
39
+
40
+ # Should return an array or array like structure with elements matching the provided conditional
41
+ # @api implementor
42
+ def find_many(conditional)
43
+ ::Kernel.raise Errors::NotImplemented
44
+ end
45
+
46
+ # A single object matching the conditional
47
+ # @api_implementor
48
+ def find_first(conditional)
49
+ ::Kernel.raise Errors::NotImplemented
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,77 @@
1
+ module Veneer
2
+ class Conditional
3
+
4
+ def self.from_hash(hash)
5
+ new(hash)
6
+ end
7
+
8
+ attr_reader :options
9
+ def initialize(opts)
10
+ @options = HashWithIndifferentAccess.new(opts || {})
11
+ odr = Array.new([@options.delete(:order)].flatten.compact)
12
+ @ordering = odr.nil? || odr.empty? ? [] : begin
13
+ odr.map do |order|
14
+ field, direction = order.split(" ")
15
+ Order.new(field, (direction || :desc))
16
+ end
17
+ end
18
+
19
+ conds = opts.fetch(:conditions, {})
20
+ @conditions = conds.map do |k,v|
21
+ field, operator = k.to_s.split(" ")
22
+ args = [field, v]
23
+ args << operator.to_sym if operator
24
+ Veneer::Conditional::Condition.new(*args)
25
+ end
26
+ end
27
+
28
+ def limit
29
+ @options[:limit]
30
+ end
31
+
32
+ def offset
33
+ @options[:offset]
34
+ end
35
+
36
+ def order
37
+ @ordering
38
+ end
39
+
40
+ def conditions
41
+ @conditions
42
+ end
43
+
44
+ class Order
45
+ attr_reader :field, :direction
46
+ def initialize(field, direction = :desc)
47
+ @field = field.to_sym
48
+ @direction = direction.to_sym
49
+ end
50
+
51
+ def ascending?
52
+ direction == :asc
53
+ end
54
+
55
+ def decending?
56
+ !ascending?
57
+ end
58
+
59
+ def ==(other)
60
+ self.class == other.class &&
61
+ field == other.field &&
62
+ direction == other.direction
63
+ end
64
+ end
65
+
66
+ class Condition
67
+ attr_accessor :field, :operator, :value
68
+
69
+ VALID_OPERATORS = [:eql, :gt, :gte, :lt, :lte, :in, :not]
70
+
71
+ def initialize(field, value, operator = :eql)
72
+ @field, @value, @operator = field.to_sym, value, operator.to_sym
73
+ raise Veneer::Errors::ConditionalOperatorNotSupported, "#{operator.inspect} not a valid operator" unless VALID_OPERATORS.include?(operator)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,38 @@
1
+ module Veneer
2
+ module Base
3
+ class InstanceWrapper
4
+ attr_accessor :instance, :options
5
+ def initialize(instance, opts = {})
6
+ @instance, @options = instance, opts
7
+ end
8
+
9
+ # Checks equality of the instances
10
+ # @api public
11
+ def ==(other)
12
+ case other
13
+ when Veneer::Base::InstanceWrapper
14
+ instance == other.instance
15
+ else
16
+ instance == other
17
+ end
18
+ end
19
+
20
+ # Updates the attributes by trying to use the keys of the
21
+ # attributes hash as a setter method (:"#{key}=") to the value of the hash
22
+ # then the object is saved
23
+ # Adapter implementors may want to overwrite may want to overwrite
24
+ # @api public
25
+ def update(attributes = {})
26
+ attributes.each do |attr,value|
27
+ instance.send(:"#{attr}=",value)
28
+ end
29
+ save
30
+ end
31
+
32
+ # send all methods to the instance
33
+ def method_missing(*args, &blk)
34
+ instance.send(*args, &blk)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ module Kernel
2
+ def Veneer(obj, opts = {})
3
+ case obj
4
+ when Class
5
+ obj::VeneerInterface::ClassWrapper.new(obj, opts)
6
+ when Veneer::Base::ClassWrapper, Veneer::Base::InstanceWrapper
7
+ obj
8
+ when nil
9
+ nil
10
+ else
11
+ obj.class::VeneerInterface::InstanceWrapper.new(obj, opts)
12
+ end
13
+ rescue NameError => e
14
+ puts e.message
15
+ raise Veneer::Errors::NotCompatible
16
+ end # Veneer()
17
+ end
@@ -0,0 +1,9 @@
1
+ module Veneer
2
+ module Errors
3
+ class VeneerError < StandardError; end
4
+ class NotCompatible < VeneerError; end
5
+ class NotSaved < VeneerError; end
6
+ class ConditionalOperatorNotSupported < VeneerError; end
7
+ class NotImplemented < VeneerError; end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module Veneer
2
+ class Proxy < ::BasicObject
3
+ end
4
+ end
@@ -0,0 +1,54 @@
1
+ class Test::Unit::TestCase
2
+ def self.veneer_should_implement_create_with_valid_attributes
3
+ context "implements create with valid attributes" do
4
+ should "setup the spec correctly" do
5
+ assert_not_nil @klass
6
+ assert_kind_of Class, @klass
7
+ assert_not_nil @valid_attributes
8
+ assert_kind_of Hash, @valid_attributes
9
+ end
10
+
11
+ teardown do
12
+ Veneer(@klass).destroy_all
13
+ end
14
+
15
+ should "create the object from the hash" do
16
+ r = Veneer(@klass).create(@valid_attributes)
17
+ assert_instance_of @klass::VeneerInterface::InstanceWrapper, r
18
+ end
19
+
20
+ should "create the object from the hash with create!" do
21
+ r = Veneer(@klass).create!(@valid_attributes)
22
+ assert_instance_of @klass::VeneerInterface::InstanceWrapper, r
23
+ end
24
+
25
+ should "create a new instance of the object" do
26
+ r = Veneer(@klass).new(@valid_attributes)
27
+ assert_instance_of @klass::VeneerInterface::InstanceWrapper, r
28
+ end
29
+ end
30
+
31
+ def self.veneer_should_implement_create_with_invalid_attributes
32
+ context "implements create! with invalid attributes" do
33
+ should "setup the spec correctly" do
34
+ assert_not_nil @klass
35
+ assert_kind_of Class, @klass
36
+ assert_not_nil @invalid_attributes
37
+ assert_kind_of Hash, @invalid_attributes
38
+ end
39
+
40
+ should "raise when creating could not save" do
41
+ assert_raise Veneer::Errors::NotSaved do
42
+ Veneer(@klass).create!(@invalid_attributes)
43
+ end
44
+ end
45
+
46
+ should "not raise when create can not save" do
47
+ assert_nothing_raised do
48
+ Veneer(@klass).create(@invalid_attributes)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,31 @@
1
+ class Test::Unit::TestCase
2
+ def self.veneer_should_impelement_destroy_all
3
+ context "implements destroy_all" do
4
+ should "setup the test correctly" do
5
+ assert_not_nil @klass
6
+ assert_kind_of Class, @klass
7
+ assert_not_nil @valid_attributes
8
+ assert_kind_of Hash, @valid_attributes
9
+ end
10
+
11
+ context "destroy_all" do
12
+ setup do
13
+ Veneer(@klass).destroy_all
14
+ assert_equal 0, Veneer(@klass).all.size
15
+ (0..5).each do |i|
16
+ Veneer(@klass).new(:name => "foo#{i}", :order_field1 => i).save
17
+ end
18
+ end
19
+
20
+ should "setup the spec correctly" do
21
+ assert_equal 6, Veneer(@klass).all.size
22
+ end
23
+
24
+ should "destroy all records" do
25
+ Veneer(@klass).destroy_all
26
+ assert_equal 0, Veneer(@klass).all.size
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,112 @@
1
+ class Test::Unit::TestCase
2
+ def self.veneer_should_implement_find
3
+ context "implements find" do
4
+ setup do
5
+ Veneer(@klass).destroy_all
6
+ (0..5).each do |i|
7
+ Veneer(@klass).new(:order_field1 => i).save!
8
+ end
9
+ end
10
+
11
+ teardown{ Veneer(@klass).destroy_all }
12
+
13
+ should "impelement a find_all method" do
14
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
15
+ assert_kind_of Array, result
16
+ end
17
+
18
+ should "implement a find_first method" do
19
+ result = Veneer(@klass).find_first(Veneer::Conditional.from_hash({}))
20
+ end
21
+
22
+ should "implement limit" do
23
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
24
+ assert_not_equal 3, total.size
25
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:limit => 3))
26
+ assert_equal 3, result.size
27
+ end
28
+
29
+ should "implement order" do
30
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:order => "order_field1"))
31
+ raw = result.map{|i| i.order_field1 }.compact
32
+ sorted = raw.sort.reverse
33
+ assert_equal raw, sorted
34
+ end
35
+
36
+ should "implement order decending" do
37
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:order => "order_field1 desc"))
38
+ raw = result.map{|i| i.order_field1 }.compact
39
+ sorted = raw.sort.reverse
40
+ assert_equal raw, sorted
41
+ end
42
+
43
+ should "implement order ascending" do
44
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:order => "order_field1 asc"))
45
+ raw = result.map{|i| i.order_field1}.compact
46
+ sorted = raw.sort
47
+ assert_equal raw, sorted
48
+ end
49
+
50
+ should "impelment offset" do
51
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
52
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash({:offset => 2, :limit => 2}))
53
+
54
+ assert_equal((total[2..3]), result)
55
+ end
56
+
57
+ context "conditions" do
58
+ setup do
59
+ Veneer(@klass).new(:name => "bar").save
60
+ Veneer(@klass).new(:name => "foo").save
61
+ Veneer(@klass).new(:name => "foobar").save
62
+ end
63
+
64
+ should "implement basic conditions" do
65
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
66
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {:name => "foo"}))
67
+ assert_equal 1, result.size
68
+ end
69
+
70
+ should "implement :not conditions" do
71
+ Veneer(@klass).all(:conditions => {:name => nil}).map(&:destroy)
72
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
73
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {"name not" => "bar"}))
74
+ assert_equal((total.size - 1), result.size)
75
+ end
76
+
77
+ should "implement gt conditions" do
78
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
79
+ expected = total.select{|i| !i.order_field1.nil? && i.order_field1 > 3}
80
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {"order_field1 gt" => 3}))
81
+ assert_equal expected.size, result.size
82
+ end
83
+
84
+ should "implement gte conditions" do
85
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
86
+ expected = total.select{|i| !i.order_field1.nil? && i.order_field1 >= 3}
87
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {"order_field1 gte" => 3}))
88
+ assert_equal 3, result.size
89
+ end
90
+
91
+ should "implement :lt condition" do
92
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {"order_field1 lt" => 3}))
93
+ assert_equal 3, result.size
94
+ end
95
+
96
+ should "implement a lte condition" do
97
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
98
+ expected = total.select{|i| !i.order_field1.nil? && i.order_field1 <= 3}
99
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {"order_field1 lte" => 3}))
100
+ assert_equal expected.size, result.size
101
+ end
102
+
103
+ should "implement an :in condition" do
104
+ total = Veneer(@klass).find_many(Veneer::Conditional.from_hash({}))
105
+ expected = total.select{|i| ["foo", "bar"].include?(i.name)}
106
+ result = Veneer(@klass).find_many(Veneer::Conditional.from_hash(:conditions => {"name in" => ["foo", "bar"]}))
107
+ assert_equal expected.size, result.size
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,36 @@
1
+ class Test::Unit::TestCase
2
+ def self.veneer_should_implement_destroy
3
+ context "on an instance" do
4
+ should "setup the test correctly" do
5
+ assert_not_nil @klass
6
+ assert_kind_of Class, @klass
7
+ assert_not_nil @valid_attributes
8
+ assert_kind_of Hash, @valid_attributes
9
+ end
10
+
11
+ setup do
12
+ Veneer(@klass).destroy_all
13
+ @valid = Veneer(@klass).new(@valid_attributes)
14
+ end
15
+
16
+ should "setup the spec" do
17
+ assert @valid.save
18
+ r = Veneer(@klass).first(:conditions => {:name => @valid.instance.name})
19
+ assert_equal @valid, r
20
+ end
21
+
22
+ should "destroy the object" do
23
+ @valid.save
24
+ v = @valid
25
+ assert_equal v, @valid.destroy
26
+ end
27
+
28
+ should "remove the object from the collection" do
29
+ @valid.save
30
+ assert_equal @valid, Veneer(@klass).first(:conditions => {:name => @valid.name})
31
+ @valid.destroy
32
+ assert_nil Veneer(@klass).first(:conditions => {:name => @valid.name})
33
+ end
34
+ end
35
+ end
36
+ end