kangaroo 0.0.1.pre

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 (68) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +2 -0
  3. data/.yardopts +6 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +66 -0
  6. data/LICENSE +22 -0
  7. data/README.md +65 -0
  8. data/Rakefile +36 -0
  9. data/config/kangaroo.yml.sample +12 -0
  10. data/docs/AdditionalServices.md +3 -0
  11. data/docs/Architecture.md +50 -0
  12. data/docs/Installation.md +73 -0
  13. data/docs/Usage.md +161 -0
  14. data/features/connection.feature +5 -0
  15. data/features/env.rb +8 -0
  16. data/features/step_definitions/basic_steps.rb +24 -0
  17. data/features/step_definitions/connection_steps.rb +13 -0
  18. data/features/support/test.yml +11 -0
  19. data/features/utility_services.feature +39 -0
  20. data/kangaroo.gemspec +29 -0
  21. data/lib/kangaroo.rb +6 -0
  22. data/lib/kangaroo/exception.rb +7 -0
  23. data/lib/kangaroo/model/attributes.rb +124 -0
  24. data/lib/kangaroo/model/base.rb +70 -0
  25. data/lib/kangaroo/model/condition_normalizer.rb +63 -0
  26. data/lib/kangaroo/model/default_attributes.rb +22 -0
  27. data/lib/kangaroo/model/field.rb +20 -0
  28. data/lib/kangaroo/model/finder.rb +92 -0
  29. data/lib/kangaroo/model/inspector.rb +55 -0
  30. data/lib/kangaroo/model/open_object_orm.rb +117 -0
  31. data/lib/kangaroo/model/persistence.rb +180 -0
  32. data/lib/kangaroo/model/relation.rb +212 -0
  33. data/lib/kangaroo/model/remote_execute.rb +29 -0
  34. data/lib/kangaroo/railtie.rb +13 -0
  35. data/lib/kangaroo/ruby_adapter/base.rb +28 -0
  36. data/lib/kangaroo/ruby_adapter/class_definition.rb +46 -0
  37. data/lib/kangaroo/ruby_adapter/fields.rb +18 -0
  38. data/lib/kangaroo/util/client.rb +59 -0
  39. data/lib/kangaroo/util/configuration.rb +82 -0
  40. data/lib/kangaroo/util/database.rb +92 -0
  41. data/lib/kangaroo/util/loader.rb +98 -0
  42. data/lib/kangaroo/util/loader/model.rb +21 -0
  43. data/lib/kangaroo/util/loader/namespace.rb +15 -0
  44. data/lib/kangaroo/util/proxy.rb +35 -0
  45. data/lib/kangaroo/util/proxy/common.rb +111 -0
  46. data/lib/kangaroo/util/proxy/db.rb +34 -0
  47. data/lib/kangaroo/util/proxy/object.rb +153 -0
  48. data/lib/kangaroo/util/proxy/report.rb +24 -0
  49. data/lib/kangaroo/util/proxy/superadmin.rb +71 -0
  50. data/lib/kangaroo/util/proxy/wizard.rb +25 -0
  51. data/lib/kangaroo/util/proxy/workflow.rb +14 -0
  52. data/lib/kangaroo/version.rb +3 -0
  53. data/spec/model/attributes_spec.rb +70 -0
  54. data/spec/model/base_spec.rb +19 -0
  55. data/spec/model/default_attributes_spec.rb +37 -0
  56. data/spec/model/finder_spec.rb +104 -0
  57. data/spec/model/inspector_spec.rb +56 -0
  58. data/spec/model/open_object_orm_spec.rb +134 -0
  59. data/spec/model/persistence_spec.rb +53 -0
  60. data/spec/model/relation_spec.rb +122 -0
  61. data/spec/ruby_adapter/class_definition_spec.rb +51 -0
  62. data/spec/server_helper.rb +167 -0
  63. data/spec/spec_helper.rb +14 -0
  64. data/spec/test_env/test.yml +11 -0
  65. data/spec/util/configuration_spec.rb +36 -0
  66. data/spec/util/loader_spec.rb +50 -0
  67. data/spec/util/proxy_spec.rb +61 -0
  68. metadata +260 -0
