sugarcrm 0.8.2 → 0.9.0

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 (34) hide show
  1. data/README.rdoc +58 -19
  2. data/Rakefile +1 -4
  3. data/VERSION +1 -1
  4. data/lib/sugarcrm.rb +7 -4
  5. data/lib/sugarcrm/associations.rb +2 -0
  6. data/lib/sugarcrm/associations/association_collection.rb +143 -0
  7. data/lib/sugarcrm/associations/association_methods.rb +92 -0
  8. data/lib/sugarcrm/attributes.rb +4 -0
  9. data/lib/sugarcrm/attributes/attribute_methods.rb +131 -0
  10. data/lib/sugarcrm/attributes/attribute_serializers.rb +55 -0
  11. data/lib/sugarcrm/attributes/attribute_typecast.rb +39 -0
  12. data/lib/sugarcrm/attributes/attribute_validations.rb +37 -0
  13. data/lib/sugarcrm/base.rb +77 -21
  14. data/lib/sugarcrm/connection.rb +3 -137
  15. data/lib/sugarcrm/connection/api/get_entry_list.rb +1 -1
  16. data/lib/sugarcrm/connection/api/get_note_attachment.rb +0 -1
  17. data/lib/sugarcrm/connection/api/set_relationship.rb +3 -0
  18. data/lib/sugarcrm/connection/connection.rb +144 -0
  19. data/lib/sugarcrm/{request.rb → connection/request.rb} +2 -10
  20. data/lib/sugarcrm/{response.rb → connection/response.rb} +10 -4
  21. data/lib/sugarcrm/exceptions.rb +14 -26
  22. data/lib/sugarcrm/module.rb +19 -18
  23. data/test/connection/test_get_entry.rb +5 -5
  24. data/test/connection/test_get_module_fields.rb +1 -1
  25. data/test/connection/test_set_relationship.rb +13 -21
  26. data/test/helper.rb +1 -1
  27. data/test/test_association_collection.rb +12 -0
  28. data/test/test_associations.rb +33 -0
  29. data/test/test_connection.rb +0 -7
  30. data/test/test_module.rb +1 -1
  31. data/test/test_sugarcrm.rb +16 -8
  32. metadata +22 -28
  33. data/lib/sugarcrm/association_methods.rb +0 -46
  34. data/lib/sugarcrm/attribute_methods.rb +0 -170
@@ -0,0 +1,33 @@
1
+ require 'helper'
2
+
3
+ class TestAssociations < Test::Unit::TestCase
4
+ context "A SugarCRM::Base instance" do
5
+ should "return an email address when sent #email_addresses" do
6
+ u = SugarCRM::User.find("seed_sarah_id")
7
+ assert_equal "sarah@example.com", u.email_addresses.first.email_address
8
+ end
9
+
10
+ should "utilize the association cache" do
11
+ u = SugarCRM::User.find(1)
12
+ u.email_addresses
13
+ assert u.association_cached? :email_addresses
14
+ end
15
+
16
+ should "permit adding a record to an association collection (such as #meetings << Meeting.new)" do
17
+ u = SugarCRM::User.find(1)
18
+ m = SugarCRM::Meeting.new
19
+ m.date_start = DateTime.now
20
+ m.duration_hours = 0.5
21
+ m.name = "Yet Another Stupid Meeting"
22
+ u.meetings << m
23
+ assert u.meetings.include?(m)
24
+ assert_equal [m], u.meetings.added
25
+ assert u.save!
26
+ u = SugarCRM::User.find(1)
27
+ assert u.meetings.include?(m)
28
+ assert u.meetings.delete(m)
29
+ assert u.meetings.save!
30
+ assert !u.meetings.include?(m)
31
+ end
32
+ end
33
+ end
@@ -1,12 +1,5 @@
1
1
  require 'helper'
2
2
 
3
- #require 'connection/test_login'
4
- #require 'connection/test_get_available_modules'
5
- #require 'connection/test_get_module_fields'
6
- #require 'connection/test_get_entry'
7
- #require 'connection/test_get_entries'
8
- #require 'connection/test_get_entry_list'
9
-
10
3
  class TestConnection < Test::Unit::TestCase
11
4
  context "A SugarCRM::Connection instance" do
12
5
  setup do
@@ -12,7 +12,7 @@ class TestModule < Test::Unit::TestCase
12
12
  end
13
13
 
14
14
  should "return required fields when #required_fields" do
15
- assert SugarCRM::User._module.required_fields.include? "user_name"
15
+ assert SugarCRM::User._module.required_fields.include? :user_name
16
16
  end
17
17
  end
18
18
  end
@@ -17,6 +17,10 @@ class TestSugarCRM < Test::Unit::TestCase
17
17
  assert_equal "Users", SugarCRM::User._module.name
