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
@@ -6,7 +6,12 @@ require 'kangaroo/util/loader'
6
6
  module Kangaroo
7
7
  module Util
8
8
  class Configuration
9
- attr_accessor :logger, :database, :models, :client
9
+ Defaults = {
10
+ 'host' => 'localhost',
11
+ 'port' => 8069
12
+ }
13
+
14
+ attr_accessor :logger, :database, :models, :client, :namespace
10
15
 
11
16
  # Initialize the Kangaroo configuration
12
17
  #
@@ -25,14 +30,13 @@ module Kangaroo
25
30
  # Load configured models with {Kangaroo::Util::Loader Loader}
26
31
  #
27
32
  def load_models
28
- if models.blank?
29
- logger.info "No models to load."
30
- return
31
- end
32
-
33
33
  login
34
- Loader.new(models, @database).load!
35
- logger.info "Loaded OpenERP models matching #{models.inspect}."
34
+
35
+ loaded_models = Loader.new(models, @database, @namespace).load!
36
+ loaded_models ||= []
37
+ logger.info "Loaded OpenERP models matching #{models.inspect} into namespace #{@namespace}: #{loaded_models.map(&:name).join(', ')}" if models
38
+
39
+ loaded_models
36
40
  rescue Exception => e
37
41
  logger.error "Loading of OpenERP models failed.\n#{e.inspect}"
38
42
  end
@@ -63,8 +67,9 @@ module Kangaroo
63
67
  # @option db_config [String] 'password' Password for authentication
64
68
  # @option db_config [Enumerable] 'models' List of models(-patterns) to load
65
69
  def configure_database db_config
66
- @database = Database.new @client, *db_config.values_at('name', 'user', 'password')
67
- @models = db_config['models']
70
+ @database = Database.new @client, *db_config.values_at('name', 'user', 'password')
71
+ @models = db_config['models']
72
+ @namespace = db_config['namespace'] || "Oo"
68
73
  logger.info %Q(Configured OpenERP database "#{db_config['name']}" at "#{client.connection.host}")
69
74
  end
70
75
 
@@ -16,49 +16,49 @@ module Kangaroo
16
16
  # Access to the {Kangaroo::Util::Proxy::Superadmin Superadmin Proxy}
17
17
  #
18
18
  # @param super_password superadmin password
19
- # @return superadmin service proxy
19
+ # @return [Kangaroo::Util::Proxy::Superadmin] superadmin service proxy
20
20
  def superadmin super_password
21
21
  client.superadmin super_password
22
22
  end
23
23
 
24
24
  # Access to the {Kangaroo::Util::Proxy::Db Database Proxy}
25
25
  #
26
- # @return database service proxy
26
+ # @return [Kangaroo::Util::Proxy::Db] database service proxy
27
27
  def db
28
28
  client.db
29
29
  end
30
30
 
31
31
  # Access to the {Kangaroo::Util::Proxy::Common Common Proxy}
32
32
  #
33
- # @return common service proxy
33
+ # @return [Kangaroo::Util::Proxy::Common] common service proxy
34
34
  def common
35
35
  client.common
36
36
  end
37
37
 
38
38
  # Access to the {Kangaroo::Util::Proxy::Workflow Workflow Proxy}
39
39
  #
40
- # @return workflow service proxy
40
+ # @return [Kangaroo::Util::Proxy::Workflow] workflow service proxy
41
41
  def workflow
42
42
  @workflow_proxy ||= Proxy::Workflow.new client.object_service, db_name, user_id, password
43
43
  end
44
44
 
45
- # Access to the {Kangaroo::Util::Proxy::Object Object Proxy}
45
+ # Access to the Kangaroo::Util::Proxy::Object
46
46
  #
47
- # @return object service proxy
47
+ # @return [Kangaroo::Util::Proxy::Object] object service proxy
48
48
  def object model_name
49
49
  Proxy::Object.new client.object_service, db_name, user_id, password, model_name
50
50
  end
51
51
 
52
52
  # Access to the {Kangaroo::Util::Proxy::Wizard Wizard Proxy}
53
53
  #
54
- # @return wizard service proxy
54
+ # @return [Kangaroo::Util::Proxy::Wizard] wizard service proxy
55
55
  def wizard
