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.
Files changed (99) hide show
  1. data/.gitignore +6 -1
  2. data/Gemfile +11 -0
  3. data/README.md +23 -132
  4. data/Rakefile +0 -8
  5. data/bin/kang +5 -64
  6. data/bin/kangdoc +21 -0
  7. data/bin/kangviz +21 -0
  8. data/config/kangaroo.yml.sample +12 -2
  9. data/docs/Architecture.md +1 -0
  10. data/docs/Classes.md +67 -0
  11. data/docs/Installation.md +2 -1
  12. data/docs/Usage.md +1 -0
  13. data/kangaroo.gemspec +8 -8
  14. data/lib/kangaroo.rb +3 -2
  15. data/lib/kangaroo/commands/base.rb +123 -0
  16. data/lib/kangaroo/commands/cli.rb +65 -0
  17. data/lib/kangaroo/commands/doc.rb +44 -0
  18. data/lib/kangaroo/commands/endpoint.rb +33 -0
  19. data/lib/kangaroo/commands/viz.rb +58 -0
  20. data/lib/kangaroo/doc.rb +2 -0
  21. data/lib/kangaroo/exception.rb +3 -0
  22. data/lib/kangaroo/hirb.rb +2 -1
  23. data/lib/kangaroo/model/associations.rb +33 -0
  24. data/lib/kangaroo/model/associations/many2one.rb +43 -0
  25. data/lib/kangaroo/model/associations/one2many.rb +41 -0
  26. data/lib/kangaroo/model/attributes.rb +88 -93
  27. data/lib/kangaroo/model/base.rb +44 -15
  28. data/lib/kangaroo/model/condition_normalizer.rb +7 -7
  29. data/lib/kangaroo/model/data_import.rb +28 -0
  30. data/lib/kangaroo/model/default_attributes.rb +20 -14
  31. data/lib/kangaroo/model/dynamic_finder.rb +42 -0
  32. data/lib/kangaroo/model/field.rb +52 -1
  33. data/lib/kangaroo/model/field/readonly.rb +39 -0
  34. data/lib/kangaroo/model/finder.rb +6 -2
  35. data/lib/kangaroo/model/inspector.rb +1 -4
  36. data/lib/kangaroo/model/mass_import.rb +42 -0
  37. data/lib/kangaroo/model/open_object_orm.rb +51 -5
  38. data/lib/kangaroo/model/persistence.rb +43 -19
  39. data/lib/kangaroo/model/readonly_attributes.rb +43 -0
  40. data/lib/kangaroo/model/relation.rb +40 -9
  41. data/lib/kangaroo/model/remote_execute.rb +1 -1
  42. data/lib/kangaroo/model/required_attributes.rb +26 -0
  43. data/lib/kangaroo/railtie.rb +13 -3
  44. data/lib/kangaroo/ruby_adapter/base.rb +2 -1
  45. data/lib/kangaroo/ruby_adapter/class_definition.rb +18 -3
  46. data/lib/kangaroo/ruby_adapter/fields.rb +27 -2
  47. data/lib/kangaroo/ruby_adapter/many2one.rb +38 -0
  48. data/lib/kangaroo/ruby_adapter/one2many.rb +31 -0
  49. data/lib/kangaroo/util/client.rb +29 -4
  50. data/lib/kangaroo/util/configuration.rb +15 -10
  51. data/lib/kangaroo/util/database.rb +8 -8
  52. data/lib/kangaroo/util/loader.rb +18 -22
  53. data/lib/kangaroo/util/loader/information_repository.rb +56 -0
  54. data/lib/kangaroo/util/loader/namespace.rb +1 -1
  55. data/lib/kangaroo/util/loader/reflection.rb +61 -0
  56. data/lib/kangaroo/util/loader/root_namespace.rb +12 -21
  57. data/lib/kangaroo/util/proxy.rb +9 -0
  58. data/lib/kangaroo/util/proxy/common.rb +28 -4
  59. data/lib/kangaroo/util/proxy/db.rb +14 -0
  60. data/lib/kangaroo/util/proxy/object.rb +40 -1
  61. data/lib/kangaroo/util/proxy/superadmin.rb +13 -0
  62. data/lib/kangaroo/version.rb +1 -1
  63. data/lib/kangaroo/viz.rb +1 -0
  64. data/lib/kangaroo/viz/base.rb +92 -0
  65. data/spec/commands/base_spec.rb +42 -0
  66. data/spec/functional/associations/many2one_spec.rb +72 -0
  67. data/spec/functional/associations/one2many_spec.rb +65 -0
  68. data/spec/functional/common_service_spec.rb +25 -0
  69. data/spec/functional/data_import_spec.rb +48 -0
  70. data/spec/functional/dynamic_finder_spec.rb +35 -0
  71. data/spec/functional/exception_handling_spec.rb +18 -0
  72. data/spec/functional/identity_spec.rb +48 -0
  73. data/spec/functional/import_export_spec.rb +39 -0
  74. data/spec/functional/lazy_loading_spec.rb +18 -11
  75. data/spec/functional/ordering_spec.rb +33 -0
  76. data/spec/functional/readonly_attributes_spec.rb +37 -0
  77. data/spec/functional/required_attributes_spec.rb +37 -0
  78. data/spec/functional/root_namespace_spec.rb +19 -0
  79. data/spec/functional/select_relation_spec.rb +26 -0
  80. data/spec/model/attributes_spec.rb +1 -0
  81. data/spec/model/base_spec.rb +1 -0
  82. data/spec/model/default_attributes_spec.rb +3 -1
  83. data/spec/model/finder_spec.rb +2 -1
  84. data/spec/model/inspector_spec.rb +1 -0
  85. data/spec/model/open_object_orm_spec.rb +5 -2
  86. data/spec/model/persistence_spec.rb +1 -0
  87. data/spec/model/relation_spec.rb +2 -2
  88. data/spec/ruby_adapter/class_definition_spec.rb +1 -0
  89. data/spec/server_helper.rb +0 -1
  90. data/spec/spec_helper.rb +4 -1
  91. data/spec/util/loader_spec.rb +6 -6
  92. metadata +152 -159
  93. data/Gemfile.lock +0 -69
  94. data/features/configuration.feature +0 -10
  95. data/features/env.rb +0 -8
  96. data/features/step_definitions/basic_steps.rb +0 -18
  97. data/features/step_definitions/configuration_steps.rb +0 -21
  98. data/features/support/test.yml +0 -11
  99. 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 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
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
- 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
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
- # 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}
22
+ # Write an attribute by name
63
23
  #
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
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
- # Define getters for attributes
33
+ # Mass set attributes. Attribute values are set via setters, not directly stored
34
+ # in the @attributes Hash.
73
35
  #