18
18
  end
19
19
 
20
+ should "return the module fields" do
21
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, SugarCRM::Account._module.fields
22
+ end
23
+
20
24
  should "responsd to self#methods" do
21
25
  assert_instance_of Array, SugarCRM::User.new.methods
22
26
  end
@@ -48,9 +52,11 @@ class TestSugarCRM < Test::Unit::TestCase
48
52
  end
49
53
 
50
54
  should "not save a record that is missing required attributes" do
55
+ SugarCRM.connection.debug = false
51
56
  u = SugarCRM::User.new
52
57
  u.last_name = "Test"
53
58
  assert !u.save
59
+ SugarCRM.connection.debug = false
54
60
  assert_raise SugarCRM::InvalidRecord do
55
61
  u.save!
56
62
  end
@@ -67,6 +73,7 @@ class TestSugarCRM < Test::Unit::TestCase
67
73
  u.status = "Active"
68
74
  assert_equal "Test", u.modified_attributes[:first_name][:new]
69
75
  assert u.save!
76
+ assert !u.new?
70
77
  m = SugarCRM::User.find_by_first_name_and_last_name("Test", "User")
71
78
  m.title = "Test User"
72
79
  assert m.save!
@@ -74,13 +81,19 @@ class TestSugarCRM < Test::Unit::TestCase
74
81
  #SugarCRM.connection.debug = false
75
82
  end
76
83
 
84
+ should "support finding first instance (sorted by attribute)" do
85
+ account = SugarCRM::Account.first({
86
+ :order_by => 'name'
87
+ })
88
+ assert_instance_of SugarCRM::Account, account
89
+ end
90
+
77
91
  should "support searching based on conditions" do
78
92
  accounts = SugarCRM::Account.all({
79
- :conditions => { :billing_address_postalcode => ["> '70000'", "< '72000'" ] },
93
+ :conditions => { :billing_address_postalcode => ["> '70000'", "< '79999'" ] },
80
94
  :limit => '10',
81
95
  :order_by => 'billing_address_postalcode'
82
96
  })
83
- assert_instance_of Array, accounts
84
97
  assert_instance_of SugarCRM::Account, accounts.first
85
98
  end
86
99
 
@@ -93,11 +106,6 @@ class TestSugarCRM < Test::Unit::TestCase
93
106
  assert_equal u.user_name, "admin"
94
107
  end
95
108
 
96
- should "return an email address when sent #email_addresses" do
97
- u = SugarCRM::User.find("seed_sarah_id")
98
- assert_equal "sarah@example.com", u.email_addresses.first.email_address
99
- end
100
-
101
109
  should "return an array of records when sent #find([id1, id2, id3])" do
102
110
  users = SugarCRM::User.find(["seed_sarah_id", 1])
103
111
  assert_equal "Administrator", users.last.title
@@ -107,7 +115,7 @@ class TestSugarCRM < Test::Unit::TestCase
107
115
  u = SugarCRM::User.find_by_user_name("sarah")
108
116
  assert_equal "sarah@example.com", u.email_addresses.first.email_address
109
117
  end
110
-
118
+
111
119
  end
112
120
 
113
121
  end
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 8
9
- - 2
10
- version: 0.8.2
8
+ - 9
9
+ - 0
10
+ version: 0.9.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Carl Hicks
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-14 00:00:00 -08:00
18
+ date: 2010-12-29 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -32,24 +32,10 @@ dependencies:
32
32
  version: "0"
33
33
  type: :development
34
34
  version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: json
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- hash: 3
44
- segments:
45
- - 0
46
- version: "0"
47
- type: :runtime
48
- version_requirements: *id002
49
35
  - !ruby/object:Gem::Dependency
50
36
  name: activesupport
51
37
  prerelease: false
52
- requirement: &id003 !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
53
39
  none: false
54
40
  requirements:
55
41
  - - ">="
@@ -60,11 +46,8 @@ dependencies:
60
46
  - 0
61
47
  version: "3.0"
62
48
  type: :runtime
63
- version_requirements: *id003
64
- description: |-
65
- I've implemented all of the basic API calls that SugarCRM supports, and am actively building an abstraction layer
66
- on top of the basic API methods. The end result will be to provide ActiveRecord style finders and first class
67
- objects. Some of this functionality is included today.
49
+ version_requirements: *id002
50
+ description: "A less clunky way to interact with SugarCRM via REST. Instead of SugarCRM.connection.get_entry(\"Users\", \"1\") you could use SugarCRM::User.find(1). There is support for collections \xC3\xA0 la SugarCRM::User.find(1).email_addresses, or SugarCRM::Contact.first.meetings << new_meeting. ActiveRecord style finders are in place, with limited support for conditions and joins."
68
51
  email: carl.hicks@gmail.com
