force 0.0.1

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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +96 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.lock +107 -0
  5. data/Guardfile +8 -0
  6. data/LICENSE +22 -0
  7. data/README.md +421 -0
  8. data/Rakefile +10 -0
  9. data/coverage/assets/0.7.1/application.css +1110 -0
  10. data/coverage/assets/0.7.1/application.js +626 -0
  11. data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
  12. data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
  13. data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
  14. data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
  15. data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
  16. data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
  17. data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
  18. data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
  19. data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
  20. data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
  21. data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
  22. data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
  23. data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
  24. data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
  25. data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
  26. data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
  27. data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
  28. data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
  29. data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
  30. data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
  31. data/coverage/assets/0.7.1/favicon_green.png +0 -0
  32. data/coverage/assets/0.7.1/favicon_red.png +0 -0
  33. data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
  34. data/coverage/assets/0.7.1/loading.gif +0 -0
  35. data/coverage/assets/0.7.1/magnify.png +0 -0
  36. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  37. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  38. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  39. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  40. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  41. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  42. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  43. data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  44. data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
  45. data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  46. data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
  47. data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
  48. data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  49. data/coverage/index.html +19808 -0
  50. data/force.gemspec +27 -0
  51. data/lib/force.rb +74 -0
  52. data/lib/force/abstract_client.rb +9 -0
  53. data/lib/force/attachment.rb +21 -0
  54. data/lib/force/client.rb +3 -0
  55. data/lib/force/collection.rb +45 -0
  56. data/lib/force/concerns/api.rb +321 -0
  57. data/lib/force/concerns/authentication.rb +39 -0
  58. data/lib/force/concerns/base.rb +59 -0
  59. data/lib/force/concerns/caching.rb +24 -0
  60. data/lib/force/concerns/canvas.rb +10 -0
  61. data/lib/force/concerns/connection.rb +74 -0
  62. data/lib/force/concerns/picklists.rb +87 -0
  63. data/lib/force/concerns/streaming.rb +31 -0
  64. data/lib/force/concerns/verbs.rb +67 -0
  65. data/lib/force/config.rb +140 -0
  66. data/lib/force/data/client.rb +18 -0
  67. data/lib/force/mash.rb +66 -0
  68. data/lib/force/middleware.rb +27 -0
  69. data/lib/force/middleware/authentication.rb +73 -0
  70. data/lib/force/middleware/authentication/password.rb +17 -0
  71. data/lib/force/middleware/authentication/token.rb +15 -0
  72. data/lib/force/middleware/authorization.rb +15 -0
  73. data/lib/force/middleware/caching.rb +22 -0
  74. data/lib/force/middleware/gzip.rb +31 -0
  75. data/lib/force/middleware/instance_url.rb +14 -0
  76. data/lib/force/middleware/logger.rb +40 -0
  77. data/lib/force/middleware/mashify.rb +16 -0
  78. data/lib/force/middleware/multipart.rb +55 -0
  79. data/lib/force/middleware/raise_error.rb +25 -0
  80. data/lib/force/signed_request.rb +48 -0
  81. data/lib/force/sobject.rb +68 -0
  82. data/lib/force/tooling/client.rb +11 -0
  83. data/lib/force/upload_io.rb +20 -0
  84. data/lib/force/version.rb +3 -0
  85. data/spec/fixtures/auth_error_response.json +4 -0
  86. data/spec/fixtures/auth_success_response.json +7 -0
  87. data/spec/fixtures/blob.jpg +0 -0
  88. data/spec/fixtures/expired_session_response.json +6 -0
  89. data/spec/fixtures/reauth_success_response.json +7 -0
  90. data/spec/fixtures/refresh_error_response.json +4 -0
  91. data/spec/fixtures/refresh_success_response.json +7 -0
  92. data/spec/fixtures/services_data_success_response.json +12 -0
  93. data/spec/fixtures/sobject/create_success_response.json +5 -0
  94. data/spec/fixtures/sobject/delete_error_response.json +1 -0
  95. data/spec/fixtures/sobject/describe_sobjects_success_response.json +31 -0
  96. data/spec/fixtures/sobject/list_sobjects_success_response.json +31 -0
  97. data/spec/fixtures/sobject/org_query_response.json +11 -0
  98. data/spec/fixtures/sobject/query_aggregate_success_response.json +23 -0
  99. data/spec/fixtures/sobject/query_empty_response.json +5 -0
  100. data/spec/fixtures/sobject/query_error_response.json +6 -0
  101. data/spec/fixtures/sobject/query_paginated_first_page_response.json +14 -0
  102. data/spec/fixtures/sobject/query_paginated_last_page_response.json +13 -0
  103. data/spec/fixtures/sobject/query_success_response.json +38 -0
  104. data/spec/fixtures/sobject/recent_success_response.json +18 -0
  105. data/spec/fixtures/sobject/search_error_response.json +6 -0
  106. data/spec/fixtures/sobject/search_success_response.json +16 -0
  107. data/spec/fixtures/sobject/sobject_describe_error_response.json +6 -0
  108. data/spec/fixtures/sobject/sobject_describe_success_response.json +1429 -0
  109. data/spec/fixtures/sobject/sobject_find_error_response.json +6 -0
  110. data/spec/fixtures/sobject/sobject_find_success_response.json +29 -0
  111. data/spec/fixtures/sobject/upsert_created_success_response.json +5 -0
  112. data/spec/fixtures/sobject/upsert_error_response.json +6 -0
  113. data/spec/fixtures/sobject/upsert_multiple_error_response.json +4 -0
  114. data/spec/fixtures/sobject/upsert_updated_success_response.json +0 -0
  115. data/spec/fixtures/sobject/write_error_response.json +6 -0
  116. data/spec/integration/abstract_client_spec.rb +306 -0
  117. data/spec/integration/data/client_spec.rb +90 -0
  118. data/spec/spec_helper.rb +20 -0
  119. data/spec/support/client_integration.rb +45 -0
  120. data/spec/support/concerns.rb +18 -0
  121. data/spec/support/event_machine.rb +14 -0
  122. data/spec/support/fixture_helpers.rb +45 -0
  123. data/spec/support/matchers.rb +11 -0
  124. data/spec/support/middleware.rb +76 -0
  125. data/spec/support/mock_cache.rb +13 -0
  126. data/spec/unit/abstract_client_spec.rb +11 -0
  127. data/spec/unit/attachment_spec.rb +15 -0
  128. data/spec/unit/collection_spec.rb +52 -0
  129. data/spec/unit/concerns/api_spec.rb +244 -0
  130. data/spec/unit/concerns/authentication_spec.rb +98 -0
  131. data/spec/unit/concerns/base_spec.rb +42 -0
  132. data/spec/unit/concerns/caching_spec.rb +29 -0
  133. data/spec/unit/concerns/canvas_spec.rb +30 -0
  134. data/spec/unit/concerns/connection_spec.rb +22 -0
  135. data/spec/unit/config_spec.rb +99 -0
  136. data/spec/unit/data/client_spec.rb +10 -0
  137. data/spec/unit/mash_spec.rb +36 -0
  138. data/spec/unit/middleware/authentication/password_spec.rb +31 -0
  139. data/spec/unit/middleware/authentication/token_spec.rb +24 -0
  140. data/spec/unit/middleware/authentication_spec.rb +67 -0
  141. data/spec/unit/middleware/authorization_spec.rb +11 -0
  142. data/spec/unit/middleware/gzip_spec.rb +66 -0
  143. data/spec/unit/middleware/instance_url_spec.rb +24 -0
  144. data/spec/unit/middleware/logger_spec.rb +19 -0
  145. data/spec/unit/middleware/mashify_spec.rb +11 -0
  146. data/spec/unit/middleware/raise_error_spec.rb +32 -0
  147. data/spec/unit/signed_request_spec.rb +24 -0
  148. data/spec/unit/sobject_spec.rb +86 -0
  149. data/spec/unit/tooling/client_spec.rb +7 -0
  150. data/tmp/rspec_guard_result +1 -0
  151. metadata +383 -0