74
- # @param [Array] attribute_names
75
- def define_getters *attribute_names
76
- attribute_names.flatten.each do |name|
77
- define_getter name
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
- # Define getter
46
+ # Read all attributes. Attributes are read via getters.
82
47
  #
83
- # @param [String, Symbol] attribute_name
84
- def define_getter attribute_name
85
- define_method attribute_name do
86
- read_attribute attribute_name
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
- # Get a list of available attributes
91
- #
92
- # @return [Array] attribute names
93
- def attribute_names
94
- @attribute_names ||= []
57
+ # Freeze this object
58
+ def freeze
59
+ @changed_attributes.freeze
60
+ @attributes.freeze
61
+ super
95
62
  end
96
63
 
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
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
- define_method "#{attribute_name}=" do |value|
106
- write_attribute attribute_name, value
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
- attribute_names << attribute_name.to_s
110
- end
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
- # 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)
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
- attribute_names.each do |attribute_name|
119
- define_accessors attribute_name
112
+ attribute_names.each do |attribute_name|
113
+ define_accessors attribute_name
114
+ end
120
115
  end
121
116
  end
122
117
  end
@@ -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 'active_model/callbacks'
10
- require 'active_support/core_ext/class'
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 OpenObjectOrm
26
- extend Finder
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 fields
50
- @fields ||= fields_get
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
- # Return this models OpenObject name
58
- def oo_name
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.map do |condition|
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.sum([]) do |key_val|
36
- convert_key_value_condition *key_val
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.to_s
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