sugarcrm 0.9.11 → 0.9.12

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 (49) hide show
  1. data/README.rdoc +11 -0
  2. data/Rakefile +1 -0
  3. data/VERSION +1 -1
  4. data/lib/rails/generators/sugarcrm/config/config_generator.rb +22 -0
  5. data/lib/rails/generators/sugarcrm/config/templates/initializer.rb +4 -0
  6. data/lib/rails/generators/sugarcrm/config/templates/sugarcrm.yml +19 -0
  7. data/lib/sugarcrm.rb +1 -0
  8. data/lib/sugarcrm/associations/association_collection.rb +7 -0
  9. data/lib/sugarcrm/associations/associations.rb +5 -0
  10. data/lib/sugarcrm/attributes/attribute_methods.rb +17 -0
  11. data/lib/sugarcrm/base.rb +1 -1
  12. data/lib/sugarcrm/connection/api/get_available_modules.rb +1 -1
  13. data/lib/sugarcrm/connection/api/get_document_revision.rb +2 -2
  14. data/lib/sugarcrm/connection/api/get_entries.rb +1 -1
  15. data/lib/sugarcrm/connection/api/get_entries_count.rb +1 -1
  16. data/lib/sugarcrm/connection/api/get_entry.rb +1 -1
  17. data/lib/sugarcrm/connection/api/get_entry_list.rb +1 -1
  18. data/lib/sugarcrm/connection/api/get_module_fields.rb +1 -1
  19. data/lib/sugarcrm/connection/api/get_note_attachment.rb +1 -1
  20. data/lib/sugarcrm/connection/api/get_relationships.rb +2 -2
  21. data/lib/sugarcrm/connection/api/get_report_entries.rb +1 -1
  22. data/lib/sugarcrm/connection/api/get_user_id.rb +1 -1
  23. data/lib/sugarcrm/connection/api/get_user_team_id.rb +1 -1
  24. data/lib/sugarcrm/connection/api/logout.rb +1 -1
  25. data/lib/sugarcrm/connection/api/seamless_login.rb +1 -1
  26. data/lib/sugarcrm/connection/api/search_by_module.rb +1 -1
  27. data/lib/sugarcrm/connection/api/set_campaign_merge.rb +1 -1
  28. data/lib/sugarcrm/connection/api/set_document_revision.rb +18 -4
  29. data/lib/sugarcrm/connection/api/set_entries.rb +1 -1
  30. data/lib/sugarcrm/connection/api/set_entry.rb +1 -1
  31. data/lib/sugarcrm/connection/api/set_note_attachment.rb +1 -1
  32. data/lib/sugarcrm/connection/api/set_relationship.rb +1 -1
  33. data/lib/sugarcrm/connection/api/set_relationships.rb +1 -1
  34. data/lib/sugarcrm/connection/connection.rb +9 -5
  35. data/lib/sugarcrm/connection_pool.rb +162 -0
  36. data/lib/sugarcrm/exceptions.rb +1 -0
  37. data/lib/sugarcrm/module_methods.rb +3 -3
  38. data/lib/sugarcrm/session.rb +63 -28
  39. data/sugarcrm.gemspec +143 -0
  40. data/sugarcrm.tmproj +952 -0
  41. data/test/connection/test_login.rb +1 -2
  42. data/test/connection/test_set_document_revision.rb +28 -0
  43. data/test/helper.rb +1 -1
  44. data/test/test_connection_pool.rb +33 -0
  45. data/test/test_session.rb +33 -16
  46. data/test/test_sugarcrm.rb +2 -5
  47. metadata +71 -61
  48. data/.document +0 -5
  49. data/test/config_test.yaml +0 -15