69
52
  executables: []
70
53
 
@@ -80,8 +63,14 @@ files:
80
63
  - Rakefile
81
64
  - VERSION
82
65
  - lib/sugarcrm.rb
83
- - lib/sugarcrm/association_methods.rb
84
- - lib/sugarcrm/attribute_methods.rb
66
+ - lib/sugarcrm/associations.rb
67
+ - lib/sugarcrm/associations/association_collection.rb
68
+ - lib/sugarcrm/associations/association_methods.rb
69
+ - lib/sugarcrm/attributes.rb
70
+ - lib/sugarcrm/attributes/attribute_methods.rb
71
+ - lib/sugarcrm/attributes/attribute_serializers.rb
72
+ - lib/sugarcrm/attributes/attribute_typecast.rb
73
+ - lib/sugarcrm/attributes/attribute_validations.rb
85
74
  - lib/sugarcrm/base.rb
86
75
  - lib/sugarcrm/connection.rb
87
76
  - lib/sugarcrm/connection/api/get_available_modules.rb
@@ -108,13 +97,14 @@ files:
108
97
  - lib/sugarcrm/connection/api/set_note_attachment.rb
109
98
  - lib/sugarcrm/connection/api/set_relationship.rb
110
99
  - lib/sugarcrm/connection/api/set_relationships.rb
100
+ - lib/sugarcrm/connection/connection.rb
111
101
  - lib/sugarcrm/connection/helper.rb
102
+ - lib/sugarcrm/connection/request.rb
103
+ - lib/sugarcrm/connection/response.rb
112
104
  - lib/sugarcrm/dynamic_finder_match.rb
113
105
  - lib/sugarcrm/exceptions.rb
114
106
  - lib/sugarcrm/module.rb
115
107
  - lib/sugarcrm/module_methods.rb
116
- - lib/sugarcrm/request.rb
117
- - lib/sugarcrm/response.rb
118
108
  - test/connection/test_get_available_modules.rb
119
109
  - test/connection/test_get_entries.rb
120
110
  - test/connection/test_get_entry.rb
@@ -128,6 +118,8 @@ files:
128
118
  - test/connection/test_logout.rb
129
119
  - test/connection/test_set_relationship.rb
130
120
  - test/helper.rb
121
+ - test/test_association_collection.rb
122
+ - test/test_associations.rb
131
123
  - test/test_connection.rb
132
124
  - test/test_module.rb
133
125
  - test/test_response.rb
@@ -180,6 +172,8 @@ test_files:
180
172
  - test/connection/test_logout.rb
181
173
  - test/connection/test_set_relationship.rb
182
174
  - test/helper.rb
175
+ - test/test_association_collection.rb
176
+ - test/test_associations.rb
183
177
  - test/test_connection.rb
184
178
  - test/test_module.rb
185
179
  - test/test_response.rb
