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.
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.yardopts +6 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +66 -0
- data/LICENSE +22 -0
- data/README.md +65 -0
- data/Rakefile +36 -0
- data/config/kangaroo.yml.sample +12 -0
- data/docs/AdditionalServices.md +3 -0
- data/docs/Architecture.md +50 -0
- data/docs/Installation.md +73 -0
- data/docs/Usage.md +161 -0
- data/features/connection.feature +5 -0
- data/features/env.rb +8 -0
- data/features/step_definitions/basic_steps.rb +24 -0
- data/features/step_definitions/connection_steps.rb +13 -0
- data/features/support/test.yml +11 -0
- data/features/utility_services.feature +39 -0
- data/kangaroo.gemspec +29 -0
- data/lib/kangaroo.rb +6 -0
- data/lib/kangaroo/exception.rb +7 -0
- data/lib/kangaroo/model/attributes.rb +124 -0
- data/lib/kangaroo/model/base.rb +70 -0
- data/lib/kangaroo/model/condition_normalizer.rb +63 -0
- data/lib/kangaroo/model/default_attributes.rb +22 -0
- data/lib/kangaroo/model/field.rb +20 -0
- data/lib/kangaroo/model/finder.rb +92 -0
- data/lib/kangaroo/model/inspector.rb +55 -0
- data/lib/kangaroo/model/open_object_orm.rb +117 -0
- data/lib/kangaroo/model/persistence.rb +180 -0
- data/lib/kangaroo/model/relation.rb +212 -0
- data/lib/kangaroo/model/remote_execute.rb +29 -0
- data/lib/kangaroo/railtie.rb +13 -0
- data/lib/kangaroo/ruby_adapter/base.rb +28 -0
- data/lib/kangaroo/ruby_adapter/class_definition.rb +46 -0
- data/lib/kangaroo/ruby_adapter/fields.rb +18 -0
- data/lib/kangaroo/util/client.rb +59 -0
- data/lib/kangaroo/util/configuration.rb +82 -0
- data/lib/kangaroo/util/database.rb +92 -0
- data/lib/kangaroo/util/loader.rb +98 -0
- data/lib/kangaroo/util/loader/model.rb +21 -0
- data/lib/kangaroo/util/loader/namespace.rb +15 -0
- data/lib/kangaroo/util/proxy.rb +35 -0
- data/lib/kangaroo/util/proxy/common.rb +111 -0
- data/lib/kangaroo/util/proxy/db.rb +34 -0
- data/lib/kangaroo/util/proxy/object.rb +153 -0
- data/lib/kangaroo/util/proxy/report.rb +24 -0
- data/lib/kangaroo/util/proxy/superadmin.rb +71 -0
- data/lib/kangaroo/util/proxy/wizard.rb +25 -0
- data/lib/kangaroo/util/proxy/workflow.rb +14 -0
- data/lib/kangaroo/version.rb +3 -0
- data/spec/model/attributes_spec.rb +70 -0
- data/spec/model/base_spec.rb +19 -0
- data/spec/model/default_attributes_spec.rb +37 -0
- data/spec/model/finder_spec.rb +104 -0
- data/spec/model/inspector_spec.rb +56 -0
- data/spec/model/open_object_orm_spec.rb +134 -0
- data/spec/model/persistence_spec.rb +53 -0
- data/spec/model/relation_spec.rb +122 -0
- data/spec/ruby_adapter/class_definition_spec.rb +51 -0
- data/spec/server_helper.rb +167 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/test_env/test.yml +11 -0
- data/spec/util/configuration_spec.rb +36 -0
- data/spec/util/loader_spec.rb +50 -0
- data/spec/util/proxy_spec.rb +61 -0
- metadata +260 -0
data/features/env.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Given /^i'm connected to an OpenERP server$/ do
|
2
|
+
logger = Logger.new(File.open("/dev/null", 'w'))
|
3
|
+
@config = Kangaroo::Util::Configuration.new 'features/support/test.yml', logger
|
4
|
+
@config.login
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^setup a proxy to "([^"]*)"$/ do |service|
|
8
|
+
proxy = Kangaroo::Util::Proxy.const_get(service.camelize).new @config.client.send("#{service}_service")
|
9
|
+
self.instance_variable_set "@#{service}", proxy
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^i call (.*)\.(.*)$/ do |service, method|
|
13
|
+
proxy = instance_variable_get "@#{service}"
|
14
|
+
@result = proxy.__send__ method
|
15
|
+
puts @result.inspect
|
16
|
+
end
|
17
|
+
|
18
|
+
Then /^i should see "([^"]*)"$/ do |arg1|
|
19
|
+
@result.should include(arg1)
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^the list should include "([^"]*)"$/ do |arg1|
|
23
|
+
@result.flatten.join("\n").should include(arg1)
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Given /^i have a configuration file$/ do
|
2
|
+
@config_hash = YAML.load "features/support/test.yml"
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^i setup a configuration$/ do
|
6
|
+
@logger = Logger.new(STDERR)
|
7
|
+
@config = Kangaroo::Util::Configuration.new @config_hash, @logger
|
8
|
+
end
|
9
|
+
|
10
|
+
Then /^i should be able to login$/ do
|
11
|
+
@logger.should_not_receive :warn
|
12
|
+
@config.login
|
13
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Feature: Utility Services
|
2
|
+
Scenario: Get server information
|
3
|
+
Given i'm connected to an OpenERP server
|
4
|
+
And setup a proxy to "common"
|
5
|
+
When i call common.about
|
6
|
+
Then i should see "OpenERP"
|
7
|
+
|
8
|
+
Scenario: Get server environment
|
9
|
+
Given i'm connected to an OpenERP server
|
10
|
+
And setup a proxy to "common"
|
11
|
+
When i call common.get_server_environment
|
12
|
+
Then i should see "OpenERP-Server Version : 6"
|
13
|
+
And i should see "Python Version : 2.6"
|
14
|
+
|
15
|
+
Scenario: Get server stats
|
16
|
+
Given i'm connected to an OpenERP server
|
17
|
+
And setup a proxy to "common"
|
18
|
+
When i call common.get_stats
|
19
|
+
Then i should see "HTTPd: running"
|
20
|
+
|
21
|
+
Scenario: List available HTTP services
|
22
|
+
Given i'm connected to an OpenERP server
|
23
|
+
And setup a proxy to "common"
|
24
|
+
When i call common.list_http_services
|
25
|
+
Then the list should include "service.http_server.XMLRPCRequestHandler"
|
26
|
+
|
27
|
+
Scenario: List available databases
|
28
|
+
Given i'm connected to an OpenERP server
|
29
|
+
And setup a proxy to "db"
|
30
|
+
When i call db.list
|
31
|
+
Then the list should include "kangaroo_test_database"
|
32
|
+
|
33
|
+
Scenario: List available languages
|
34
|
+
Given i'm connected to an OpenERP server
|
35
|
+
And setup a proxy to "db"
|
36
|
+
When i call db.list_lang
|
37
|
+
Then the list should include "English"
|
38
|
+
|
39
|
+
|
data/kangaroo.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "kangaroo/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "kangaroo"
|
7
|
+
s.version = Kangaroo::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
10
|
+
s.authors = ["Michael Eickenberg", "Marian Theisen"]
|
11
|
+
s.email = 'marian@cice-online.net'
|
12
|
+
s.summary = "Kang! ActiveRecord-ish OpenObject"
|
13
|
+
s.homepage = "http://github.com/cice/kangARoo"
|
14
|
+
s.description = "ActiveRecord-ish OpenObject Wrapper"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'rapuncel', '~> 0.0.2'
|
22
|
+
s.add_dependency "activerecord", ">= 3.0.0"
|
23
|
+
s.add_dependency "activesupport", ">= 3.0.0"
|
24
|
+
|
25
|
+
s.add_development_dependency 'yard'
|
26
|
+
s.add_development_dependency 'rspec'
|
27
|
+
s.add_development_dependency 'ruby-debug'
|
28
|
+
s.add_development_dependency 'cucumber'
|
29
|
+
end
|
data/lib/kangaroo.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'active_model/dirty'
|
2
|
+
|
3
|
+
module Kangaroo
|
4
|
+
module Attributes
|
5
|
+
# @private
|
6
|
+
def self.included base
|
7
|
+
base.send :include, ActiveModel::Dirty
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
# Read an attribute value by name
|
12
|
+
#
|
13
|
+
# @param [String, Symbol] name attribute name
|
14
|
+
# @return attribute value
|
15
|
+
def read_attribute name
|
16
|
+
@attributes[name.to_s]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Write an attribute by name
|
20
|
+
#
|
21
|
+
# @param [String, Symbol] name attribute name
|
22
|
+
# @param value attribute value to set
|
23
|
+
# @return attribute value
|
24
|
+
def write_attribute name, value
|
25
|
+
attribute_will_change! name.to_s
|
26
|
+
@attributes[name.to_s] = value
|
27
|
+
end
|
28
|
+
|
29
|
+
# Mass set attributes. Attribute values are set via setters, not directly stored
|
30
|
+
# in the @attributes Hash.
|
31
|
+
#
|
32
|
+
# @param [Hash] attributes Hash of attribute names and values
|
33
|
+
# @return [Hash] attributes
|
34
|
+
def attributes= attributes
|
35
|
+
attributes.except('id', :id).map do |key_value|
|
36
|
+
__send__ "#{key_value.first}=", key_value.last
|
37
|
+
end
|
38
|
+
|
39
|
+
self.attributes
|
40
|
+
end
|
41
|
+
|
42
|
+
# Read all attributes. Attributes are read via getters.
|
43
|
+
#
|
44
|
+
# @return [Hash] attributes
|
45
|
+
def attributes
|
46
|
+
{}.tap do |attributes|
|
47
|
+
self.class.attribute_names.each do |key|
|
48
|
+
attributes[key] = send(key)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Freeze this object
|
54
|
+
def freeze
|
55
|
+
@changed_attributes.freeze
|
56
|
+
@attributes.freeze
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
# If you need to customize your models, e.g. add attributes
|
62
|
+
# not covered by fields_get, you can call {extend_attribute_methods}
|
63
|
+
#
|
64
|
+
# @param [Array] attributes list of attribute names to define accessors for
|
65
|
+
def extend_attribute_methods *attributes
|
66
|
+
attributes.flatten.each do |attr|
|
67
|
+
next if attribute_names.include?(attr.to_s)
|
68
|
+
define_accessors attr
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Define getters for attributes
|
73
|
+
#
|
74
|
+
# @param [Array] attribute_names
|
75
|
+
def define_getters *attribute_names
|
76
|
+
attribute_names.flatten.each do |name|
|
77
|
+
define_getter name
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Define getter
|
82
|
+
#
|
83
|
+
# @param [String, Symbol] attribute_name
|
84
|
+
def define_getter attribute_name
|
85
|
+
define_method attribute_name do
|
86
|
+
read_attribute attribute_name
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get a list of available attributes
|
91
|
+
#
|
92
|
+
# @return [Array] attribute names
|
93
|
+
def attribute_names
|
94
|
+
@attribute_names ||= []
|
95
|
+
end
|
96
|
+
|
97
|
+
# Define getter and setter for an attribute
|
98
|
+
#
|
99
|
+
# @param [String, Symbol] attribute_name
|
100
|
+
def define_accessors attribute_name
|
101
|
+
define_method attribute_name do
|
102
|
+
read_attribute attribute_name
|
103
|
+
end
|
104
|
+
|
105
|
+
define_method "#{attribute_name}=" do |value|
|
106
|
+
write_attribute attribute_name, value
|
107
|
+
end
|
108
|
+
|
109
|
+
attribute_names << attribute_name.to_s
|
110
|
+
end
|
111
|
+
|
112
|
+
# Define getters and setters for attributes
|
113
|
+
#
|
114
|
+
# @param [Array] attribute_names
|
115
|
+
def define_multiple_accessors *attribute_names
|
116
|
+
define_attribute_methods attribute_names.map(&:to_s)
|
117
|
+
|
118
|
+
attribute_names.each do |attribute_name|
|
119
|
+
define_accessors attribute_name
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'kangaroo/model/relation'
|
2
|
+
require 'kangaroo/model/attributes'
|
3
|
+
require 'kangaroo/model/default_attributes'
|
4
|
+
require 'kangaroo/model/inspector'
|
5
|
+
require 'kangaroo/model/persistence'
|
6
|
+
require 'kangaroo/model/open_object_orm'
|
7
|
+
require 'kangaroo/model/finder'
|
8
|
+
require 'kangaroo/model/remote_execute'
|
9
|
+
require 'active_model/callbacks'
|
10
|
+
require 'active_support/core_ext/class'
|
11
|
+
|
12
|
+
module Kangaroo
|
13
|
+
module Model
|
14
|
+
class Base
|
15
|
+
class_attribute :database
|
16
|
+
class_inheritable_array :field_names
|
17
|
+
|
18
|
+
extend ActiveModel::Callbacks
|
19
|
+
define_model_callbacks :initialize
|
20
|
+
|
21
|
+
include Attributes
|
22
|
+
include Persistence
|
23
|
+
include DefaultAttributes
|
24
|
+
include Inspector
|
25
|
+
extend OpenObjectOrm
|
26
|
+
extend Finder
|
27
|
+
include RemoteExecute
|
28
|
+
|
29
|
+
attr_reader :id
|
30
|
+
|
31
|
+
# Initialize a new object, and set attributes
|
32
|
+
#
|
33
|
+
# @param [Hash] attributes
|
34
|
+
def initialize attributes = {}
|
35
|
+
@attributes = {}
|
36
|
+
|
37
|
+
_run_initialize_callbacks do
|
38
|
+
self.attributes = attributes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Send method calls via xmlrpc to OpenERP
|
43
|
+
#
|
44
|
+
def remote
|
45
|
+
self.class.remote
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
def fields
|
50
|
+
@fields ||= fields_get
|
51
|
+
end
|
52
|
+
|
53
|
+
def namespace
|
54
|
+
("::" + name.match(/^(?:\:\:)?([^\:]+)/)[1]).constantize
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return this models OpenObject name
|
58
|
+
def oo_name
|
59
|
+
namespace.ruby_to_oo self.name
|
60
|
+
end
|
61
|
+
|
62
|
+
# Send method calls via xmlrpc to OpenERP
|
63
|
+
#
|
64
|
+
def remote
|
65
|
+
@remote ||= database.object oo_name
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Kangaroo
|
2
|
+
module Model
|
3
|
+
module ConditionNormalizer
|
4
|
+
CONDITION_OPERATORS = *%w(= != > >= < <= ilike like in child_of parent_left parent_right).freeze
|
5
|
+
CONDITION_PATTERN = /\A(.*)\s+(#{CONDITION_OPERATORS * "|"})\s+(.*)\Z/i.freeze
|
6
|
+
|
7
|
+
protected
|
8
|
+
def normalize_conditions conditions
|
9
|
+
conditions = if Hash === conditions
|
10
|
+
return [] if conditions.blank?
|
11
|
+
[conditions]
|
12
|
+
else
|
13
|
+
Array(conditions)
|
14
|
+
end
|
15
|
+
|
16
|
+
conditions.map do |condition|
|
17
|
+
normalize_condition condition
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def normalize_condition condition
|
22
|
+
case condition
|
23
|
+
when Array
|
24
|
+
condition
|
25
|
+
when Hash
|
26
|
+
convert_hash_condition condition
|
27
|
+
when String
|
28
|
+
convert_string_condition condition
|
29
|
+
else
|
30
|
+
raise "Expected Array, Hash or String"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def convert_hash_condition condition
|
35
|
+
condition.sum([]) do |key_val|
|
36
|
+
convert_key_value_condition *key_val
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def convert_key_value_condition field, value
|
41
|
+
operator = if Array === value
|
42
|
+
value = value.map &:to_s
|
43
|
+
'in'
|
44
|
+
else
|
45
|
+
value = value.to_s
|
46
|
+
'='
|
47
|
+
end
|
48
|
+
|
49
|
+
[field.to_s, operator, value]
|
50
|
+
end
|
51
|
+
|
52
|
+
def convert_string_condition string
|
53
|
+
# Ugly workaround, if you know how to make 'not in' work along the other operators
|
54
|
+
# with a single RegExp, please let me now
|
55
|
+
if (key_val = string.split("not in")).length > 1
|
56
|
+
[key_val.first.strip, 'not in', key_val.last.strip]
|
57
|
+
else
|
58
|
+
CONDITION_PATTERN.match(string).try(:captures) || string
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kangaroo
|
2
|
+
module DefaultAttributes
|
3
|
+
# @private
|
4
|
+
def self.included klass
|
5
|
+
klass.extend ClassMethods
|
6
|
+
|
7
|
+
klass.before_initialize do
|
8
|
+
return true if persisted?
|
9
|
+
|
10
|
+
self.class.default_attributes.each do |name, value|
|
11
|
+
write_attribute name, value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def default_attributes
|
18
|
+
default_get :fields => attribute_names
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'kangaroo/model/attributes'
|
2
|
+
|
3
|
+
module Kangaroo
|
4
|
+
module Model
|
5
|
+
class Field
|
6
|
+
include Attributes
|
7
|
+
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
def initialize name, attributes = {}
|
11
|
+
@attributes = {}
|
12
|
+
@name = name
|
13
|
+
|
14
|
+
attributes.each do |key, val|
|
15
|
+
write_attribute key, val
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|