56
56
  @wizard_proxy ||= Proxy::Wizard.new client.wizard_service, db_name, user_id, password
57
57
  end
58
58
 
59
59
  # Access to the {Kangaroo::Util::Proxy::Report Report Proxy}
60
60
  #
61
- # @return report service proxy
61
+ # @return [Kangaroo::Util::Proxy::Report] report service proxy
62
62
  def report
63
63
  @report_proxy ||= Proxy::Report.new client.report_service, db_name, user_id, password
64
64
  end
@@ -4,9 +4,12 @@ require 'kangaroo/ruby_adapter/base'
4
4
  module Kangaroo
5
5
  module Util
6
6
  class Loader
7
- autoload :Model, 'kangaroo/util/loader/model'
8
- autoload :Namespace, 'kangaroo/util/loader/namespace'
9
- autoload :RootNamespace, 'kangaroo/util/loader/root_namespace'
7
+ autoload :Model, 'kangaroo/util/loader/model'
8
+ autoload :Namespace, 'kangaroo/util/loader/namespace'
9
+ autoload :RootNamespace, 'kangaroo/util/loader/root_namespace'
10
+ autoload :Reflection, 'kangaroo/util/loader/reflection'
11
+ autoload :InformationRepository, 'kangaroo/util/loader/information_repository'
12
+
10
13
  attr_accessor :model_names, :models, :database, :namespace
11
14
 
12
15
  # Initialize a Loader instance
@@ -17,6 +20,7 @@ module Kangaroo
17
20
  @database = database
18
21
  @model_names = model_names
19
22
  sanitize_model_names
23
+ root_module.database = database
20
24
  end
21
25
 
22
26
  # Loads matching models and uses {Kangaroo::RubyAdapter::Base RubyAdapter} to
@@ -31,34 +35,26 @@ module Kangaroo
31
35
 
32
36
  protected
33
37
  def root_module
34
- namespace.constantize
38
+ namespace.constantize.tap do |ns|
39
+ unless ns.respond_to?(:namespace)
40
+ ns.send :extend, Kangaroo::Util::Loader::Namespace
41
+ end
42
+
43
+ unless ns.respond_to?(:oo_to_ruby)
44
+ ns.send :extend, Kangaroo::Util::Loader::RootNamespace
45
+ end
46
+ end
35
47
 
36
48
  rescue NameError
37
49
  eval <<-RUBY
38
50
  module #{namespace}
39
51
  extend Kangaroo::Util::Loader::RootNamespace
40
- extend Kangaroo::Util::Loader::Namespace
41
52
  end
42
53
  RUBY
43
54
  end
44
55
 
45
- def ir_module
46
- root_module.const_defined?("Ir") ?
47
- root_module.const_get("Ir") :
48
- root_module.const_set("Ir", Module.new)
49
- end
50
-
51
56
  def reflection_model
52
- ir_module.const_defined?("Model") ?
53
- ir_module.const_get("Model") :
54
- ir_module.const_set("Model", create_reflection_model)
55
- end
56
-
57
- def create_reflection_model
58
- Class.new(Kangaroo::Model::Base).tap do |model|
59
- model.send :include, Model
60
- model.database = database
61
- end
57
+ root_module.reflection_model
62
58
  end
63
59
 
64
60
  def load_oo_models
@@ -80,7 +76,7 @@ module Kangaroo
80
76
  def sanitize_model_names
81
77
  @model_names = case @model_names
82
78
  when nil, []
83
- raise 'No models specified.'
79
+ []
84
80
  when :all
85
81
  ['%']
86
82
  when String