@@ -0,0 +1,25 @@
1
+ module Kangaroo
2
+ module Util
3
+ class Proxy::Wizard < Proxy
4
+ # Create Wizard
5
+ #
6
+ # @param [String] name wizard name to create
7
+ # @param [Hash] datas
8
+ # @return [Number] id of created wizard
9
+ def create name, datas = {}
10
+ call! :create, name, datas
11
+ end
12
+
13
+ # Execute an action on a wizard
14
+ #
15
+ # @param [Number] id wizard id
16
+ # @param [Hash] datas
17
+ # @param [String] action
18
+ # @param [Hash] context
19
+ # @return return value of action
20
+ def execute id, datas, action = 'init', context = {}
21
+ call! :execute, id, datas, action, context
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ module Kangaroo
2
+ module Util
3
+ class Proxy::Workflow < Proxy
4
+ # Advance workflow via exec_workflow on OpenERPs object service.
5
+ #
6
+ # @param name function name to call
7
+ # @param model_name OpenERP model to execute the function on
8
+ # @return returned value
9
+ def call! name, model_name, id
10
+ super :exec_workflow, model_name, id, name
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Kangaroo
2
+ VERSION = "0.0.1.pre"
3
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+ require 'kangaroo/model/base'
3
+
4
+ module Kangaroo
5
+ module Model
6
+ describe Attributes do
7
+ before :all do
8
+ @klass = Class.new(Kangaroo::Model::Base)
9
+ @klass.define_multiple_accessors :a, :b
10
+ end
11
+
12
+ before :each do
13
+ @klass.stub!(:default_attributes).and_return({})
14
+ end
15
+
16
+ it 'stores the attribute names' do
17
+ @klass.attribute_names.should == ['a', 'b']
18
+ end
19
+
20
+ it 'allows to read attributes via read_attribute' do
21
+ @object = @klass.new :a => 'one'
22
+ @object.read_attribute(:a).should == 'one'
23
+ end
24
+
25
+ it 'allows to read attributes via getters' do
26
+ @object = @klass.new :a => 'one'
27
+ @object.a.should == 'one'
28
+ end
29
+
30
+ it 'allows to write attributes via write_attribute' do
31
+ @object = @klass.new :a => 'one'
32
+ @object.write_attribute :a, 'two'
33
+ @object.a.should == 'two'
34
+ end
35
+
36
+ it 'allows to write attributes via setters' do
37
+ @object = @klass.new :a => 'one'
38
+ @object.a = 'two'
39
+ @object.a.should == 'two'
40
+ end
41
+
42
+ it 'allows to mass assign attributes via #attributes=' do
43
+ @object = @klass.new
44
+ @object.attributes = {:a => 'one'}
45
+ @object.a.should == 'one'
46
+ end
47
+
48
+ it 'allows to read all attributes via #attributes' do
49
+ @object = @klass.new :a => 'one'
50
+ @object.attributes['a'].should == 'one'
51
+ end
52
+
53
+ describe 'ActiveModel::Dirty behavior' do
54
+ it 'marks changed attributes and stores old value' do
55
+ @object = @klass.new :a => 'one'
56
+ @object.a = 'two'
57
+ @object.should be_changed
58
+ @object.a_was.should == 'one'
59
+ @object.should be_a_changed
60
+ end
61
+
62
+ it 'marks initial values as changed' do
63
+ @object = @klass.new :a => 'one'
64
+ @object.should be_changed
65
+ @object.should be_a_changed
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'kangaroo/model/base'
3
+
4
+ module Kangaroo
5
+ module Model
6
+ describe Base do
7
+ before :all do
8
+ @klass = Class.new(Kangaroo::Model::Base)
9
+ @klass.define_multiple_accessors :a, :b
10
+ end
11
+
12
+ it 'sets attributes on initialization' do
13
+ @klass.stub!(:default_attributes).and_return({})
14
+ @object = @klass.new :a => 'one'
15
+ @object.instance_variable_get('@attributes')['a'].should == 'one'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'kangaroo/model/base'
3
+
4
+ module Kangaroo
5
+ module Model
6
+ describe DefaultAttributes do
7
+ before :all do
8
+ @klass = Class.new(Kangaroo::Model::Base)
9
+ @klass.define_multiple_accessors :a, :b
10
+ end
11
+
12
+ it 'sets default values on initialization' do
13
+ @klass.stub!(:default_attributes).and_return(:a => 'one')
14
+ @object = @klass.new
15
+ @object.a.should == 'one'
16
+ @object.should be_a_changed
17
+ end
18
+
19
+ it 'sets default values before initial values' do
20
+ @klass.stub!(:default_attributes).and_return(:a => 'one')
21
+ @object = @klass.new :a => 'two'
22
+ @object.a.should == 'two'
23
+ end
24
+
25
+ it 'fetches default values via default_get on the object service' do
26
+ @klass = Class.new(Kangaroo::Model::Base)
27
+ @klass.define_multiple_accessors :a, :b
28
+ @klass.field_names = %w(a b)
29
+ @klass.stub!(:remote).and_return mock('object_service')
30
+ @klass.remote.should_receive(:default_get).with(%w(a b), anything).and_return :a => 'one', :b => 'two'
31
+ @object = @klass.new
32
+ @object.a.should == 'one'
33
+ @object.b.should == 'two'
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ require 'kangaroo/model/base'
3
+
4
+ module Kangaroo
5
+ module Model
6
+ describe Finder do
7
+ include SpecHelper
8
+
9
+ before :each do
10
+ @klass = Class.new(Kangaroo::Model::Base)
11
+ @klass.define_multiple_accessors :a, :b
12
+ @klass.stub!(:default_attributes).and_return({})
13
+ @remote_stub = mock 'remote'
14
+ @klass.stub!(:remote).and_return @remote_stub
15
+ end
16
+
17
+ describe 'relational #all' do
18
+ it 'allows specifying conditions via #where' do
19
+ @remote_stub.should_receive(:search).with([["a", "=", "one"]], *anythings(5)).
20
+ and_return [1]
21
+ @remote_stub.stub!(:read).and_return [{:a => 'one', :id => 1}]
22
+ @klass.where(:a => 'one').all
23
+ end
24
+
25
+ it 'allows specifying a limit via #limit' do
26
+ @remote_stub.should_receive(:search).with([], nil, 10, *anythings(3)).
27
+ and_return [1]
28
+ @remote_stub.stub!(:read).and_return [{:a => 'one', :id => 1}]
29
+ @klass.limit(10).all
30
+ end
31
+
32
+ it 'allows specifying an offset via #offset' do
33
+ @remote_stub.should_receive(:search).with([], 10, nil, *anythings(3)).
34
+ and_return [1]
35
+ @remote_stub.stub!(:read).and_return [{:a => 'one', :id => 1}]
36
+ @klass.offset(10).all
37
+ end
38
+
39
+ it 'allows specifying a sort order via #order' do
40
+ @remote_stub.should_receive(:search).with([], nil, nil, 'a', *anythings(2)).
41
+ and_return [1]
42
+ @remote_stub.stub!(:read).and_return [{:a => 'one', :id => 1}]
43
+ @klass.order('a').all
44
+ end
45
+
46
+ it 'allows specifying descending sort order via #order(column, true)' do
47
+ @remote_stub.should_receive(:search).with([], nil, nil, 'a desc', *anythings(2)).
48
+ and_return [1]
49
+ @remote_stub.stub!(:read).and_return [{:a => 'one', :id => 1}]
50
+ @klass.order('a', true).all
51
+ end
52
+
53
+ it 'allows specifying fields to read via #select' do
54
+ @remote_stub.stub!(:search).and_return [1]
55
+ @remote_stub.should_receive(:read).with([1], ['a'], {}).
56
+ and_return [{:a => 'one', :id => 1}]
57
+ @klass.select('a').all
58
+ end
59
+
60
+ it 'allows specifying the context via #context' do
61
+ @remote_stub.stub!(:search).and_return [1]
62
+ @remote_stub.should_receive(:read).
63
+ with([1], ['a', 'b'], :lang => 'de_DE').
64
+ and_return [{:a => 'one', :id => 1}]
65
+ @klass.context(:lang => 'de_DE').all
66
+ end
67
+ end
68
+
69
+ it 'relational #count returns number of records fulfilling the conditions' do
70
+ @remote_stub.should_receive(:search).with([['a', '=', 'one']], *anythings(5)).
71
+ and_return 5
72
+ @klass.where(:a => 'one').count.should == 5
73
+ end
74
+
75
+ describe '#all' do
76
+ it 'searches for all records, and reads all attributes' do
77
+ @remote_stub.should_receive(:search).with([], *anythings(5)).
78
+ and_return [1, 2]
79
+ @remote_stub.should_receive(:read).with([1, 2], ['a', 'b'], anything).
80
+ and_return [{:id => 1, :a => 'one'}, {:id => 2, :a => 'two'}]
81
+ @klass.all
82
+ end
83
+ end
84
+
85
+ describe '#first' do
86
+ it 'searches for 1 record, and reads all attributes' do
87
+ @remote_stub.should_receive(:search).with([], nil, 1, *anythings(3)).
88
+ and_return [1]
89
+ @remote_stub.should_receive(:read).with([1], ['a', 'b'], anything).
90
+ and_return [{:id => 1, :a => 'one'}]
91
+ @klass.first
92
+ end
93
+ end
94
+
95
+ describe '#count' do
96
+ it 'only counts how many records are present' do
97
+ @remote_stub.should_receive(:search).with([], 0, anything, anything, anything, true).
98
+ and_return 2
99
+ @klass.count
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'kangaroo/model/base'
3
+
4
+ module Kangaroo
5
+ module Model
6
+ describe Inspector do
7
+ before :all do
8
+ SomeClass = Class.new(Kangaroo::Model::Base)
9
+ SomeClass.define_multiple_accessors :first_attribute, :second_attribute
10
+ end
11
+
12
+ before :each do
13
+ SomeClass.stub!(:default_attributes).and_return({})
14
+ end
15
+
16
+ context 'Class#inspect' do
17
+ it 'includes attribute names' do
18
+ SomeClass.inspect.should include('first_attribute')
19
+ SomeClass.inspect.should include('second_attribute')
20
+ end
21
+
22
+ it 'includes class name' do
23
+ SomeClass.inspect.should include('SomeClass')
24
+ end
25
+
26
+ it 'includes id' do
27
+ SomeClass.inspect.should include('id')
28
+ end
29
+ end
30
+
31
+ context 'Object#inspect' do
32
+ before :each do
33
+ @object = SomeClass.new :first_attribute => 'one', :second_attribute => 'two'
34
+ end
35
+
36
+ it 'includes attribute names and values' do
37
+ @object.inspect.should include('first_attribute: "one"')
38
+ @object.inspect.should include('second_attribute: "two"')
39
+ end
40
+
41
+ it 'includes class name' do
42
+ @object.inspect.should include('SomeClass')
43
+ end
44
+
45
+ it 'includes id' do
46
+ @object.instance_variable_set '@id', 3
47
+ @object.inspect.should include('id: 3')
48
+ end
49
+
50
+ it 'includes id: nil on new records' do
51
+ @object.inspect.should include('id: nil')
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+ require 'server_helper'
3
+ require 'kangaroo/model/base'
4
+
5
+ module Kangaroo
6
+ module Model
7
+ describe OpenObjectOrm do
8
+ include TestServerHelper
9
+
10
+ before :each do
11
+ @klass = Class.new(Kangaroo::Model::Base)
12
+ @klass.define_multiple_accessors :a, :b
13
+ @klass.stub!(:default_attributes).and_return({})
14
+ @klass.stub!(:remote).and_return proxy('object', 'some_class')
15
+ end
16
+
17
+ describe '#read' do
18
+ it 'reads and instantiates records' do
19
+ object_service.stub!(:xmlrpc_call).
20
+ with('execute', 'some_class', 'read', [1], ['a', 'b']).
21
+ and_return([{:a => 'one', :id => 1}])
22
+ @klass.read([1], :fields => ['a', 'b']).first.a.should == 'one'
23
+ end
24
+
25
+ it 'passes on the "context"' do
26
+ object_service.stub!(:xmlrpc_call).
27
+ and_return([{:a => 'one', :id => 1}])
28
+ @klass.read([1], :fields => ['a', 'b'], :context => {:lang => 'de'}).first.context[:lang].should == 'de'
29
+ end
30
+
31
+ it 'uses attribute_names as default value for field list' do
32
+ object_service.should_receive(:xmlrpc_call).with('execute', 'some_class', 'read', [1], ['a', 'b']).
33
+ and_return([{:a => 'one', :id => 1}])
34
+ @klass.read([1])
35
+ end
36
+ end
37
+
38
+ describe '#fields_get' do
39
+ it 'fetches details about fields of this model' do
40
+ object_service.should_receive(:xmlrpc_call).with('execute', 'some_class', 'fields_get', ['a'], false).
41
+ and_return({:a => {:type => "selection"}})
42
+ @klass.fields_get(:fields => ['a']).first.read_attribute(:type).should == 'selection'
43
+ end
44
+
45
+ it 'stores the name in the Field model' do
46
+ object_service.should_receive(:xmlrpc_call).with('execute', 'some_class', 'fields_get', ['a'], false).
47
+ and_return({:a => {:type => "selection"}})
48
+ @klass.fields_get(:fields => ['a']).first.name.should == :a
49
+ end
50
+
51
+ it 'uses attribute_names as default value for field list' do
52
+ object_service.should_receive(:xmlrpc_call).
53
+ with('execute', 'some_class', 'fields_get', ['a', 'b'], false).
54
+ and_return({:a => {:type => 'selection'}})
55
+ @klass.fields_get
56
+ end
57
+ end
58
+
59
+ describe '#search' do
60
+ it 'delegates search calls with array conditions to object service' do
61
+ object_service.should_receive(:xmlrpc_call).
62
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, false, false, false, false
63
+ @klass.search [['a', '=', 'one']]
64
+ end
65
+
66
+ it 'allows empty conditions' do
67
+ object_service.should_receive(:xmlrpc_call).exactly(4).times.
68
+ with 'execute', 'some_class', 'search', [], 0, false, false, false, false
69
+ @klass.search []
70
+ @klass.search ''
71
+ @klass.search nil
72
+ @klass.search({})
73
+ end
74
+
75
+ it 'converts simple hash conditions' do
76
+ object_service.should_receive(:xmlrpc_call).twice.
77
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, false, false, false, false
78
+ @klass.search [:a => 'one']
79
+ @klass.search :a => 'one'
80
+ end
81
+
82
+ it 'converts array hash conditions' do
83
+ object_service.should_receive(:xmlrpc_call).
84
+ with 'execute', 'some_class', 'search', [['a', 'in', ['one', 'two']]], 0, false, false, false, false
85
+ @klass.search :a => ['one', 'two']
86
+ end
87
+
88
+ describe 'string conditions' do
89
+ it 'parses equal to string condition' do
90
+ object_service.should_receive(:xmlrpc_call).
91
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, false, false, false, false
92
+ @klass.search "a = one"
93
+ end
94
+
95
+ it 'parses "not in" condition' do
96
+ object_service.should_receive(:xmlrpc_call).
97
+ with 'execute', 'some_class', 'search', [['a', 'not in', 'one']], 0, false, false, false, false
98
+ @klass.search "a not in one"
99
+ end
100
+ end
101
+
102
+ it 'accepts a limit option' do
103
+ object_service.should_receive(:xmlrpc_call).
104
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, 20, false, false, false
105
+ @klass.search 'a = one', :limit => 20
106
+ end
107
+
108
+ it 'accepts a offset option' do
109
+ object_service.should_receive(:xmlrpc_call).
110
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 10, false, false, false, false
111
+ @klass.search 'a = one', :offset => 10
112
+ end
113
+
114
+ it 'accepts a context option' do
115
+ object_service.should_receive(:xmlrpc_call).
116
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, false, false, {"a" => 'b'}, false
117
+ @klass.search 'a = one', :context => {:a => 'b'}
118
+ end
119
+
120
+ it 'accepts an order option' do
121
+ object_service.should_receive(:xmlrpc_call).
122
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, false, 'b', false, false
123
+ @klass.search 'a = one', :order => 'b'
124
+ end
125
+
126
+ it 'accepts a count option' do
127
+ object_service.should_receive(:xmlrpc_call).
128
+ with 'execute', 'some_class', 'search', [['a', '=', 'one']], 0, false, false, false, true
129
+ @klass.search 'a = one', :count => true
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end