@@ -0,0 +1,39 @@
1
+ module Force
2
+ module Concerns
3
+ module Authentication
4
+
5
+ # Public: Force an authentication
6
+ def authenticate!
7
+ raise AuthenticationError, 'No authentication middleware present' unless authentication_middleware
8
+ middleware = authentication_middleware.new nil, self, options
9
+ middleware.authenticate!
10
+ end
11
+
12
+ # Internal: Determines what middleware will be used based on the options provided
13
+ def authentication_middleware
14
+ if username_password?
15
+ Force::Middleware::Authentication::Password
16
+ elsif oauth_refresh?
17
+ Force::Middleware::Authentication::Token
18
+ end
19
+ end
20
+
21
+ # Internal: Returns true if username/password (autonomous) flow should be used for
22
+ # authentication.
23
+ def username_password?
24
+ options[:username] &&
25
+ options[:password] &&
26
+ options[:client_id] &&
27
+ options[:client_secret]
28
+ end
29
+
30
+ # Internal: Returns true if oauth token refresh flow should be used for
31
+ # authentication.
32
+ def oauth_refresh?
33
+ options[:refresh_token] &&
34
+ options[:client_id] &&
35
+ options[:client_secret]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,59 @@
1
+ module Force
2
+ module Concerns
3
+ module Base
4
+ attr_reader :options
5
+
6
+ # Public: Creates a new client instance
7
+ #
8
+ # options - A hash of options to be passed in (default: {}).
9
+ # :username - The String username to use (required for password authentication).
10
+ # :password - The String password to use (required for password authentication).
11
+ # :security_token - The String security token to use (required for password authentication).
12
+ #
13
+ # :oauth_token - The String oauth access token to authenticate api
14
+ # calls (required unless password
15
+ # authentication is used).
16
+ # :refresh_token - The String refresh token to obtain fresh
17
+ # oauth access tokens (required if oauth
18
+ # authentication is used).
19
+ # :instance_url - The String base url for all api requests
20
+ # (required if oauth authentication is used).
21
+ #
22
+ # :client_id - The oauth client id to use. Needed for both
23
+ # password and oauth authentication
24
+ # :client_secret - The oauth client secret to use.
25
+ #
26
+ # :host - The String hostname to use during
27
+ # authentication requests (default: 'login.salesforce.com').
28
+ #
29
+ # :api_version - The String REST api version to use (default: '24.0')
30
+ #
31
+ # :authentication_retries - The number of times that client
32
+ # should attempt to reauthenticate
33
+ # before raising an exception (default: 3).
34
+ #
35
+ # :compress - Set to true to have Salesforce compress the response (default: false).
36
+ # :timeout - Faraday connection request read/open timeout. (default: nil).
37
+ #
38
+ # :proxy_uri - Proxy URI: 'http://proxy.example.com:port' or 'http://user@pass:proxy.example.com:port'
39
+ #
40
+ # :authentication_callback
41
+ # - A Proc that is called with the response body after a successful authentication.
42
+ def initialize(options = {})
43
+ @options = Hash[Force.configuration.options.map { |option| [option, Force.configuration.send(option)] }]
44
+ @options.merge!(options)
45
+
46
+ yield builder if block_given?
47
+ end
48
+
49
+ def instance_url
50
+ authenticate! unless options[:instance_url]
51
+ options[:instance_url]
52
+ end
53
+
54
+ def inspect
55
+ "#<#{self.class} @options=#{@options.inspect}>"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,24 @@
1
+ module Force
2
+ module Concerns
3
+ module Caching
4
+ # Public: Runs the block with caching disabled.
5
+ #
6
+ # block - A query/describe/etc.
7
+ #
8
+ # Returns the result of the block
9
+ def without_caching(&block)
10
+ options[:use_cache] = false
11
+ block.call
12
+ ensure
13
+ options.delete(:use_cache)
14
+ end
15
+
16
+ private
17
+
18
+ # Internal: Cache to use for the caching middleware
19
+ def cache
20
+ options[:cache]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module Force
2
+ module Concerns
3
+ module Canvas
4
+ def decode_signed_request(signed_request)
5
+ raise 'client_secret not set.' unless options[:client_secret]
6
+ SignedRequest.decode(signed_request, options[:client_secret])
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,74 @@
1
+ module Force
2
+ module Concerns
3
+ module Connection
4
+ # Public: The Faraday::Builder instance used for the middleware stack. This
5
+ # can be used to insert an custom middleware.
6
+ #
7
+ # Examples
8
+ #
9
+ # # Add the instrumentation middleware for Rails.
10
+ # client.middleware.use FaradayMiddleware::Instrumentation
11
+ #
12
+ # Returns the Faraday::Builder for the Faraday connection.
13
+ def middleware
14
+ connection.builder
15
+ end
16
+
17
+ alias_method :builder, :middleware
18
+
19
+ private
20
+
21
+ # Internal: Internal faraday connection where all requests go through
22
+ def connection
23
+ @connection ||= Faraday.new(options[:instance_url], connection_options) do |builder|
24
+ # Parses JSON into Hashie::Mash structures.
25
+ builder.use Force::Middleware::Mashify, self, options
26
+ # Handles multipart file uploads for blobs.
27
+ builder.use Force::Middleware::Multipart
28
+ # Converts the request into JSON.
29
+ builder.request :json
30
+ # Handles reauthentication for 403 responses.
31
+ builder.use authentication_middleware, self, options if authentication_middleware
32
+ # Sets the oauth token in the headers.
33
+ builder.use Force::Middleware::Authorization, self, options
34
+ # Ensures the instance url is set.
35
+ builder.use Force::Middleware::InstanceURL, self, options
36
+ # Parses returned JSON response into a hash.
37
+ builder.response :json, :content_type => /\bjson$/
38
+ # Caches GET requests.
39
+ builder.use Force::Middleware::Caching, cache, options if cache
40
+ # Follows 30x redirects.
41
+ builder.use FaradayMiddleware::FollowRedirects
42
+ # Raises errors for 40x responses.
43
+ builder.use Force::Middleware::RaiseError
44
+ # Log request/responses
45
+ builder.use Force::Middleware::Logger, Force.configuration.logger, options if Force.log?
46
+ # Compress/Decompress the request/response
47
+ builder.use Force::Middleware::Gzip, self, options
48
+
49
+ builder.adapter adapter
50
+ end
51
+ end
52
+
53
+ def adapter
54
+ options[:adapter]
55
+ end
56
+
57
+ # Internal: Faraday Connection options
58
+ def connection_options
59
+ { :request => {
60
+ :timeout => options[:timeout],
61
+ :open_timeout => options[:timeout] },
62
+ :proxy => options[:proxy_uri],
63
+ :ssl => {:verify => false}
64
+ }
65
+ end
66
+
67
+ # Internal: Returns true if the middlware stack includes the
68
+ # Force::Middleware::Mashify middleware.
69
+ def mashify?
70
+ middleware.handlers.index(Force::Middleware::Mashify)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,87 @@
1
+ module Force
2
+ module Concerns
3
+ module Picklists
4
+ # Public: Get the available picklist values for a picklist or multipicklist field.
5
+ #
6
+ # sobject - The String name of the sobject.
7
+ # field - The String name of the picklist/multipicklist field.
8
+ # options - A hash of options. (default: {}).
9
+ # :valid_for - If specified, will only return picklist values
10
+ # that are valid for the controlling picklist
11
+ # value
12
+ #
13
+ # Examples
14
+ #
15
+ # client.picklist_values('Account', 'Type')
16
+ # # => [#<Force::Mash label="Prospect" value="Prospect">]
17
+ #
18
+ # # Given a custom object named Automobile__c with picklist fields
19
+ # # Model__c and Make__c, where Model__c depends on the value of
20
+ # # Make__c.
21
+ # client.picklist_values('Automobile__c', 'Model__c', :valid_for => 'Honda')
22
+ # # => [#<Force::Mash label="Civic" value="Civic">, ... ]
23
+ #
24
+ # Returns an array of Force::Mash objects.
25
+ def picklist_values(sobject, field, options = {})
26
+ PicklistValues.new(describe(sobject)['fields'], field, options)
27
+ end
28
+
29
+ private
30
+
31
+ class PicklistValues < Array
32
+
33
+ def initialize(fields, field, options = {})
34
+ @fields, @field = fields, field
35
+ @valid_for = options.delete(:valid_for)
36
+ raise "#{field} is not a dependent picklist" if @valid_for && !dependent?
37
+ replace(picklist_values)
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :fields
43
+
44
+ def picklist_values
45
+ if valid_for?
46
+ field['picklistValues'].select { |picklist_entry| valid? picklist_entry }
47
+ else
48
+ field['picklistValues']
49
+ end
50
+ end
51
+
52
+ # Returns true of the given field is dependent on another field.
53
+ def dependent?
54
+ !!field['dependentPicklist']
55
+ end
56
+
57
+ def valid_for?
58
+ !!@valid_for
59
+ end
60
+
61
+ def controlling_picklist
62
+ @_controlling_picklist ||= controlling_field['picklistValues'].find { |picklist_entry| picklist_entry['value'] == @valid_for }
63
+ end
64
+
65
+ def index
66
+ @_index ||= controlling_field['picklistValues'].index(controlling_picklist)
67
+ end
68
+
69
+ def controlling_field
70
+ @_controlling_field ||= fields.find { |f| f['name'] == field['controllerName'] }
71
+ end
72
+
73
+ def field
74
+ @_field ||= fields.find { |f| f['name'] == @field }
75
+ end
76
+
77
+ # Returns true if the picklist entry is valid for the controlling picklist.
78
+ #
79
+ # See http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_describesobjects_describesobjectresult.htm
80
+ def valid?(picklist_entry)
81
+ valid_for = picklist_entry['validFor'].ljust(16, 'A').unpack('m').first.unpack('q*')
82
+ (valid_for[index >> 3] & (0x80 >> index % 8)) != 0
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,31 @@
1
+ module Force
2
+ module Concerns
3
+ module Streaming
4
+ # Public: Subscribe to a PushTopic
5
+ #
6
+ # channels - The name of the PushTopic channel(s) to subscribe to.
7
+ # block - A block to run when a new message is received.
8
+ #
9
+ # Returns a Faye::Subscription
10
+ def subscribe(channels, &block)
11
+ faye.subscribe Array(channels).map { |channel| "/topic/#{channel}" }, &block
12
+ end
13
+
14
+ # Public: Faye client to use for subscribing to PushTopics
15
+ def faye
16
+ raise 'Instance URL missing. Call .authenticate! first.' unless options[:instance_url]
17
+
18
+ @faye ||= Faye::Client.new("#{options[:instance_url]}/cometd/#{options[:api_version]}").tap do |client|
19
+ client.bind 'transport:down' do
20
+ Force.log "[COMETD DOWN]"
21
+ client.set_header 'Authorization', "OAuth #{authenticate!.access_token}"
22
+ end
23
+
24
+ client.bind 'transport:up' do
25
+ Force.log "[COMETD UP]"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,67 @@
1
+ module Force
2
+ module Concerns
3
+ module Verbs
4
+ # Internal: Define methods to handle a verb.
5
+ #
6
+ # verbs - A list of verbs to define methods for.
7
+ #
8
+ # Examples
9
+ #
10
+ # define_verbs :get, :post
11
+ #
12
+ # Returns nil.
13
+ def define_verbs(*verbs)
14
+ verbs.each do |verb|
15
+ define_verb(verb)
16
+ define_api_verb(verb)
17
+ end
18
+ end
19
+
20
+ # Internal: Defines a method to handle HTTP requests with the passed in
21
+ # verb.
22
+ #
23
+ # verb - Symbol name of the verb (e.g. :get).
24
+ #
25
+ # Examples
26
+ #
27
+ # define_verb :get
28
+ # # => get '/services/data/v24.0/sobjects'
29
+ #
30
+ # Returns nil.
31
+ def define_verb(verb)
32
+ define_method verb do |*args, &block|
33
+ retries = options[:authentication_retries]
34
+ begin
35
+ connection.send(verb, *args, &block)
36
+ rescue Force::UnauthorizedError
37
+ if retries > 0
38
+ retries -= 1
39
+ connection.url_prefix = options[:instance_url]
40
+ retry
41
+ end
42
+
43
+ raise
44
+ end
45
+ end
46
+ end
47
+
48
+ # Internal: Defines a method to handle HTTP requests with the passed in
49
+ # verb to a salesforce api endpoint.
50
+ #
51
+ # verb - Symbol name of the verb (e.g. :get).
52
+ #
53
+ # Examples
54
+ #
55
+ # define_api_verb :get
56
+ # # => api_get 'sobjects'
57
+ #
58
+ # Returns nil.
59
+ def define_api_verb(verb)
60
+ define_method :"api_#{verb}" do |*args, &block|
61
+ args[0] = api_path(args[0])
62
+ send(verb, *args, &block)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,140 @@
1
+ require 'logger'
2
+
3
+ module Force
4
+ class << self
5
+ attr_writer :log
6
+
7
+ # Returns the current Configuration
8
+ #
9
+ # Example
10
+ #
11
+ # Force.configuration.username = "username"
12
+ # Force.configuration.password = "password"
13
+ def configuration
14
+ @configuration ||= Configuration.new
15
+ end
16
+
17
+ # Yields the Configuration
18
+ #
19
+ # Example
20
+ #
21
+ # Force.configure do |config|
22
+ # config.username = "username"
23
+ # config.password = "password"
24
+ # end
25
+ def configure
26
+ yield configuration
27
+ end
28
+
29
+ def log?
30
+ @log ||= false
31
+ end
32
+
33
+ def log(message)
34
+ return unless Force.log?
35
+ Force.configuration.logger.send :debug, message
36
+ end
37
+ end
38
+
39
+ class Configuration
40
+ class Option
41
+ attr_reader :configuration, :name, :options
42
+
43
+ def self.define(*args)
44
+ new(*args).define
45
+ end
46
+
47
+ def initialize(configuration, name, options = {})
48
+ @configuration, @name, @options = configuration, name, options
49
+ @default = options.fetch(:default, nil)
50
+ end
51
+
52
+ def define
53
+ write_attribute
54
+ define_method if default_provided?
55
+ self
56
+ end
57
+
58
+ private
59
+
60
+ attr_reader :default
61
+ alias_method :default_provided?, :default
62
+
63
+ def write_attribute
64
+ configuration.send :attr_accessor, name
65
+ end
66
+
67
+ def define_method
68
+ our_default = default
69
+ our_name = name
70
+ configuration.send :define_method, our_name do
71
+ instance_variable_get(:"@#{our_name}") ||
72
+ instance_variable_set(:"@#{our_name}", our_default.respond_to?(:call) ? our_default.call : our_default)
73
+ end
74
+ end
75
+ end
76
+
77
+ class << self
78
+ attr_accessor :options
79
+
80
+ def option(*args)
81
+ option = Option.define(self, *args)
82
+ (self.options ||= []) << option.name
83
+ end
84
+ end
85
+
86
+ option :api_version, :default => '26.0'
87
+
88
+ # The username to use during login.
89
+ option :username, :default => lambda { ENV['SALESFORCE_USERNAME'] }
90
+
91
+ # The password to use during login.
92
+ option :password, :default => lambda { ENV['SALESFORCE_PASSWORD'] }
93
+
94
+ # The security token to use during login.
95
+ option :security_token, :default => lambda { ENV['SALESFORCE_SECURITY_TOKEN'] }
96
+
97
+ # The OAuth client id
98
+ option :client_id, :default => lambda { ENV['SALESFORCE_CLIENT_ID'] }
99
+
100
+ # The OAuth client secret
101
+ option :client_secret, :default => lambda { ENV['SALESFORCE_CLIENT_SECRET'] }
102
+
103
+ # Set this to true if you're authenticating with a Sandbox instance.
104
+ # Defaults to false.
105
+ option :host, :default => lambda { ENV['SALESFORCE_HOST'] || 'login.salesforce.com' }
106
+
107
+ option :oauth_token
108
+ option :refresh_token
109
+ option :instance_url
110
+
111
+ # Set this to an object that responds to read, write and fetch and all GET
112
+ # requests will be cached.
113
+ option :cache
114
+
115
+ # The number of times reauthentication should be tried before failing.
116
+ option :authentication_retries, :default => 3
117
+
118
+ # Set to true if you want responses from Salesforce to be gzip compressed.
119
+ option :compress
120
+
121
+ # Faraday request read/open timeout.
122
+ option :timeout
123
+
124
+ # Faraday adapter to use. Defaults to Faraday.default_adapter.
125
+ option :adapter, :default => lambda { Faraday.default_adapter }
126
+
127
+ option :proxy_uri, :default => lambda { ENV['PROXY_URI'] }
128
+
129
+ # A Proc that is called with the response body after a successful authentication.
130
+ option :authentication_callback
131
+
132
+ def logger
133
+ @logger ||= ::Logger.new STDOUT
134
+ end
135
+
136
+ def options
137
+ self.class.options
138
+ end
139
+ end
140
+ end