kangaroo 0.0.3 → 0.1.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -1
- data/Gemfile +11 -0
- data/README.md +23 -132
- data/Rakefile +0 -8
- data/bin/kang +5 -64
- data/bin/kangdoc +21 -0
- data/bin/kangviz +21 -0
- data/config/kangaroo.yml.sample +12 -2
- data/docs/Architecture.md +1 -0
- data/docs/Classes.md +67 -0
- data/docs/Installation.md +2 -1
- data/docs/Usage.md +1 -0
- data/kangaroo.gemspec +8 -8
- data/lib/kangaroo.rb +3 -2
- data/lib/kangaroo/commands/base.rb +123 -0
- data/lib/kangaroo/commands/cli.rb +65 -0
- data/lib/kangaroo/commands/doc.rb +44 -0
- data/lib/kangaroo/commands/endpoint.rb +33 -0
- data/lib/kangaroo/commands/viz.rb +58 -0
- data/lib/kangaroo/doc.rb +2 -0
- data/lib/kangaroo/exception.rb +3 -0
- data/lib/kangaroo/hirb.rb +2 -1
- data/lib/kangaroo/model/associations.rb +33 -0
- data/lib/kangaroo/model/associations/many2one.rb +43 -0
- data/lib/kangaroo/model/associations/one2many.rb +41 -0
- data/lib/kangaroo/model/attributes.rb +88 -93
- data/lib/kangaroo/model/base.rb +44 -15
- data/lib/kangaroo/model/condition_normalizer.rb +7 -7
- data/lib/kangaroo/model/data_import.rb +28 -0
- data/lib/kangaroo/model/default_attributes.rb +20 -14
- data/lib/kangaroo/model/dynamic_finder.rb +42 -0
- data/lib/kangaroo/model/field.rb +52 -1
- data/lib/kangaroo/model/field/readonly.rb +39 -0
- data/lib/kangaroo/model/finder.rb +6 -2
- data/lib/kangaroo/model/inspector.rb +1 -4
- data/lib/kangaroo/model/mass_import.rb +42 -0
- data/lib/kangaroo/model/open_object_orm.rb +51 -5
- data/lib/kangaroo/model/persistence.rb +43 -19
- data/lib/kangaroo/model/readonly_attributes.rb +43 -0
- data/lib/kangaroo/model/relation.rb +40 -9
- data/lib/kangaroo/model/remote_execute.rb +1 -1
- data/lib/kangaroo/model/required_attributes.rb +26 -0
- data/lib/kangaroo/railtie.rb +13 -3
- data/lib/kangaroo/ruby_adapter/base.rb +2 -1
- data/lib/kangaroo/ruby_adapter/class_definition.rb +18 -3
- data/lib/kangaroo/ruby_adapter/fields.rb +27 -2
- data/lib/kangaroo/ruby_adapter/many2one.rb +38 -0
- data/lib/kangaroo/ruby_adapter/one2many.rb +31 -0
- data/lib/kangaroo/util/client.rb +29 -4
- data/lib/kangaroo/util/configuration.rb +15 -10
- data/lib/kangaroo/util/database.rb +8 -8
- data/lib/kangaroo/util/loader.rb +18 -22
- data/lib/kangaroo/util/loader/information_repository.rb +56 -0
- data/lib/kangaroo/util/loader/namespace.rb +1 -1
- data/lib/kangaroo/util/loader/reflection.rb +61 -0
- data/lib/kangaroo/util/loader/root_namespace.rb +12 -21
- data/lib/kangaroo/util/proxy.rb +9 -0
- data/lib/kangaroo/util/proxy/common.rb +28 -4
- data/lib/kangaroo/util/proxy/db.rb +14 -0
- data/lib/kangaroo/util/proxy/object.rb +40 -1
- data/lib/kangaroo/util/proxy/superadmin.rb +13 -0
- data/lib/kangaroo/version.rb +1 -1
- data/lib/kangaroo/viz.rb +1 -0
- data/lib/kangaroo/viz/base.rb +92 -0
- data/spec/commands/base_spec.rb +42 -0
- data/spec/functional/associations/many2one_spec.rb +72 -0
- data/spec/functional/associations/one2many_spec.rb +65 -0
- data/spec/functional/common_service_spec.rb +25 -0
- data/spec/functional/data_import_spec.rb +48 -0
- data/spec/functional/dynamic_finder_spec.rb +35 -0
- data/spec/functional/exception_handling_spec.rb +18 -0
- data/spec/functional/identity_spec.rb +48 -0
- data/spec/functional/import_export_spec.rb +39 -0
- data/spec/functional/lazy_loading_spec.rb +18 -11
- data/spec/functional/ordering_spec.rb +33 -0
- data/spec/functional/readonly_attributes_spec.rb +37 -0
- data/spec/functional/required_attributes_spec.rb +37 -0
- data/spec/functional/root_namespace_spec.rb +19 -0
- data/spec/functional/select_relation_spec.rb +26 -0
- data/spec/model/attributes_spec.rb +1 -0
- data/spec/model/base_spec.rb +1 -0
- data/spec/model/default_attributes_spec.rb +3 -1
- data/spec/model/finder_spec.rb +2 -1
- data/spec/model/inspector_spec.rb +1 -0
- data/spec/model/open_object_orm_spec.rb +5 -2
- data/spec/model/persistence_spec.rb +1 -0
- data/spec/model/relation_spec.rb +2 -2
- data/spec/ruby_adapter/class_definition_spec.rb +1 -0
- data/spec/server_helper.rb +0 -1
- data/spec/spec_helper.rb +4 -1
- data/spec/util/loader_spec.rb +6 -6
- metadata +152 -159
- data/Gemfile.lock +0 -69
- data/features/configuration.feature +0 -10
- data/features/env.rb +0 -8
- data/features/step_definitions/basic_steps.rb +0 -18
- data/features/step_definitions/configuration_steps.rb +0 -21
- data/features/support/test.yml +0 -11
- data/features/utility_services.feature +0 -33
@@ -0,0 +1,43 @@
|
|
1
|
+
module Kangaroo
|
2
|
+
module Model
|
3
|
+
module Associations
|
4
|
+
module Many2one
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def read_many2one_id_for field
|
8
|
+
field_value = send field.name
|
9
|
+
|
10
|
+
if Array === field_value
|
11
|
+
field_value.first
|
12
|
+
else
|
13
|
+
field_value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_many2one_id_for field, id
|
18
|
+
send field.setter_name, id
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_many2one_name_for field
|
22
|
+
field_value = send field.name
|
23
|
+
|
24
|
+
if Array === field_value
|
25
|
+
field_value.last
|
26
|
+
else
|
27
|
+
read_many2one_obj_for(field).try :name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_many2one_obj_for field
|
32
|
+
id = read_many2one_id_for(field)
|
33
|
+
|
34
|
+
field.relation_class.find_by_id id
|
35
|
+
end
|
36
|
+
|
37
|
+
def write_many2one_obj_for field, obj
|
38
|
+
write_many2one_id_for field, obj.id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Kangaroo
|
2
|
+
module Model
|
3
|
+
module Associations
|
4
|
+
module One2many
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def read_one2many_ids_for field
|
8
|
+
field_value = send field.name
|
9
|
+
return unless Array === field_value
|
10
|
+
|
11
|
+
if Array === field_value.first
|
12
|
+
field_value.first.last
|
13
|
+
else
|
14
|
+
field_value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def write_one2many_ids_for field, ids
|
19
|
+
send field.setter_name, coerce_one2many_ids(ids)
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_one2many_objs_for field
|
23
|
+
ids = read_one2many_ids_for field
|
24
|
+
|
25
|
+
field.relation_class.where(:id => ids)
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_one2many_objs_for field, objs
|
29
|
+
ids = objs.map &:id
|
30
|
+
|
31
|
+
write_one2many_ids_for field, ids
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def coerce_one2many_ids ids
|
36
|
+
[[6, 0, ids]]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,122 +1,117 @@
|
|
1
1
|
require 'active_model/dirty'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
2
3
|
|
3
4
|
module Kangaroo
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
5
|
+
module Model
|
6
|
+
module Attributes
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
include ActiveModel::Dirty
|
11
|
+
class_attribute :attribute_names
|
37
12
|
end
|
38
13
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
def attributes
|
46
|
-
{}.tap do |attributes|
|
47
|
-
self.class.attribute_names.each do |key|
|
48
|
-
attributes[key] = send(key)
|
49
|
-
end
|
14
|
+
# Read an attribute value by name
|
15
|
+
#
|
16
|
+
# @param [String, Symbol] name attribute name
|
17
|
+
# @return attribute value
|
18
|
+
def read_attribute name
|
19
|
+
@attributes[name.to_s]
|
50
20
|
end
|
51
|
-
end
|
52
21
|
|
53
|
-
|
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}
|
22
|
+
# Write an attribute by name
|
63
23
|
#
|
64
|
-
# @param [
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
24
|
+
# @param [String, Symbol] name attribute name
|
25
|
+
# @param value attribute value to set
|
26
|
+
# @return attribute value
|
27
|
+
def write_attribute name, value
|
28
|
+
name = name.to_s
|
29
|
+
attribute_will_change! name unless @attributes[name] == value
|
30
|
+
@attributes[name] = value
|
70
31
|
end
|
71
32
|
|
72
|
-
#
|
33
|
+
# Mass set attributes. Attribute values are set via setters, not directly stored
|
34
|
+
# in the @attributes Hash.
|
73
35
|
#
|
74
|
-
# @param [
|
75
|
-
|
76
|
-
|
77
|
-
|
36
|
+
# @param [Hash] attributes Hash of attribute names and values
|
37
|
+
# @return [Hash] attributes
|
38
|
+
def attributes= attributes
|
39
|
+
attributes.except('id', :id).map do |key_value|
|
40
|
+
__send__ "#{key_value.first}=", key_value.last
|
78
41
|
end
|
42
|
+
|
43
|
+
self.attributes
|
79
44
|
end
|
80
45
|
|
81
|
-
#
|
46
|
+
# Read all attributes. Attributes are read via getters.
|
82
47
|
#
|
83
|
-
# @
|
84
|
-
def
|
85
|
-
|
86
|
-
|
48
|
+
# @return [Hash] attributes
|
49
|
+
def attributes
|
50
|
+
{}.tap do |attributes|
|
51
|
+
attribute_names.each do |key|
|
52
|
+
attributes[key] = send(key)
|
53
|
+
end
|
87
54
|
end
|
88
55
|
end
|
89
56
|
|
90
|
-
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
57
|
+
# Freeze this object
|
58
|
+
def freeze
|
59
|
+
@changed_attributes.freeze
|
60
|
+
@attributes.freeze
|
61
|
+
super
|
95
62
|
end
|
96
63
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
64
|
+
module ClassMethods
|
65
|
+
# If you need to customize your models, e.g. add attributes
|
66
|
+
# not covered by fields_get, you can call {extend_attribute_methods}
|
67
|
+
#
|
68
|
+
# @param [Array] attributes list of attribute names to define accessors for
|
69
|
+
def extend_attribute_methods *attributes
|
70
|
+
attributes.flatten.each do |attr|
|
71
|
+
next if attribute_names.include?(attr.to_s)
|
72
|
+
define_accessors attr
|
73
|
+
end
|
103
74
|
end
|
104
75
|
|
105
|
-
|
106
|
-
|
76
|
+
# Define setter
|
77
|
+
#
|
78
|
+
# @param [String, Symbol] attribute_name
|
79
|
+
def define_setter attribute_name
|
80
|
+
define_method "#{attribute_name}=" do |value|
|
81
|
+
write_attribute attribute_name, value
|
82
|
+
end
|
107
83
|
end
|
108
84
|
|
109
|
-
|
110
|
-
|
85
|
+
# Define getter
|
86
|
+
#
|
87
|
+
# @param [String, Symbol] attribute_name
|
88
|
+
def define_getter attribute_name
|
89
|
+
define_method attribute_name do
|
90
|
+
read_attribute attribute_name
|
91
|
+
end
|
92
|
+
end
|
111
93
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
94
|
+
# Define getter and setter for an attribute
|
95
|
+
#
|
96
|
+
# @param [String, Symbol] attribute_name
|
97
|
+
def define_accessors attribute_name
|
98
|
+
define_getter attribute_name
|
99
|
+
define_setter attribute_name
|
100
|
+
|
101
|
+
self.attribute_names ||= []
|
102
|
+
attribute_names << attribute_name.to_s
|
103
|
+
attribute_names.uniq!
|
104
|
+
end
|
105
|
+
|
106
|
+
# Define getters and setters for attributes
|
107
|
+
#
|
108
|
+
# @param [Array] attribute_names
|
109
|
+
def define_multiple_accessors *attribute_names
|
110
|
+
define_attribute_methods attribute_names.map(&:to_s)
|
117
111
|
|
118
|
-
|
119
|
-
|
112
|
+
attribute_names.each do |attribute_name|
|
113
|
+
define_accessors attribute_name
|
114
|
+
end
|
120
115
|
end
|
121
116
|
end
|
122
117
|
end
|
data/lib/kangaroo/model/base.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'active_support/core_ext/class'
|
3
|
+
|
1
4
|
require 'kangaroo/model/relation'
|
2
5
|
require 'kangaroo/model/attributes'
|
3
6
|
require 'kangaroo/model/default_attributes'
|
@@ -6,13 +9,18 @@ require 'kangaroo/model/persistence'
|
|
6
9
|
require 'kangaroo/model/open_object_orm'
|
7
10
|
require 'kangaroo/model/finder'
|
8
11
|
require 'kangaroo/model/remote_execute'
|
9
|
-
require '
|
10
|
-
require '
|
12
|
+
require 'kangaroo/model/readonly_attributes'
|
13
|
+
require 'kangaroo/model/required_attributes'
|
14
|
+
require 'kangaroo/model/data_import'
|
15
|
+
require 'kangaroo/model/dynamic_finder'
|
16
|
+
require 'kangaroo/model/associations'
|
17
|
+
require 'kangaroo/model/mass_import'
|
18
|
+
require 'kangaroo/util/loader/namespace'
|
11
19
|
|
12
20
|
module Kangaroo
|
13
21
|
module Model
|
14
22
|
class Base
|
15
|
-
class_attribute :database
|
23
|
+
class_attribute :database, :namespace, :oo_name, :oo_model
|
16
24
|
class_inheritable_array :field_names
|
17
25
|
|
18
26
|
extend ActiveModel::Callbacks
|
@@ -22,10 +30,17 @@ module Kangaroo
|
|
22
30
|
include Persistence
|
23
31
|
include DefaultAttributes
|
24
32
|
include Inspector
|
25
|
-
extend
|
26
|
-
extend
|
33
|
+
extend OpenObjectOrm
|
34
|
+
extend Finder
|
27
35
|
include RemoteExecute
|
28
|
-
|
36
|
+
extend ReadonlyAttributes
|
37
|
+
include RequiredAttributes
|
38
|
+
extend DataImport
|
39
|
+
extend DynamicFinder
|
40
|
+
include Associations
|
41
|
+
include MassImport
|
42
|
+
extend Util::Loader::Namespace
|
43
|
+
|
29
44
|
attr_reader :id
|
30
45
|
|
31
46
|
# Initialize a new object, and set attributes
|
@@ -44,19 +59,22 @@ module Kangaroo
|
|
44
59
|
def remote
|
45
60
|
self.class.remote
|
46
61
|
end
|
62
|
+
|
63
|
+
def == other
|
64
|
+
if new_record?
|
65
|
+
false
|
66
|
+
else
|
67
|
+
self.class === other and id == other.id
|
68
|
+
end
|
69
|
+
end
|
47
70
|
|
48
71
|
class << self
|
49
|
-
def
|
50
|
-
@
|
51
|
-
end
|
52
|
-
|
53
|
-
def namespace
|
54
|
-
("::" + name.match(/^(?:\:\:)?([^\:]+)/)[1]).constantize
|
72
|
+
def fields_hash
|
73
|
+
@fields_hash ||= fields_to_hash(fields_get)
|
55
74
|
end
|
56
75
|
|
57
|
-
|
58
|
-
|
59
|
-
namespace.ruby_to_oo self.name
|
76
|
+
def fields
|
77
|
+
@fields ||= fields_hash.values
|
60
78
|
end
|
61
79
|
|
62
80
|
# Send method calls via xmlrpc to OpenERP
|
@@ -64,6 +82,17 @@ module Kangaroo
|
|
64
82
|
def remote
|
65
83
|
@remote ||= database.object oo_name
|
66
84
|
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
def fields_to_hash fields
|
88
|
+
return nil if fields.nil?
|
89
|
+
|
90
|
+
{}.tap do |h|
|
91
|
+
fields.each do |field|
|
92
|
+
h[field.name] = field
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
67
96
|
end
|
68
97
|
end
|
69
98
|
end
|
@@ -13,7 +13,7 @@ module Kangaroo
|
|
13
13
|
Array(conditions)
|
14
14
|
end
|
15
15
|
|
16
|
-
conditions.
|
16
|
+
conditions.sum([]) do |condition|
|
17
17
|
normalize_condition condition
|
18
18
|
end
|
19
19
|
end
|
@@ -21,7 +21,7 @@ module Kangaroo
|
|
21
21
|
def normalize_condition condition
|
22
22
|
case condition
|
23
23
|
when Array
|
24
|
-
condition
|
24
|
+
[condition]
|
25
25
|
when Hash
|
26
26
|
convert_hash_condition condition
|
27
27
|
when String
|
@@ -32,8 +32,8 @@ module Kangaroo
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def convert_hash_condition condition
|
35
|
-
condition.
|
36
|
-
convert_key_value_condition
|
35
|
+
condition.map do |key_val|
|
36
|
+
convert_key_value_condition(*key_val)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -42,7 +42,7 @@ module Kangaroo
|
|
42
42
|
value = value.map &:to_s
|
43
43
|
'in'
|
44
44
|
else
|
45
|
-
value = value
|
45
|
+
value = value
|
46
46
|
'='
|
47
47
|
end
|
48
48
|
|
@@ -53,9 +53,9 @@ module Kangaroo
|
|
53
53
|
# Ugly workaround, if you know how to make 'not in' work along the other operators
|
54
54
|
# with a single RegExp, please let me now
|
55
55
|
if (key_val = string.split("not in")).length > 1
|
56
|
-
[key_val.first.strip, 'not in', key_val.last.strip]
|
56
|
+
[[key_val.first.strip, 'not in', key_val.last.strip]]
|
57
57
|
else
|
58
|
-
CONDITION_PATTERN.match(string).try(:captures) || string
|
58
|
+
[CONDITION_PATTERN.match(string).try(:captures) || string]
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Kangaroo
|
2
|
+
module Model
|
3
|
+
module DataImport
|
4
|
+
def import_all records, options = {}
|
5
|
+
fields = changed_fields_in records
|
6
|
+
datas = map_fields_in records, fields
|
7
|
+
|
8
|
+
fields << '.id'
|
9
|
+
import_data fields, datas, options
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
def changed_fields_in records
|
14
|
+
records.sum([]) do |record|
|
15
|
+
record.changed
|
16
|
+
end.uniq
|
17
|
+
end
|
18
|
+
|
19
|
+
def map_fields_in records, fields
|
20
|
+
records.map do |record|
|
21
|
+
fields.map do |field|
|
22
|
+
record.read_attribute field
|
23
|
+
end + [record.id]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|