@@ -1,46 +0,0 @@
1
- module SugarCRM; module AssociationMethods
2
-
3
- module ClassMethods
4
- # Returns an array of the module link fields
5
- def associations_from_module_link_fields
6
- self._module.link_fields.keys
7
- end
8
- end
9
-
10
- # Generates the association proxy methods for related modules
11
- def define_association_methods
12
- return if association_methods_generated?
13
- @associations.each do |k|
14
- self.class.module_eval %Q?
15
- def #{k}
16
- query_association :#{k}
17
- end
18
- def #{k}=(value)
19
- update_association :#{k},value
20
- end
21
- ?
22
- end
23
- self.class.association_methods_generated = true
24
- end
25
-
26
- #
27
- # {"email_addresses"=>
28
- # {"name"=>"email_addresses",
29
- # "module"=>"EmailAddress",
30
- # "bean_name"=>"EmailAddress",
31
- # "relationship"=>"users_email_addresses",
32
- # "type"=>"link"},
33
- #
34
- def query_association(association)
35
- collection = SugarCRM.connection.get_relationships(
36
- self.class._module.name,
37
- self.id,
38
- association.to_s
39
- )
40
- end
41
-
42
- def update_association(association, value)
43
- false
44
- end
45
-
46
- end; end
@@ -1,170 +0,0 @@
1
- module SugarCRM; module AttributeMethods
2
-
3
- module ClassMethods
4
- # Returns a hash of the module fields from the module
5
- def attributes_from_module_fields
6
- fields = {}.with_indifferent_access
7
- self._module.fields.keys.sort.each do |k|
8
- fields[k.to_s] = nil
9
- end
10
- fields
11
- end
12
- end
13
-
14
- # Determines if attributes have been changed
15
- def changed?
16
- @modified_attributes.length > 0
17
- end
18
-
19
- # Is this a new record?
20
- def new?
21
- @id.blank?
22
- end
23
-
24
- # Converts the attributes hash into format recognizable by Sugar
25
- # { :last_name => "Smith"}
26
- # becomes
27
- # { :last_name => {:name => "last_name", :value => "Smith"}}
28
- def serialize_attributes
29
- attr_hash = {}
30
- @attributes.each_pair do |name,value|
31
- attr_hash[name] = serialize_attribute(name,value)
32
- end
33
- attr_hash[:id] = serialize_id unless new?
34
- attr_hash
35
- end
36
-
37
- # Converts the modified_attributes hash into format recognizable by Sugar
38
- # { :last_name => {:old => "Smit", :new => "Smith"}}
39
- # becomes
40
- # { :last_name => {:name => "last_name", :value => "Smith"}}
41
- def serialize_modified_attributes
42
- attr_hash = {}
43
- @modified_attributes.each_pair do |name,hash|
44
- attr_hash[name] = serialize_attribute(name,hash[:new])
45
- end
46
- attr_hash[:id] = serialize_id unless new?
47
- attr_hash
48
- end
49
-
50
- # Checks to see if we have all the neccessary attributes
51
- def valid?
52
- valid = true
53
- self.class._module.required_fields.each do |attribute|
54
- case attr_type_for(attribute)
55
- when "bool"
56
- case @attributes[attribute]
57
- when TrueClass
58
- next
59
- when FalseClass
60
- next
61
- else
62
- @errors.add "#{attribute} must be true or false"
63
- valid = false
64
- end
65
- else
66
- if @attributes[attribute].blank?
67
- @errors.add "#{attribute} cannot be blank"
68
- valid = false
69
- end
70
- end
71
- end
72
- valid
73
- end
74
-
75
- # List the required attributes for save
76
- def required_attributes
77
- self.class._module.required_fields
78
- end
79
-
80
- # Serializes the id
81
- def serialize_id
82
- {:name => "id", :value => @id.to_s}
83
- end
84
-
85
- # Un-typecasts the attribute - false becomes 0
86
- def serialize_attribute(name,value)
87
- attr_value = value
88
- case attr_type_for(name)
89
- when "bool"
90
- attr_value = 0
91
- attr_value = 1 if value
92
- end
93
- {:name => name, :value => attr_value}
94
- end
95
-
96
- # Generates get/set methods for keys in the attributes hash
97
- def define_attribute_methods
98
- return if attribute_methods_generated?
99
- @attributes.each_pair do |k,v|
100
- self.class.module_eval %Q?
101
- def #{k}
102
- read_attribute :#{k}
103
- end
104
- def #{k}=(value)
105
- write_attribute :#{k},value
106
- end
107
- ?
108
- end
109
- self.class.attribute_methods_generated = true
110
- end
111
-
112
- # Returns an <tt>#inspect</tt>-like string for the value of the
113
- # attribute +attr_name+. String attributes are elided after 50
114
- # characters, and Date and Time attributes are returned in the
115
- # <tt>:db</tt> format. Other attributes return the value of
116
- # <tt>#inspect</tt> without modification.
117
- #
118
- # person = Person.create!(:name => "David Heinemeier Hansson " * 3)
119
- #
120
- # person.attribute_for_inspect(:name)
121
- # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
122
- #
123
- # person.attribute_for_inspect(:created_at)
124
- # # => '"2009-01-12 04:48:57"'
125
- def attribute_for_inspect(attr_name)
126
- value = read_attribute(attr_name)
127
- if value.is_a?(String) && value.length > 50
128
- "#{value[0..50]}...".inspect
129
- elsif value.is_a?(Date) || value.is_a?(Time)
130
- %("#{value.to_s(:db)}")
131
- else
132
- value.inspect
133
- end
134
- end
135
-
136
- protected
137
-
138
- # Returns the attribute type for a given attribute
139
- def attr_type_for(attribute)
140
- field = self.class._module.fields[attribute]
141
- return false unless field
142
- field["type"]
143
- end
144
-
145
- # Attempts to typecast each attribute based on the module field type
146
- def typecast_attributes
147
- @attributes.each_pair do |name,value|
148
- attr_type = attr_type_for(name)
149
- next unless attr_type
150
- case attr_type
151
- when "bool"
152
- @attributes[name] = (value == "1")
153
- end
154
- end
155
- @attributes
156
- end
157
-
158
- # Wrapper around attributes hash
159
- def read_attribute(key)
160
- @attributes[key]
161
- end
162
-
163
- # Wrapper around attributes hash
164
- def write_attribute(key, value)
165
- @modified_attributes[key] = { :old => @attributes[key].to_s, :new => value }
166
- @attributes[key] = value
167
- end
168
-
169
- end; end
170
-