@@ -0,0 +1,56 @@
1
+ module Kangaroo
2
+ module Util
3
+ class Loader
4
+ module InformationRepository
5
+ def ir_module
6
+ const_defined?("Ir") ?
7
+ const_get("Ir") :
8
+ define_ir_namespace
9
+ end
10
+
11
+ def values_model
12
+ ir_module.const_get('Values')
13
+ end
14
+
15
+ def ir_get key1, key2, model
16
+ model = ruby_to_oo model
17
+ results = values_model.remote.get key1, key2, [model]
18
+
19
+ {}.tap do |hsh|
20
+ results.each do |result|
21
+ id, name, value = result
22
+ hsh[name.to_sym] = value
23
+ end
24
+ end
25
+ end
26
+
27
+ def get_object_reference openerp_module, xml_id = nil
28
+ openerp_module, xml_id = coerce_xml_id openerp_module, xml_id
29
+
30
+ database.object('ir.model.data').get_object_reference openerp_module.to_s, xml_id.to_s
31
+ end
32
+
33
+ def by_xml_id openerp_module, xml_id = nil
34
+ type, id = get_object_reference openerp_module, xml_id
35
+
36
+ class_for(type).find id
37
+ end
38
+
39
+ private
40
+ def coerce_xml_id openerp_module, xml_id = nil
41
+ if xml_id.blank?
42
+ openerp_module.split('.')
43
+ else
44
+ [openerp_module, xml_id]
45
+ end
46
+ end
47
+
48
+ def define_ir_namespace
49
+ mod = Module.new
50
+ mod.send :extend, Kangaroo::Util::Loader::Namespace
51
+ const_set("Ir", mod)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -27,7 +27,7 @@ module Kangaroo
27
27
  else
28
28
  super
29
29
  end
30
- rescue
30
+ rescue Exception => e
31
31
  super
32
32
  end
33
33
  end
@@ -0,0 +1,61 @@
1
+ module Kangaroo
2
+ module Util
3
+ class Loader
4
+ module Reflection
5
+ attr_accessor :dont_load_models
6
+
7
+ # Return the Reflection model ('ir.model') for this namespace
8
+ def reflection_model
9
+ @reflection_model ||= begin
10
+ ir_module.const_defined?("Model") ?
11
+ ir_module.const_get("Model") :
12
+ ir_module.const_set("Model", create_reflection_model)
13
+ end
14
+ end
15
+
16
+ # Check if a model exists, accepts Ruby or OpenObject name parameter
17
+ def model_exists? name
18
+ name = ruby_to_oo name
19
+ reflection_model.where(:model => name).exists?
20
+ end
21
+
22
+ # Check if there are (nested) models in a namespace e.g.
23
+ #
24
+ # models.in?('product') #=> true
25
+ #
26
+ # as there is at least the OpenObject model 'product.product'
27
+ def models_in? name
28
+ name = ruby_to_oo name
29
+
30
+ reflection_model.where("model like #{name}.%").exists?
31
+ end
32
+
33
+ # Load an additional model into the current namespace
34
+ def load_model model_name
35
+ return if @dont_load_models
36
+
37
+ existing_ruby_class = oo_to_ruby(model_name).constantize rescue nil
38
+ return existing_ruby_class if existing_ruby_class
39
+
40
+ model_name = ruby_to_oo model_name
41
+ Loader.new([model_name], reflection_model.database, name).load!.first
42
+ end
43
+
44
+ # Return the model for a specified OpenObject model
45
+ def class_for oo_name
46
+ oo_to_ruby(oo_name).constantize
47
+ end
48
+
49
+ private
50
+ def create_reflection_model
51
+ Class.new(Kangaroo::Model::Base).tap do |model|
52
+ model.oo_name = 'ir.model'
53
+ model.database = database
54
+ model.namespace = self
55
+ model.send :include, Model
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -2,32 +2,23 @@ module Kangaroo
2
2
  module Util
3
3
  class Loader
4
4
  module RootNamespace
5
+ include Namespace
6
+ include InformationRepository
7
+ include Reflection
8
+
9
+ mattr_accessor :database
10
+
11
+ # Apply naming convention: convert OpenObject name (e.g. "product.product") to
12
+ # Ruby class name, respecting current namespace (e.g. "Oo::Product::Product")
5
13
  def oo_to_ruby oo_name
6
14
  name + "::" + oo_name.gsub('.','/').camelize
7
15
  end
8
16
 
17
+ # Apply naming convention: convert
18
+ # Ruby class name, respecting current namespace (e.g. "Oo::Product::Product")
19
+ # to OpenObject name (e.g. "product.product")
9
20
  def ruby_to_oo ruby_name