@@ -0,0 +1,162 @@
1
+ require 'monitor'
2
+
3
+ module SugarCRM; class ConnectionPool
4
+ attr_reader :size, :timeout
5
+ def initialize(session)
6
+ @session = session
7
+
8
+ # The cache of reserved connections mapped to threads
9
+ @reserved_connections = {}
10
+
11
+ # The mutex used to synchronize pool access
12
+ @connection_mutex = Monitor.new
13
+ @queue = @connection_mutex.new_cond
14
+ @timeout = config_timeout || 5
15
+
16
+ # default max pool size to 5
17
+ @size = config_pool_size || default_pool_size
18
+
19
+ @connections = []
20
+ @checked_out = []
21
+ end
22
+
23
+ # If a connection already exists yield it to the block. If no connection
24
+ # exists checkout a connection, yield it to the block, and checkin the
25
+ # connection when finished.
26
+ def with_connection
27
+ connection_id = current_connection_id
28
+ fresh_connection = true unless @reserved_connections[connection_id]
29
+ yield connection
30
+ ensure
31
+ release_connection(connection_id) if fresh_connection
32
+ end
33
+
34
+ # Retrieve the connection associated with the current thread, or call
35
+ # #checkout to obtain one if necessary.
36
+ #
37
+ # #connection can be called any number of times; the connection is
38
+ # held in a hash keyed by the thread id.
39
+ def connection
40
+ @reserved_connections[current_connection_id] ||= checkout
41
+ end
42
+
43
+ # Check-out a sugarcrm connection from the pool, indicating that you want
44
+ # to use it. You should call #checkin when you no longer need this.
45
+ #
46
+ # This is done by either returning an existing connection, or by creating
47
+ # a new connection. If the maximum number of connections for this pool has
48
+ # already been reached, but the pool is empty (i.e. they're all being used),
49
+ # then this method will wait until a thread has checked in a connection.
50
+ # The wait time is bounded however: if no connection can be checked out
51
+ # within the timeout specified for this pool, then a ConnectionTimeoutError
52
+ # exception will be raised.
53
+ def checkout
54
+ # Checkout an available connection
55
+ @connection_mutex.synchronize do
56
+ loop do
57
+ conn = if @checked_out.size < @connections.size
58
+ checkout_existing_connection
59
+ elsif @connections.size < @size
60
+ checkout_new_connection
61
+ end
62
+ return conn if conn
63
+
64
+ @queue.wait(@timeout)
65
+
66
+ if(@checked_out.size < @connections.size)
67
+ next
68
+ else
69
+ clear_stale_cached_connections!
70
+ if @size == @checked_out.size
71
+ raise SugarCRM::ConnectionTimeoutError, "could not obtain a sugarcrm connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+
79
+ # Check-in a sugarcrm connection back into the pool, indicating that you
80
+ # no longer need this connection.
81
+ def checkin(conn)
82
+ @connection_mutex.synchronize do
83
+ @checked_out.delete conn
84
+ @queue.signal
85
+ end
86
+ end
87
+
88
+ # Disconnects all connections in the pool, and clears the pool.
89
+ def disconnect!
90
+ @reserved_connections.each_value do |conn|
91
+ checkin conn
92
+ end
93
+ @reserved_connections = {}
94
+ @connections.each do |conn|
95
+ conn.logout
96
+ end
97
+ @connections = []
98
+ end
99
+
100
+ # Return any checked-out connections back to the pool by threads that
101
+ # are no longer alive.
102
+ def clear_stale_cached_connections!
103
+ keys = @reserved_connections.keys - Thread.list.find_all { |t|
104
+ t.alive?
105
+ }.map { |thread| thread.object_id }
106
+ keys.each do |key|
107
+ checkin @reserved_connections[key]
108
+ @reserved_connections.delete(key)
109
+ end
110
+ end
111
+
112
+ private
113
+ def new_connection
114
+ c = Connection.new(@session.config[:base_url], @session.config[:username], @session.config[:password], @session.config[:options])
115
+ c.session = @session
116
+ c
117
+ end
118
+
119
+ def checkout_new_connection
120
+ c = new_connection
121
+ @connections << c
122
+ checkout_connection(c)
123
+ end
124
+
125
+ def checkout_existing_connection
126
+ c = (@connections - @checked_out).first
127
+ checkout_connection(c)
128
+ end
129
+
130
+ def checkout_connection(c)
131
+ @checked_out << c
132
+ c
133
+ end
134
+
135
+ def current_connection_id #:nodoc:
136
+ Thread.current.object_id
137
+ end
138
+
139
+ # Returns the connection pool timeout, if present
140
+ def config_timeout
141
+ begin
142
+ @session.config[:options][:connection_pool][:wait_timeout] && @session.config[:options][:connection_pool][:wait_timeout].to_i
143
+ rescue
144
+ false
145
+ end
146
+ end
147
+
148
+ # Returns the connection pool size, if present
149
+ def config_pool_size
150
+ begin
151
+ @session.config[:options][:connection_pool][:size] && @session.config[:options][:connection_pool][:size].to_i
152
+ rescue
153
+ false
154
+ end
155
+ end
156
+
157
+ # The default for the connection pool's maximum size depends on environment:
158
+ # default pool size will be 1 unless used within Rails
159
+ def default_pool_size
160
+ defined?(Rails) ? 5 : 1
161
+ end
162
+ end; end
@@ -3,6 +3,7 @@ module SugarCRM
3
3
  class MultipleSessions < RuntimeError; end
