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,5 @@
1
+ Feature: Connection
2
+ Scenario: Connect to an OpenERP server
3
+ Given i have a configuration file
4
+ When i setup a configuration
5
+ Then i should be able to login
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'rspec/expectations'
5
+ require 'cucumber/rspec/doubles'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w(.. .. lib)))
8
+ require 'kangaroo'
@@ -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,11 @@
1
+ host: 127.0.0.1
2
+ port: 8069
3
+
4
+ database:
5
+ name: kangaroo_test_database
6
+ user: admin
7
+ password: admin
8
+
9
+ models:
10
+ - res.*
11
+ - product.product
@@ -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
+
@@ -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
@@ -0,0 +1,6 @@
1
+ require 'kangaroo/railtie' if defined?(Rails)
2
+ require 'kangaroo/util/configuration'
3
+ require 'kangaroo/model/base'
4
+
5
+ module Kangaroo
6
+ end
@@ -0,0 +1,7 @@
1
+ module Kangaroo
2
+ class Exception < ::Exception ; end
3
+ class RecordNotFound < Exception ; end
4
+ class RecordSavingFailed < Exception ; end
5
+ class InstantiatedRecordNeedsIDError < Exception ; end
6
+ class ChildDefinedBeforeParentError < Exception ; end
7
+ end
@@ -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