10
- ruby_name.sub(name + "::",'').underscore.gsub '/', '.'
11
- end
12
-
13
- def reflection_model
14
- const_get('Ir').const_get('Model')
15
- end
16
-
17
- def model_exists? name
18
- name = ruby_to_oo name
19
- reflection_model.where(:model => name).exists?
20
- end
21
-
22
- def models_in? name
23
- name = ruby_to_oo name
24
-
25
- reflection_model.where("model like #{name}.%").exists?
26
- end
27
-
28
- def load_model model_name
29
- model_name = ruby_to_oo model_name
30
- Loader.new([model_name], reflection_model.database, name).load!.first
21
+ ruby_name.to_s.sub(name + "::",'').underscore.gsub '/', '.'
31
22
  end
32
23
  end
33
24
  end
@@ -18,6 +18,15 @@ module Kangaroo
18
18
 
19
19
  def call! name, *args
20
20
  super name, *__curry__(*args)
21
+ rescue Rapuncel::Response::Fault => f
22
+ case f.message
23
+ when /^Method not found\: (.+)/
24
+ raise NoMethodError, $1, caller + ["OpenERP Server Traceback:"] + f.backtrace.reverse
25
+ else
26
+ message = "OpenERP Server Exception " + f.message.to_s
27
+
28
+ raise Rapuncel::Response::Fault, message, f.backtrace.reverse[0..-2]
29
+ end
21
30
  end
22
31
 
23
32
  def self.new *args
@@ -1,6 +1,29 @@
1
1
  module Kangaroo
2
2
  module Util
3
+
4
+ # Proxy to the Common service (at /xmlrpc/common). This service provides
5
+ # numerous auxiliary functions to get information about the running OpenERP
6
+ # instance, and e.g. set the current log level, or login.
7
+ # You can access this Proxy via your client instance:
8
+ # @example
9
+ #
10
+ # config = Kangaroo::Util::Configuration.new 'spec/test_env/test.yml'
11
+ # client = config.client
12
+ # client.common
13
+ #
14
+ # @note that some of these functions need the superadmin password as first argument.
3
15
  class Proxy::Common < Proxy
16
+ LogLevel = {
17
+ :error => 40,
18
+ :warning => 30,
19
+ :info => 20,
20
+ :test => 15,
21
+ :debug => 10,
22
+ :debug_rpc => 8,
23
+ :debug_rpc_answer => 6,
24
+ :debug_sql => 5
25
+ }.freeze
26
+
4
27
  # Login to an OpenERP database
5
28
  #
6
29
  # @param [String] db_name The database to log in
@@ -45,10 +68,11 @@ module Kangaroo
45
68
  # Set log level
46
69
  #
47
70
  # @param super_password Superadmin password
48
- # @param loglevel Loglevel to set
71
+ # @param loglevel Loglevel to set, either as integer or as Symbol/String
49
72
  # @return true
50
73
  def set_loglevel super_password, loglevel
51
- call! :set_loglevel, loglevel.upcase
74
+ loglevel = LogLevel[loglevel.to_sym] unless loglevel.is_a?(Numeric)
75
+ call! :set_loglevel, super_password, loglevel
52
76
  end
53
77
 
54
78
  # Get server stats
@@ -83,8 +107,8 @@ module Kangaroo
83
107
  # Get SQL count, needs loglevel DEBUG_SQL
84
108
  #
85
109
  # @return Count of SQL queries
86
- def get_sqlcount
87
- call! :get_sqlcount
110
+ def get_sqlcount super_password
111
+ call! :get_sqlcount, super_password
88
112
  end
89
113
 
90
114
  # Get list of available updates, needs valid Publisher's Warranty
@@ -1,6 +1,20 @@
1
1
  module Kangaroo
2
2
  module Util
3
+
4
+ # Proxy to the Db service (at /xmlrpc/db), specifically
5
+ # to those functions, that don't need the superadmin password.
6
+ # You can access this Proxy via your client instance:
7
+ # @example
8
+ #
9
+ # config = Kangaroo::Util::Configuration.new 'spec/test_env/test.yml'
10
+ # client = config.client
11
+ # db_proxy = client.db
12
+ # db_proxy.list
13
+ #
14
+ # For functions that need superadmin authentication (like create, drop etc)
15
+ # @see Kangaroo::Util::Proxy::Superadmin
3
16
  class Proxy::Db < Proxy
17
+
4
18
  # Check if a database exists
5
19
  #
6
20
  # @param db_name Name of database to check