4
4
  class LoginError < RuntimeError; end
5
5
  class MissingCredentials < RuntimeError; end
6
+ class ConnectionTimeoutError < RuntimeError; end
6
7
  class EmptyResponse < RuntimeError; end
7
8
  class UnhandledResponse < RuntimeError; end
8
9
  class InvalidSugarCRMUrl < RuntimeError; end
@@ -15,7 +15,7 @@ module SugarCRM
15
15
  end
16
16
 
17
17
  # store the various connected sessions
18
- # key = session.id, value = session instance
18
+ # key = session.object_id, value = session instance
19
19
  @@sessions = {}
20
20
  def self.sessions
21
21
  @@sessions
@@ -23,11 +23,11 @@ module SugarCRM
23
23
 
24
24
  def self.add_session(session)
25
25
  @@used_namespaces << session.namespace unless @@used_namespaces.include? session.namespace
26
- @@sessions[session.id] = session
26
+ @@sessions[session.object_id] = session
27
27
  end
28
28
 
29
29
  def self.remove_session(session)
30
- @@sessions.delete(session.id)
30
+ @@sessions.delete(session.object_id)
31
31
  end
32
32
 
33
33
  def self.session
@@ -1,7 +1,7 @@
1
1
  # This class hold an individual connection to a SugarCRM server.
2
2
  # There can be several such simultaneous connections
3
3
  module SugarCRM; class Session
4
- attr_reader :config, :connection, :extensions_path, :id, :namespace, :namespace_const
4
+ attr_reader :config, :connection_pool, :extensions_path, :namespace, :namespace_const
5
5
  attr_accessor :modules
6
6
  def initialize(url, user, pass, opts={})
