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.
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