sugarcrm 0.9.11 → 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
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
+