7
7
  options = {
@@ -19,51 +19,69 @@ module SugarCRM; class Session
19
19
  connect_and_add_session
20
20
  end
21
21
 
22
- # create a new session from the credentials present in a file
23
- def self.new_from_file(path, opts={})
24
- config = load_and_parse_config(path)
22
+ # Creates a new session from the credentials present in a file
23
+ def self.from_file(path, opts={})
24
+ config_values = self.parse_config_file(path)
25
+ self.from_hash(config_values[:config], opts)
26
+ end
27
+
28
+ # Creates a new session from the credentials in the hash
29
+ def self.from_hash(hash, opts={})
30
+ pool_options = parse_connection_pool_options(hash)
31
+ options = opts
32
+ (options = {:connection_pool => pool_options}.merge(opts)) if pool_options.size > 0
33
+
25
34
  begin
26
- session = self.new(config[:base_url], config[:username], config[:password], opts)
35
+ session = self.new(hash[:base_url], hash[:username], hash[:password], options)
27
36
  rescue MissingCredentials => e
28
37
  return false
29
38
  end
30
39
  session.namespace_const
31
40
  end
32
41
 
42
+ # Returns a hash with the content in the YAML argument file
43
+ def self.parse_config_file(path)
44
+ self.validate_path path
45
+ contents = YAML.load_file(path)
46
+ return {} unless contents
47
+ self.symbolize_keys(contents)
48
+ end
49
+
33
50
  def setup_connection
34
51
  load_config_files unless connection_info_loaded?
35
52
  raise MissingCredentials, "Missing login credentials. Make sure you provide the SugarCRM URL, username, and password" unless connection_info_loaded?
36
53
  end
37
54
 
38
- # re-use this session and namespace if the user wants to connect with different credentials
39
55
  def connect(url=nil, user=nil, pass=nil, opts={})
40
56
  options = {
41
- :debug => (@connection && @connection.debug?),
57
+ :debug => @config[:options][:debug],
42
58
  :register_modules => true
43
59
  }.merge(opts)
44
60
 
61
+ # store the params used to connect
45
62
  {:base_url => url, :username => user, :password => pass}.each{|k,v|
46
63
  @config[k] = v unless v.nil?
47
64
  }
48
65
 
49
66
  SugarCRM::Module.deregister_all(self)
50
- SugarCRM.remove_session(self)
51
- @connection = SugarCRM::Connection.new(@config[:base_url], @config[:username], @config[:password], options) if connection_info_loaded?
52
- @connection.session = self
53
- @id = @connection.session_id
54
- SugarCRM.add_session(self) # must be removed and added back, as the session id (used as the hash key) changes
67
+ @connection_pool = SugarCRM::ConnectionPool.new(self)
55
68
  SugarCRM::Module.register_all(self)
56
69
  load_extensions
57
70
  true
58
71
  end
59
72
  alias :connect! :connect
60
- alias :reconnect :connect
61
- alias :reconnect! :connect
62
- alias :reload! :connect
73
+
74
+ # Re-uses this session and namespace if the user wants to connect with different credentials
75
+ def reconnect(url=nil, user=nil, pass=nil, opts={})
76
+ @connection_pool.disconnect!
77
+ connect(url, user, pass, opts)
78
+ end
79
+ alias :reconnect! :reconnect
80
+ alias :reload! :reconnect
63
81
 
64
82
  # log out from SugarCRM and cleanup (deregister modules, remove session, etc.)
65
83
  def disconnect
66
- @connection.logout
84
+ @connection_pool.disconnect!
67
85
  SugarCRM::Module.deregister_all(self)
68
86
  namespace = @namespace
69
87
  SugarCRM.instance_eval{ remove_const namespace } # remove NamespaceX from SugarCRM
@@ -71,6 +89,11 @@ module SugarCRM; class Session
71
89
  end
72
90
  alias :disconnect! :disconnect
73
91
 
92
+ # Returns a connection from the connection pool, if available
93
+ def connection
94
+ @connection_pool.connection
95
+ end
96
+
74
97
  def extensions_folder=(folder, dirstring=nil)
75
98
  path = File.expand_path(folder, dirstring)
76
99
  @extensions_path = path
@@ -79,7 +102,8 @@ module SugarCRM; class Session
79
102
 
80
103
  # load credentials from file, and (re)connect to SugarCRM
81
104
  def load_config(path)
82
- @config = self.class.load_and_parse_config(path)
105
+ new_config = self.class.parse_config_file(path)
106
+ @config[:config] = new_config[:config] if new_config
83
107
  reconnect(@config[:base_url], @config[:username], @config[:password]) if connection_info_loaded?
84
108
  @config
85
109
  end
@@ -93,20 +117,21 @@ module SugarCRM; class Session
93
117
 
94
118
  # lazy load the SugarCRM version we're connecting to
95
119
  def sugar_version
96
- @version ||= @connection.get_server_info["version"]
120
+ @version ||= connection.get_server_info["version"]
97
121
  end
98
122
 
99
123
  private
100
- def self.load_and_parse_config(path)
101
- validate_path path
102
- hash = {}
103
- config = YAML.load_file(path)
104
- if config && config["config"]
105
- config["config"].each{|k,v|
106
- hash[k.to_sym] = v
107
- }
108
- end
109
- hash
124
+ # Converts all hash keys to symbols (if a hash value is itself a hash, call the method recursively)
125
+ # Session.symbolize_keys({"one" => 1, "two" => {"foo" => "bar"}}) # => {:one => 1, :two => {:foo => "bar"}}
126
+ def self.symbolize_keys(hash)
127
+ hash.inject({}){|memo,(k,v)|
128
+ unless v.class == Hash
129
+ memo[k.to_sym] = v
130
+ else
131
+ memo[k.to_sym] = self.symbolize_keys(v)
132
+ end
133
+ memo
134
+ }
110
135
  end
111
136
 
112
137
  def self.validate_path(path)
@@ -121,6 +146,7 @@ module SugarCRM; class Session
121
146
  end
122
147
 
123
148
  def connection_info_loaded?
149
+ return false unless @config
124
150
  @config[:base_url] && @config[:username] && @config[:password]
125
151
  end
126
152
 
@@ -176,4 +202,13 @@ module SugarCRM; class Session
176
202
  SugarCRM.add_session(self)
177
203
  end
178
204
 
205
+ # Returns hash containing only keys/values relating to connection pool options. These are removed from parameter hash.
206
+ def self.parse_connection_pool_options(config_values)
207
+ result = {}
208
+ pool_size = config_values.delete(:pool)
209
+ result[:size] = pool_size if pool_size
210
+ wait_timeout = config_values.delete(:wait_timeout)
211
+ result[:wait_timeout] = wait_timeout if wait_timeout
212
+ result
213
+ end
179
214
  end; end
data/sugarcrm.gemspec ADDED
@@ -0,0 +1,143 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{sugarcrm}
8
+ s.version = "0.9.12"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Carl Hicks", "David Sulc"]
12
+ s.date = %q{2011-03-02}
13
+ s.default_executable = %q{sugarcrm}
14
+ s.email = %q{carl.hicks@gmail.com}
15
+ s.executables = ["sugarcrm"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ "./Gemfile",
22
+ "./LICENSE",
23
+ "./README.rdoc",
24
+ "./Rakefile",
25
+ "./VERSION",
26
+ "./lib/rails/generators/sugarcrm/config/config_generator.rb",
27
+ "./lib/rails/generators/sugarcrm/config/templates/initializer.rb",
28
+ "./lib/rails/generators/sugarcrm/config/templates/sugarcrm.yml",
29
+ "./lib/sugarcrm.rb",
30
+ "./lib/sugarcrm/associations.rb",
31
+ "./lib/sugarcrm/associations/association.rb",
32
+ "./lib/sugarcrm/associations/association_cache.rb",
33
+ "./lib/sugarcrm/associations/association_collection.rb",
34
+ "./lib/sugarcrm/associations/association_methods.rb",
35
+ "./lib/sugarcrm/associations/associations.rb",
36
+ "./lib/sugarcrm/attributes.rb",
37
+ "./lib/sugarcrm/attributes/attribute_methods.rb",
38
+ "./lib/sugarcrm/attributes/attribute_serializers.rb",
39
+ "./lib/sugarcrm/attributes/attribute_typecast.rb",
40
+ "./lib/sugarcrm/attributes/attribute_validations.rb",
41
+ "./lib/sugarcrm/base.rb",
42
+ "./lib/sugarcrm/config/sugarcrm.yaml",
43
+ "./lib/sugarcrm/connection.rb",
44
+ "./lib/sugarcrm/connection/api/get_available_modules.rb",
45
+ "./lib/sugarcrm/connection/api/get_document_revision.rb",
46
+ "./lib/sugarcrm/connection/api/get_entries.rb",
47
+ "./lib/sugarcrm/connection/api/get_entries_count.rb",
48
+ "./lib/sugarcrm/connection/api/get_entry.rb",
49
+ "./lib/sugarcrm/connection/api/get_entry_list.rb",
50
+ "./lib/sugarcrm/connection/api/get_module_fields.rb",
51
+ "./lib/sugarcrm/connection/api/get_note_attachment.rb",
52
+ "./lib/sugarcrm/connection/api/get_relationships.rb",
53
+ "./lib/sugarcrm/connection/api/get_report_entries.rb",
54
+ "./lib/sugarcrm/connection/api/get_server_info.rb",
55
+ "./lib/sugarcrm/connection/api/get_user_id.rb",
56
+ "./lib/sugarcrm/connection/api/get_user_team_id.rb",
57
+ "./lib/sugarcrm/connection/api/login.rb",
58
+ "./lib/sugarcrm/connection/api/logout.rb",
59
+ "./lib/sugarcrm/connection/api/seamless_login.rb",
60
+ "./lib/sugarcrm/connection/api/search_by_module.rb",
61
+ "./lib/sugarcrm/connection/api/set_campaign_merge.rb",
62
+ "./lib/sugarcrm/connection/api/set_document_revision.rb",
63
+ "./lib/sugarcrm/connection/api/set_entries.rb",
64
+ "./lib/sugarcrm/connection/api/set_entry.rb",
65
+ "./lib/sugarcrm/connection/api/set_note_attachment.rb",
66
+ "./lib/sugarcrm/connection/api/set_relationship.rb",
67
+ "./lib/sugarcrm/connection/api/set_relationships.rb",
68
+ "./lib/sugarcrm/connection/connection.rb",
69
+ "./lib/sugarcrm/connection/helper.rb",
70
+ "./lib/sugarcrm/connection/request.rb",
71
+ "./lib/sugarcrm/connection/response.rb",
72
+ "./lib/sugarcrm/connection_pool.rb",
73
+ "./lib/sugarcrm/exceptions.rb",
74
+ "./lib/sugarcrm/extensions/README.txt",
75
+ "./lib/sugarcrm/finders.rb",
76
+ "./lib/sugarcrm/finders/dynamic_finder_match.rb",
77
+ "./lib/sugarcrm/finders/finder_methods.rb",
78
+ "./lib/sugarcrm/module.rb",
79
+ "./lib/sugarcrm/module_methods.rb",
80
+ "./lib/sugarcrm/session.rb",
81
+ "./sugarcrm.gemspec",
82
+ "./sugarcrm.tmproj"
83
+ ]
84
+ s.homepage = %q{http://github.com/chicks/sugarcrm}
85
+ s.require_paths = ["lib"]
86
+ s.rubygems_version = %q{1.3.7}
87
+ s.summary = %q{A less clunky way to interact with SugarCRM via REST.}
88
+ s.test_files = [
89
+ "test/connection/test_get_available_modules.rb",
90
+ "test/connection/test_get_entries.rb",
91
+ "test/connection/test_get_entry.rb",
92
+ "test/connection/test_get_entry_list.rb",
93
+ "test/connection/test_get_module_fields.rb",
94
+ "test/connection/test_get_relationships.rb",
95
+ "test/connection/test_get_server_info.rb",
96
+ "test/connection/test_get_user_id.rb",
97
+ "test/connection/test_get_user_team_id.rb",
98
+ "test/connection/test_login.rb",
99
+ "test/connection/test_logout.rb",
100
+ "test/connection/test_set_document_revision.rb",
101
+ "test/connection/test_set_note_attachment.rb",
102
+ "test/connection/test_set_relationship.rb",
103
+ "test/extensions_test/patch.rb",
104
+ "test/helper.rb",
105
+ "test/test_association_collection.rb",
106
+ "test/test_associations.rb",
107
+ "test/test_connection.rb",
108
+ "test/test_connection_pool.rb",
109
+ "test/test_module.rb",
110
+ "test/test_response.rb",
111
+ "test/test_session.rb",
112
+ "test/test_sugarcrm.rb"
113
+ ]
114
+
115
+ if s.respond_to? :specification_version then
116
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
117
+ s.specification_version = 3
118
+
119
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
120
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0"])
121
+ s.add_runtime_dependency(%q<i18n>, [">= 0"])
122
+ s.add_runtime_dependency(%q<json>, [">= 0"])
123
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
124
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
125
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
126
+ else
127
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
128
+ s.add_dependency(%q<i18n>, [">= 0"])
129
+ s.add_dependency(%q<json>, [">= 0"])
130
+ s.add_dependency(%q<shoulda>, [">= 0"])
131
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
132
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
133
+ end
134
+ else
135
+ s.add_dependency(%q<activesupport>, [">= 3.0.0"])
136
+ s.add_dependency(%q<i18n>, [">= 0"])
137
+ s.add_dependency(%q<json>, [">= 0"])
138
+ s.add_dependency(%q<shoulda>, [">= 0"])
139
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
140
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
141
+ end
142
+ end
143
+