rforce 0.11 → 0.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.
- checksums.yaml +7 -0
- data/History.txt +9 -0
- data/Manifest.txt +3 -1
- data/README.rdoc +3 -4
- data/Rakefile +6 -3
- data/examples/oauth_setup.rb +26 -0
- data/examples/oauth_use.rb +25 -0
- data/examples/simple.rb +20 -0
- data/lib/rforce/binding.rb +85 -59
- data/lib/rforce/soap_response.rb +1 -3
- data/lib/rforce/version.rb +1 -1
- data/spec/rforce_spec.rb +7 -25
- data/tasks/timing.rake +0 -1
- metadata +30 -60
- data/lib/rforce/soap_response_hpricot.rb +0 -90
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 0f5d3cfdef0e31e56d1bc1d770e79f26323d0a6c
         | 
| 4 | 
            +
              data.tar.gz: a73f9b20c24d37ba4a3a68b2c43e16a1d9204822
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 861c42017d1f723532b074fef3e400e843f1fcf20e4da5448add773a769c02dc2c6ce17f2fc24d7eb009a44015e944f5297d8c55b8306dcbb71dc076b9004359
         | 
| 7 | 
            +
              data.tar.gz: baa7d21e2f81675213086da031bb0eca550658d3a9625f94f9a7e820fa4c51bc4a620804356fa8f00dd8688c6537b7d4fa4133a47ad8ee9f8d7c156e26a4e2d3
         | 
    
        data/History.txt
    CHANGED
    
    | @@ -1,3 +1,12 @@ | |
| 1 | 
            +
            == 0.12.0 2014-07-27
         | 
| 2 | 
            +
            * 2 enhancements
         | 
| 3 | 
            +
              * Clearer errors when skipping login (Victor Stan)
         | 
| 4 | 
            +
              * Allow passing in an optional logger (Jeff Jolma)
         | 
| 5 | 
            +
            * 3 bug fixes
         | 
| 6 | 
            +
              * Fixed URL error in OAuth flow (reported by karthickbabuos)
         | 
| 7 | 
            +
              * Corrected UTF-8 handling error (Maxime Rety)
         | 
| 8 | 
            +
              * Fixed repeat login issue (Jeff Jolma)
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            == 0.11.0 2013-06-08
         | 
| 2 11 | 
             
            * 1 minor enhancement
         | 
| 3 12 | 
             
              * Give the README an .rdoc extension for easy Github viewing
         | 
    
        data/Manifest.txt
    CHANGED
    
    | @@ -2,13 +2,15 @@ History.txt | |
| 2 2 | 
             
            Manifest.txt
         | 
| 3 3 | 
             
            README.rdoc
         | 
| 4 4 | 
             
            Rakefile
         | 
| 5 | 
            +
            examples/oauth_setup.rb
         | 
| 6 | 
            +
            examples/oauth_use.rb
         | 
| 7 | 
            +
            examples/simple.rb
         | 
| 5 8 | 
             
            lib/rforce.rb
         | 
| 6 9 | 
             
            lib/rforce/binding.rb
         | 
| 7 10 | 
             
            lib/rforce/method_keys.rb
         | 
| 8 11 | 
             
            lib/rforce/soap_pullable.rb
         | 
| 9 12 | 
             
            lib/rforce/soap_response.rb
         | 
| 10 13 | 
             
            lib/rforce/soap_response_expat.rb
         | 
| 11 | 
            -
            lib/rforce/soap_response_hpricot.rb
         | 
| 12 14 | 
             
            lib/rforce/soap_response_nokogiri.rb
         | 
| 13 15 | 
             
            lib/rforce/soap_response_rexml.rb
         | 
| 14 16 | 
             
            lib/rforce/version.rb
         | 
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,9 +1,8 @@ | |
| 1 1 | 
             
            = rforce
         | 
| 2 2 |  | 
| 3 | 
            -
            * http://rforce.rubyforge.org
         | 
| 4 | 
            -
            * http://rubyforge.org/projects/rforce
         | 
| 5 | 
            -
            * http://bitbucket.org/undees/rforce
         | 
| 6 3 | 
             
            * http://github.com/undees/rforce
         | 
| 4 | 
            +
            * http://bitbucket.org/undees/rforce
         | 
| 5 | 
            +
            * http://rdoc.info/github/undees/rforce
         | 
| 7 6 |  | 
| 8 7 | 
             
            == DESCRIPTION:
         | 
| 9 8 |  | 
| @@ -75,7 +74,7 @@ Rather than enforcing adherence to the sforce.com schema, RForce assumes you are | |
| 75 74 |  | 
| 76 75 | 
             
            == LICENSE:
         | 
| 77 76 |  | 
| 78 | 
            -
            Copyright (c) 2005- | 
| 77 | 
            +
            Copyright (c) 2005-2014 Ian Dees and contributors
         | 
| 79 78 |  | 
| 80 79 | 
             
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 81 80 | 
             
            a copy of this software and associated documentation files (the
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -8,16 +8,19 @@ require 'hoe/gemspec2' | |
| 8 8 | 
             
            Hoe.plugin :gemspec2
         | 
| 9 9 |  | 
| 10 10 | 
             
            Hoe.spec 'rforce' do
         | 
| 11 | 
            +
              is_jruby = (RUBY_PLATFORM == 'java')
         | 
| 12 | 
            +
              is_ruby18 = (RUBY_VERSION =~ /^1.8/)
         | 
| 13 | 
            +
             | 
| 11 14 | 
             
              developer('Ian Dees', 'undees@gmail.com')
         | 
| 15 | 
            +
              license('MIT')
         | 
| 12 16 |  | 
| 13 17 | 
             
              self.extra_deps << ['builder', '~> 3.0']
         | 
| 14 18 | 
             
              self.extra_deps << ['oauth', '~> 0.4']
         | 
| 15 19 |  | 
| 16 20 | 
             
              self.extra_dev_deps << ['rspec', '~> 2.8']
         | 
| 17 21 | 
             
              self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
         | 
| 18 | 
            -
              self.extra_dev_deps << [' | 
| 19 | 
            -
              self.extra_dev_deps << [' | 
| 20 | 
            -
              self.extra_dev_deps << ['xmlparser', '~> 0.7']
         | 
| 22 | 
            +
              self.extra_dev_deps << ['nokogiri', '~> 1.5'] unless is_ruby18
         | 
| 23 | 
            +
              self.extra_dev_deps << ['xmlparser', '~> 0.7'] unless is_jruby
         | 
| 21 24 |  | 
| 22 25 | 
             
              self.rdoc_locations = ['undees@rforce.rubyforge.org:/var/www/gforge-projects/rforce']
         | 
| 23 26 | 
             
              self.remote_rdoc_dir = ''
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'oauth'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            consumer_key    = ENV['SALESFORCE_CONSUMER_KEY']
         | 
| 4 | 
            +
            consumer_secret = ENV['SALESFORCE_CONSUMER_SECRET']
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            oauth_options = {
         | 
| 7 | 
            +
              :site               => 'https://login.salesforce.com',
         | 
| 8 | 
            +
              :scheme             => :body,
         | 
| 9 | 
            +
              :request_token_path => '/_nc_external/system/security/oauth/RequestTokenHandler',
         | 
| 10 | 
            +
              :authorize_path     => '/setup/secur/RemoteAccessAuthorizationPage.apexp',
         | 
| 11 | 
            +
              :access_token_path  => '/_nc_external/system/security/oauth/AccessTokenHandler',
         | 
| 12 | 
            +
            }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            consumer = OAuth::Consumer.new consumer_key, consumer_secret, oauth_options
         | 
| 15 | 
            +
            # consumer.http.set_debug_output STDERR # if you're curious
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            request       = consumer.get_request_token
         | 
| 18 | 
            +
            authorize_url = request.authorize_url :oauth_consumer_key => consumer_key
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            puts "Go to #{authorize_url} in your browser, then enter the verification code:"
         | 
| 21 | 
            +
            verification_code = gets.strip
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            access = request.get_access_token :oauth_verifier => verification_code
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            puts "Access Token:  " + access.token
         | 
| 26 | 
            +
            puts "Access Secret: " + access.secret
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            require 'rforce'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            oauth = {
         | 
| 4 | 
            +
              :consumer_key    => ENV['SALESFORCE_CONSUMER_KEY'],
         | 
| 5 | 
            +
              :consumer_secret => ENV['SALESFORCE_CONSUMER_SECRET'],
         | 
| 6 | 
            +
              :access_token    => ENV['SALESFORCE_ACCESS_TOKEN'],
         | 
| 7 | 
            +
              :access_secret   => ENV['SALESFORCE_ACCESS_SECRET'],
         | 
| 8 | 
            +
              :login_url       => 'https://login.salesforce.com/services/OAuth/u/20.0'
         | 
| 9 | 
            +
            }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            binding = RForce::Binding.new \
         | 
| 12 | 
            +
              'https://www.salesforce.com/services/Soap/u/20.0',
         | 
| 13 | 
            +
              nil,
         | 
| 14 | 
            +
              oauth
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            binding.login_with_oauth
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            answer = binding.search \
         | 
| 19 | 
            +
              :searchString =>
         | 
| 20 | 
            +
                'find {McFakerson Co} in name fields returning account(id)'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            account = answer.searchResponse.result.searchRecords.record
         | 
| 23 | 
            +
            account_id = account.Id
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            puts account_id
         | 
    
        data/examples/simple.rb
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require 'rforce'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            email    = ENV['SALESFORCE_USER']
         | 
| 4 | 
            +
            password = ENV['SALESFORCE_PASS']
         | 
| 5 | 
            +
            token    = ENV['SALESFORCE_TOKEN']
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            binding = RForce::Binding.new \
         | 
| 8 | 
            +
              'https://www.salesforce.com/services/Soap/u/20.0'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            binding.login \
         | 
| 11 | 
            +
              email, password + token
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            answer = binding.search \
         | 
| 14 | 
            +
              :searchString =>
         | 
| 15 | 
            +
                'find {McFakerson Co} in name fields returning account(id)'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            account = answer.searchResponse.result.searchRecords.record
         | 
| 18 | 
            +
            account_id = account.Id
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            puts account_id
         | 
    
        data/lib/rforce/binding.rb
    CHANGED
    
    | @@ -44,99 +44,87 @@ module RForce | |
| 44 44 | 
             
                MruHeader = '<partner:MruHeader soap:mustUnderstand="1"><partner:updateMru>true</partner:updateMru></partner:MruHeader>'
         | 
| 45 45 | 
             
                ClientIdHeader = '<partner:CallOptions soap:mustUnderstand="1"><partner:client>%s</partner:client></partner:CallOptions>'
         | 
| 46 46 |  | 
| 47 | 
            -
                #  | 
| 48 | 
            -
                #  | 
| 47 | 
            +
                # Create a binding to the server (after which you can call login
         | 
| 48 | 
            +
                # or login_with_oauth to connect to it). If you pass an oauth
         | 
| 49 | 
            +
                # hash, it must contain the keys :consumer_key, :consumer_secret,
         | 
| 49 50 | 
             
                # :access_token, :access_secret, and :login_url.
         | 
| 50 51 | 
             
                #
         | 
| 51 52 | 
             
                # proxy may be a URL of the form http://user:pass@example.com:port
         | 
| 52 53 | 
             
                #
         | 
| 53 | 
            -
                 | 
| 54 | 
            +
                # if a logger is specified, it will be used for very verbose SOAP logging
         | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                def initialize(url, sid = nil, oauth = nil, proxy = nil, logger = nil)
         | 
| 54 57 | 
             
                  @session_id = sid
         | 
| 55 58 | 
             
                  @oauth = oauth
         | 
| 56 59 | 
             
                  @proxy = proxy
         | 
| 57 60 | 
             
                  @batch_size = DEFAULT_BATCH_SIZE
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                   | 
| 61 | 
            +
                  @logger = logger
         | 
| 62 | 
            +
                  @url = URI.parse(url)
         | 
| 60 63 | 
             
                end
         | 
| 61 64 |  | 
| 62 | 
            -
             | 
| 63 65 | 
             
                def show_debug
         | 
| 64 66 | 
             
                  ENV['SHOWSOAP'] == 'true'
         | 
| 65 67 | 
             
                end
         | 
| 66 68 |  | 
| 69 | 
            +
                def create_server(url)
         | 
| 70 | 
            +
                  server = Net::HTTP.Proxy(@proxy).new(url.host, url.port)
         | 
| 71 | 
            +
                  server.use_ssl = (url.scheme == 'https')
         | 
| 72 | 
            +
                  server.verify_mode = OpenSSL::SSL::VERIFY_NONE
         | 
| 67 73 |  | 
| 68 | 
            -
             | 
| 69 | 
            -
                   | 
| 70 | 
            -
             | 
| 71 | 
            -
                  if (@oauth)
         | 
| 72 | 
            -
                    consumer = OAuth::Consumer.new \
         | 
| 73 | 
            -
                      @oauth[:consumer_key],
         | 
| 74 | 
            -
                      @oauth[:consumer_secret],
         | 
| 75 | 
            -
                      {
         | 
| 76 | 
            -
                        :site => url,
         | 
| 77 | 
            -
                        :proxy => @proxy
         | 
| 78 | 
            -
                      }
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                    consumer.http.set_debug_output $stderr if show_debug
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                    @server  = OAuth::AccessToken.new \
         | 
| 83 | 
            -
                      consumer,
         | 
| 84 | 
            -
                      @oauth[:access_token],
         | 
| 85 | 
            -
                      @oauth[:access_secret]
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                    class << @server
         | 
| 88 | 
            -
                      alias_method :post2, :post
         | 
| 89 | 
            -
                    end
         | 
| 90 | 
            -
                  else
         | 
| 91 | 
            -
                    @server = Net::HTTP.Proxy(@proxy).new(@url.host, @url.port)
         | 
| 92 | 
            -
                    @server.use_ssl = @url.scheme == 'https'
         | 
| 93 | 
            -
                    @server.verify_mode = OpenSSL::SSL::VERIFY_NONE
         | 
| 94 | 
            -
             | 
| 95 | 
            -
                    # run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
         | 
| 96 | 
            -
                    @server.set_debug_output $stderr if show_debug
         | 
| 97 | 
            -
                  end
         | 
| 98 | 
            -
                end
         | 
| 99 | 
            -
             | 
| 100 | 
            -
                #  Connect to remote server
         | 
| 101 | 
            -
                #
         | 
| 102 | 
            -
                def connect(user, password)
         | 
| 103 | 
            -
                  @user = user
         | 
| 104 | 
            -
                  @password = password
         | 
| 74 | 
            +
                  # run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
         | 
| 75 | 
            +
                  server.set_debug_output $stderr if show_debug
         | 
| 105 76 |  | 
| 106 | 
            -
                   | 
| 77 | 
            +
                  return server
         | 
| 107 78 | 
             
                end
         | 
| 108 79 |  | 
| 109 80 | 
             
                # Log in to the server with a user name and password, remembering
         | 
| 110 81 | 
             
                # the session ID returned to us by Salesforce.
         | 
| 111 82 | 
             
                def login(user, password)
         | 
| 112 | 
            -
                   | 
| 83 | 
            +
                  @user     = user
         | 
| 84 | 
            +
                  @password = password
         | 
| 85 | 
            +
                  @server   = create_server(@url)
         | 
| 86 | 
            +
                  response  = call_remote(:login, [:username, user, :password, password])
         | 
| 113 87 |  | 
| 114 88 | 
             
                  raise "Incorrect user name / password [#{response.Fault}]" unless response.loginResponse
         | 
| 115 89 |  | 
| 116 | 
            -
                  result | 
| 90 | 
            +
                  result      = response[:loginResponse][:result]
         | 
| 117 91 | 
             
                  @session_id = result[:sessionId]
         | 
| 92 | 
            +
                  @url        = URI.parse(result[:serverUrl])
         | 
| 93 | 
            +
                  @server     = create_server(@url)
         | 
| 118 94 |  | 
| 119 | 
            -
                   | 
| 120 | 
            -
             | 
| 121 | 
            -
                  response
         | 
| 95 | 
            +
                  return response
         | 
| 122 96 | 
             
                end
         | 
| 123 97 |  | 
| 124 98 | 
             
                # Log in to the server with OAuth, remembering
         | 
| 125 99 | 
             
                # the session ID returned to us by Salesforce.
         | 
| 126 100 | 
             
                def login_with_oauth
         | 
| 127 | 
            -
                   | 
| 128 | 
            -
                    @oauth[: | 
| 101 | 
            +
                  consumer = OAuth::Consumer.new \
         | 
| 102 | 
            +
                    @oauth[:consumer_key],
         | 
| 103 | 
            +
                    @oauth[:consumer_secret]
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  access = OAuth::AccessToken.new \
         | 
| 106 | 
            +
                    consumer, @oauth[:access_token],
         | 
| 107 | 
            +
                    @oauth[:access_secret]
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  login_url = @oauth[:login_url]
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  result = access.post \
         | 
| 112 | 
            +
                    login_url,
         | 
| 129 113 | 
             
                    '',
         | 
| 130 114 | 
             
                    {'content-type' => 'application/x-www-form-urlencoded'}
         | 
| 131 115 |  | 
| 132 116 | 
             
                  case result
         | 
| 133 117 | 
             
                  when Net::HTTPSuccess
         | 
| 134 | 
            -
                    doc | 
| 118 | 
            +
                    doc         = REXML::Document.new result.body
         | 
| 135 119 | 
             
                    @session_id = doc.elements['*/sessionId'].text
         | 
| 136 | 
            -
                     | 
| 137 | 
            -
                     | 
| 120 | 
            +
                    @url        = URI.parse(doc.elements['*/serverUrl'].text)
         | 
| 121 | 
            +
                    @server     = access
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                    class << @server
         | 
| 124 | 
            +
                      alias_method :post2, :post
         | 
| 125 | 
            +
                    end
         | 
| 138 126 |  | 
| 139 | 
            -
                    return {:sessionId => @ | 
| 127 | 
            +
                    return {:sessionId => @session_id, :serverUrl => @url.to_s}
         | 
| 140 128 | 
             
                  when Net::HTTPUnauthorized
         | 
| 141 129 | 
             
                    raise 'Invalid OAuth tokens'
         | 
| 142 130 | 
             
                  else
         | 
| @@ -148,8 +136,11 @@ module RForce | |
| 148 136 | 
             
                # a hash or (if order is important) an array of alternating
         | 
| 149 137 | 
             
                # keys and values.
         | 
| 150 138 | 
             
                def call_remote(method, args)
         | 
| 139 | 
            +
                  # Different URI requirements for regular vs. OAuth.  This is
         | 
| 140 | 
            +
                  # *screaming* for a refactor.
         | 
| 141 | 
            +
                  fallback_soap_url = @oauth ? @url.to_s : @url.path
         | 
| 151 142 |  | 
| 152 | 
            -
                  urn, soap_url = block_given? ? yield : ["urn:partner.soap.sforce.com",  | 
| 143 | 
            +
                  urn, soap_url = block_given? ? yield : ["urn:partner.soap.sforce.com", fallback_soap_url]
         | 
| 153 144 |  | 
| 154 145 | 
             
                  # Create XML text from the arguments.
         | 
| 155 146 | 
             
                  expanded = ''
         | 
| @@ -181,6 +172,7 @@ module RForce | |
| 181 172 | 
             
                  # Fill in the blanks of the SOAP envelope with our
         | 
| 182 173 | 
             
                  # session ID and the expanded XML of our request.
         | 
| 183 174 | 
             
                  request = (Envelope % [@session_id, extra_headers, expanded])
         | 
| 175 | 
            +
                  @logger && @logger.info("RForce request: #{request}")
         | 
| 184 176 |  | 
| 185 177 | 
             
                  # reset the batch size for the next request
         | 
| 186 178 | 
             
                  @batch_size = DEFAULT_BATCH_SIZE
         | 
| @@ -201,14 +193,23 @@ module RForce | |
| 201 193 | 
             
                  end
         | 
| 202 194 |  | 
| 203 195 | 
             
                  # Send the request to the server and read the response.
         | 
| 196 | 
            +
                  @logger && @logger.info("RForce request to host #{@server} url #{soap_url} headers: #{headers}")
         | 
| 204 197 | 
             
                  response = @server.post2(soap_url, request.lstrip, headers)
         | 
| 205 198 |  | 
| 206 199 | 
             
                  # decode if we have encoding
         | 
| 207 200 | 
             
                  content = decode(response)
         | 
| 208 201 |  | 
| 202 | 
            +
                  # Fix charset encoding. Needed because the "content" variable may contain a UTF-8
         | 
| 203 | 
            +
                  # or ISO-8859-1 string, but is carrying the US-ASCII encoding.
         | 
| 204 | 
            +
                  content = fix_encoding(content)
         | 
| 205 | 
            +
             | 
| 209 206 | 
             
                  # Check to see if INVALID_SESSION_ID was raised and try to relogin in
         | 
| 210 207 | 
             
                  if method != :login and @session_id and content =~ /sf:INVALID_SESSION_ID/
         | 
| 211 | 
            -
                     | 
| 208 | 
            +
                    if @user
         | 
| 209 | 
            +
                      login(@user, @password)
         | 
| 210 | 
            +
                    else
         | 
| 211 | 
            +
                      raise "INVALID_SESSION_ID"
         | 
| 212 | 
            +
                    end
         | 
| 212 213 |  | 
| 213 214 | 
             
                    # repackage and rencode request with the new session id
         | 
| 214 215 | 
             
                    request = (Envelope % [@session_id, extra_headers, expanded])
         | 
| @@ -218,12 +219,16 @@ module RForce | |
| 218 219 | 
             
                    response = @server.post2(soap_url, request.lstrip, headers)
         | 
| 219 220 |  | 
| 220 221 | 
             
                    content = decode(response)
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                    # Fix charset encoding. Needed because the "content" variable may contain a UTF-8
         | 
| 224 | 
            +
                    # or ISO-8859-1 string, but is carrying the US-ASCII encoding.
         | 
| 225 | 
            +
                    content = fix_encoding(content)
         | 
| 221 226 | 
             
                  end
         | 
| 222 227 |  | 
| 228 | 
            +
                  @logger && @logger.info("RForce response: #{content}")
         | 
| 223 229 | 
             
                  SoapResponse.new(content).parse
         | 
| 224 230 | 
             
                end
         | 
| 225 231 |  | 
| 226 | 
            -
             | 
| 227 232 | 
             
                # decode gzip
         | 
| 228 233 | 
             
                def decode(response)
         | 
| 229 234 | 
             
                  encoding = response['Content-Encoding']
         | 
| @@ -246,7 +251,6 @@ module RForce | |
| 246 251 | 
             
                  end
         | 
| 247 252 | 
             
                end
         | 
| 248 253 |  | 
| 249 | 
            -
             | 
| 250 254 | 
             
                # encode gzip
         | 
| 251 255 | 
             
                def encode(request)
         | 
| 252 256 | 
             
                  return request if show_debug
         | 
| @@ -261,6 +265,28 @@ module RForce | |
| 261 265 | 
             
                  end
         | 
| 262 266 | 
             
                end
         | 
| 263 267 |  | 
| 268 | 
            +
                # fix invalid US-ASCII strings by applying the correct encoding on ruby 1.9+
         | 
| 269 | 
            +
                def fix_encoding(string)
         | 
| 270 | 
            +
                  if [:valid_encoding?, :force_encoding].all? { |m| string.respond_to?(m) }
         | 
| 271 | 
            +
                    if !string.valid_encoding?
         | 
| 272 | 
            +
                      # The 2 possible encodings in responses are UTF-8 and ISO-8859-1
         | 
| 273 | 
            +
                      # http://www.salesforce.com/us/developer/docs/api/Content/implementation_considerations.htm#topic-title_international
         | 
| 274 | 
            +
                      #
         | 
| 275 | 
            +
                      ["UTF-8", "ISO-8859-1"].each do |encoding_name|
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                        s = string.dup.force_encoding(encoding_name)
         | 
| 278 | 
            +
             | 
| 279 | 
            +
                        if s.valid_encoding?
         | 
| 280 | 
            +
                          return s
         | 
| 281 | 
            +
                        end
         | 
| 282 | 
            +
                      end
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                      raise "Invalid encoding in SOAP response: not in [US-ASCII, UTF-8, ISO-8859-1]"
         | 
| 285 | 
            +
                    end
         | 
| 286 | 
            +
                  end
         | 
| 287 | 
            +
             | 
| 288 | 
            +
                  return string
         | 
| 289 | 
            +
                end
         | 
| 264 290 |  | 
| 265 291 | 
             
                # Turns method calls on this object into remote SOAP calls.
         | 
| 266 292 | 
             
                def method_missing(method, *args)
         | 
    
        data/lib/rforce/soap_response.rb
    CHANGED
    
    | @@ -1,5 +1,4 @@ | |
| 1 1 | 
             
            begin; require 'rforce/soap_response_nokogiri'; rescue LoadError; end
         | 
| 2 | 
            -
            begin; require 'rforce/soap_response_hpricot'; rescue LoadError; end
         | 
| 3 2 | 
             
            begin; require 'rforce/soap_response_expat';   rescue LoadError; end
         | 
| 4 3 | 
             
            require 'rforce/soap_response_rexml'
         | 
| 5 4 |  | 
| @@ -7,8 +6,7 @@ require 'rforce/soap_response_rexml' | |
| 7 6 | 
             
            module RForce
         | 
| 8 7 | 
             
              # Use the fastest XML parser available.
         | 
| 9 8 | 
             
              SoapResponse =
         | 
| 10 | 
            -
                (RForce::const_get(:SoapResponseExpat) rescue nil)    ||
         | 
| 11 9 | 
             
                (RForce::const_get(:SoapResponseNokogiri) rescue nil) ||
         | 
| 12 | 
            -
                (RForce::const_get(: | 
| 10 | 
            +
                (RForce::const_get(:SoapResponseExpat) rescue nil)    ||
         | 
| 13 11 | 
             
                SoapResponseRexml
         | 
| 14 12 | 
             
            end
         | 
    
        data/lib/rforce/version.rb
    CHANGED
    
    
    
        data/spec/rforce_spec.rb
    CHANGED
    
    | @@ -60,7 +60,7 @@ describe 'a SoapResponse implementation' do | |
| 60 60 | 
             
                fname = File.join(File.dirname(__FILE__), 'soap-response.xml')
         | 
| 61 61 | 
             
                @contents = File.open(fname) {|f| f.read}
         | 
| 62 62 |  | 
| 63 | 
            -
                [:rexml, :expat, : | 
| 63 | 
            +
                [:rexml, :expat, :nokogiri].each do |processor|
         | 
| 64 64 | 
             
                  name     = "SoapResponse#{processor.to_s.capitalize}".to_sym
         | 
| 65 65 | 
             
                  variable = "@#{processor}_recs".to_sym
         | 
| 66 66 |  | 
| @@ -82,14 +82,10 @@ describe 'a SoapResponse implementation' do | |
| 82 82 |  | 
| 83 83 | 
             
              # Special-case expat tests for CI
         | 
| 84 84 | 
             
              it 'returns the same results with expat' do
         | 
| 85 | 
            -
                 | 
| 85 | 
            +
                skip 'expat not installed' unless @expat_recs
         | 
| 86 86 | 
             
                @expat_recs.should == @rexml_recs
         | 
| 87 87 | 
             
              end
         | 
| 88 88 |  | 
| 89 | 
            -
              it 'returns the same results with hpricot' do
         | 
| 90 | 
            -
                @hpricot_recs.should == @rexml_recs
         | 
| 91 | 
            -
              end
         | 
| 92 | 
            -
             | 
| 93 89 | 
             
              it 'understands XML entities' do
         | 
| 94 90 | 
             
                expected = "Bee's knees"
         | 
| 95 91 | 
             
                @rexml_recs.first.Description.should == expected
         | 
| @@ -98,16 +94,6 @@ describe 'a SoapResponse implementation' do | |
| 98 94 | 
             
                if @expat_recs
         | 
| 99 95 | 
             
                  @expat_recs.first.Description.should == expected
         | 
| 100 96 | 
             
                end
         | 
| 101 | 
            -
             | 
| 102 | 
            -
                @hpricot_recs.first.Description.should == expected
         | 
| 103 | 
            -
              end
         | 
| 104 | 
            -
            end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
            describe 'SoapResponseHpricot' do
         | 
| 107 | 
            -
              it 'parses basic XML entities' do
         | 
| 108 | 
            -
                text = '<tag attr="Bee's knees & toes">'
         | 
| 109 | 
            -
                SoapResponseHpricot.unescapeXML(text).should ==
         | 
| 110 | 
            -
                  %q(<tag attr="Bee's knees & toes">)
         | 
| 111 97 | 
             
              end
         | 
| 112 98 | 
             
            end
         | 
| 113 99 |  | 
| @@ -213,9 +199,11 @@ shared_examples_for 'a SOAP response' do | |
| 213 199 | 
             
              end
         | 
| 214 200 | 
             
            end
         | 
| 215 201 |  | 
| 216 | 
            -
             | 
| 217 | 
            -
               | 
| 218 | 
            -
                 | 
| 202 | 
            +
            if RForce.const_defined? :SoapResponseNokogiri
         | 
| 203 | 
            +
              describe 'SoapResponseNokogiri' do
         | 
| 204 | 
            +
                it_behaves_like 'a SOAP response' do
         | 
| 205 | 
            +
                  let(:klass) { SoapResponseNokogiri }
         | 
| 206 | 
            +
                end
         | 
| 219 207 | 
             
              end
         | 
| 220 208 | 
             
            end
         | 
| 221 209 |  | 
| @@ -234,12 +222,6 @@ describe 'SoapResponseRexml' do | |
| 234 222 | 
             
              end
         | 
| 235 223 | 
             
            end
         | 
| 236 224 |  | 
| 237 | 
            -
            describe 'SoapResponseHpricot' do
         | 
| 238 | 
            -
              it_behaves_like 'a SOAP response' do
         | 
| 239 | 
            -
                let(:klass) { SoapResponseHpricot }
         | 
| 240 | 
            -
              end
         | 
| 241 | 
            -
            end
         | 
| 242 | 
            -
             | 
| 243 225 | 
             
            CreateXml = <<HERE.gsub(/\n\s*/, '')
         | 
| 244 226 | 
             
            <partner:create>
         | 
| 245 227 | 
             
              <partner:sObjects>
         | 
    
        data/tasks/timing.rake
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,20 +1,18 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rforce
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: '0. | 
| 5 | 
            -
              prerelease: 
         | 
| 4 | 
            +
              version: '0.12'
         | 
| 6 5 | 
             
            platform: ruby
         | 
| 7 6 | 
             
            authors:
         | 
| 8 7 | 
             
            - Ian Dees
         | 
| 9 8 | 
             
            autorequire: 
         | 
| 10 9 | 
             
            bindir: bin
         | 
| 11 10 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date:  | 
| 11 | 
            +
            date: 2014-07-28 00:00:00.000000000 Z
         | 
| 13 12 | 
             
            dependencies:
         | 
| 14 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 14 | 
             
              name: builder
         | 
| 16 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            -
                none: false
         | 
| 18 16 | 
             
                requirements:
         | 
| 19 17 | 
             
                - - ~>
         | 
| 20 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| @@ -22,7 +20,6 @@ dependencies: | |
| 22 20 | 
             
              type: :runtime
         | 
| 23 21 | 
             
              prerelease: false
         | 
| 24 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            -
                none: false
         | 
| 26 23 | 
             
                requirements:
         | 
| 27 24 | 
             
                - - ~>
         | 
| 28 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| @@ -30,7 +27,6 @@ dependencies: | |
| 30 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 31 28 | 
             
              name: oauth
         | 
| 32 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 33 | 
            -
                none: false
         | 
| 34 30 | 
             
                requirements:
         | 
| 35 31 | 
             
                - - ~>
         | 
| 36 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| @@ -38,63 +34,55 @@ dependencies: | |
| 38 34 | 
             
              type: :runtime
         | 
| 39 35 | 
             
              prerelease: false
         | 
| 40 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 41 | 
            -
                none: false
         | 
| 42 37 | 
             
                requirements:
         | 
| 43 38 | 
             
                - - ~>
         | 
| 44 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 45 40 | 
             
                    version: '0.4'
         | 
| 46 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 47 | 
            -
              name:  | 
| 42 | 
            +
              name: rdoc
         | 
| 48 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 49 | 
            -
                none: false
         | 
| 50 44 | 
             
                requirements:
         | 
| 51 45 | 
             
                - - ~>
         | 
| 52 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 53 | 
            -
                    version: ' | 
| 47 | 
            +
                    version: '4.0'
         | 
| 54 48 | 
             
              type: :development
         | 
| 55 49 | 
             
              prerelease: false
         | 
| 56 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 57 | 
            -
                none: false
         | 
| 58 51 | 
             
                requirements:
         | 
| 59 52 | 
             
                - - ~>
         | 
| 60 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            -
                    version: ' | 
| 54 | 
            +
                    version: '4.0'
         | 
| 62 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 63 | 
            -
              name:  | 
| 56 | 
            +
              name: rspec
         | 
| 64 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 65 | 
            -
                none: false
         | 
| 66 58 | 
             
                requirements:
         | 
| 67 59 | 
             
                - - ~>
         | 
| 68 60 | 
             
                  - !ruby/object:Gem::Version
         | 
| 69 | 
            -
                    version: ' | 
| 61 | 
            +
                    version: '2.8'
         | 
| 70 62 | 
             
              type: :development
         | 
| 71 63 | 
             
              prerelease: false
         | 
| 72 64 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 73 | 
            -
                none: false
         | 
| 74 65 | 
             
                requirements:
         | 
| 75 66 | 
             
                - - ~>
         | 
| 76 67 | 
             
                  - !ruby/object:Gem::Version
         | 
| 77 | 
            -
                    version: ' | 
| 68 | 
            +
                    version: '2.8'
         | 
| 78 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 79 | 
            -
              name:  | 
| 70 | 
            +
              name: hoe-gemspec2
         | 
| 80 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 81 | 
            -
                none: false
         | 
| 82 72 | 
             
                requirements:
         | 
| 83 73 | 
             
                - - ~>
         | 
| 84 74 | 
             
                  - !ruby/object:Gem::Version
         | 
| 85 | 
            -
                    version: ' | 
| 75 | 
            +
                    version: '1.1'
         | 
| 86 76 | 
             
              type: :development
         | 
| 87 77 | 
             
              prerelease: false
         | 
| 88 78 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 89 | 
            -
                none: false
         | 
| 90 79 | 
             
                requirements:
         | 
| 91 80 | 
             
                - - ~>
         | 
| 92 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 93 | 
            -
                    version: ' | 
| 82 | 
            +
                    version: '1.1'
         | 
| 94 83 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 95 84 | 
             
              name: nokogiri
         | 
| 96 85 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 97 | 
            -
                none: false
         | 
| 98 86 | 
             
                requirements:
         | 
| 99 87 | 
             
                - - ~>
         | 
| 100 88 | 
             
                  - !ruby/object:Gem::Version
         | 
| @@ -102,7 +90,6 @@ dependencies: | |
| 102 90 | 
             
              type: :development
         | 
| 103 91 | 
             
              prerelease: false
         | 
| 104 92 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 105 | 
            -
                none: false
         | 
| 106 93 | 
             
                requirements:
         | 
| 107 94 | 
             
                - - ~>
         | 
| 108 95 | 
             
                  - !ruby/object:Gem::Version
         | 
| @@ -110,7 +97,6 @@ dependencies: | |
| 110 97 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 111 98 | 
             
              name: xmlparser
         | 
| 112 99 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 113 | 
            -
                none: false
         | 
| 114 100 | 
             
                requirements:
         | 
| 115 101 | 
             
                - - ~>
         | 
| 116 102 | 
             
                  - !ruby/object:Gem::Version
         | 
| @@ -118,47 +104,28 @@ dependencies: | |
| 118 104 | 
             
              type: :development
         | 
| 119 105 | 
             
              prerelease: false
         | 
| 120 106 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            -
                none: false
         | 
| 122 107 | 
             
                requirements:
         | 
| 123 108 | 
             
                - - ~>
         | 
| 124 109 | 
             
                  - !ruby/object:Gem::Version
         | 
| 125 110 | 
             
                    version: '0.7'
         | 
| 126 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 127 | 
            -
              name: rdoc
         | 
| 128 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 129 | 
            -
                none: false
         | 
| 130 | 
            -
                requirements:
         | 
| 131 | 
            -
                - - ~>
         | 
| 132 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 133 | 
            -
                    version: '3.10'
         | 
| 134 | 
            -
              type: :development
         | 
| 135 | 
            -
              prerelease: false
         | 
| 136 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 137 | 
            -
                none: false
         | 
| 138 | 
            -
                requirements:
         | 
| 139 | 
            -
                - - ~>
         | 
| 140 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 141 | 
            -
                    version: '3.10'
         | 
| 142 111 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 143 112 | 
             
              name: hoe
         | 
| 144 113 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 145 | 
            -
                none: false
         | 
| 146 114 | 
             
                requirements:
         | 
| 147 115 | 
             
                - - ~>
         | 
| 148 116 | 
             
                  - !ruby/object:Gem::Version
         | 
| 149 | 
            -
                    version: ' | 
| 117 | 
            +
                    version: '3.12'
         | 
| 150 118 | 
             
              type: :development
         | 
| 151 119 | 
             
              prerelease: false
         | 
| 152 120 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 153 | 
            -
                none: false
         | 
| 154 121 | 
             
                requirements:
         | 
| 155 122 | 
             
                - - ~>
         | 
| 156 123 | 
             
                  - !ruby/object:Gem::Version
         | 
| 157 | 
            -
                    version: ' | 
| 158 | 
            -
            description:  | 
| 124 | 
            +
                    version: '3.12'
         | 
| 125 | 
            +
            description: |-
         | 
| 126 | 
            +
              RForce is a simple, usable binding to the Salesforce API.
         | 
| 159 127 |  | 
| 160 | 
            -
             | 
| 161 | 
            -
              {<img src="https://travis-ci.org/undees/rforce.png" />}[https://travis-ci.org/undees/rforce]'
         | 
| 128 | 
            +
              {<img src="https://travis-ci.org/undees/rforce.png" />}[https://travis-ci.org/undees/rforce]
         | 
| 162 129 | 
             
            email:
         | 
| 163 130 | 
             
            - undees@gmail.com
         | 
| 164 131 | 
             
            executables: []
         | 
| @@ -166,18 +133,21 @@ extensions: [] | |
| 166 133 | 
             
            extra_rdoc_files:
         | 
| 167 134 | 
             
            - History.txt
         | 
| 168 135 | 
             
            - Manifest.txt
         | 
| 136 | 
            +
            - README.rdoc
         | 
| 169 137 | 
             
            files:
         | 
| 170 138 | 
             
            - History.txt
         | 
| 171 139 | 
             
            - Manifest.txt
         | 
| 172 140 | 
             
            - README.rdoc
         | 
| 173 141 | 
             
            - Rakefile
         | 
| 142 | 
            +
            - examples/oauth_setup.rb
         | 
| 143 | 
            +
            - examples/oauth_use.rb
         | 
| 144 | 
            +
            - examples/simple.rb
         | 
| 174 145 | 
             
            - lib/rforce.rb
         | 
| 175 146 | 
             
            - lib/rforce/binding.rb
         | 
| 176 147 | 
             
            - lib/rforce/method_keys.rb
         | 
| 177 148 | 
             
            - lib/rforce/soap_pullable.rb
         | 
| 178 149 | 
             
            - lib/rforce/soap_response.rb
         | 
| 179 150 | 
             
            - lib/rforce/soap_response_expat.rb
         | 
| 180 | 
            -
            - lib/rforce/soap_response_hpricot.rb
         | 
| 181 151 | 
             
            - lib/rforce/soap_response_nokogiri.rb
         | 
| 182 152 | 
             
            - lib/rforce/soap_response_rexml.rb
         | 
| 183 153 | 
             
            - lib/rforce/version.rb
         | 
| @@ -187,30 +157,30 @@ files: | |
| 187 157 | 
             
            - spec/spec_helper.rb
         | 
| 188 158 | 
             
            - tasks/timing.rake
         | 
| 189 159 | 
             
            - .gemtest
         | 
| 190 | 
            -
            homepage: http://rforce | 
| 191 | 
            -
            licenses: | 
| 160 | 
            +
            homepage: http://github.com/undees/rforce
         | 
| 161 | 
            +
            licenses:
         | 
| 162 | 
            +
            - MIT
         | 
| 163 | 
            +
            metadata: {}
         | 
| 192 164 | 
             
            post_install_message: 
         | 
| 193 165 | 
             
            rdoc_options:
         | 
| 194 166 | 
             
            - --main
         | 
| 195 | 
            -
            - README. | 
| 167 | 
            +
            - README.rdoc
         | 
| 196 168 | 
             
            require_paths:
         | 
| 197 169 | 
             
            - lib
         | 
| 198 170 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 199 | 
            -
              none: false
         | 
| 200 171 | 
             
              requirements:
         | 
| 201 | 
            -
              - -  | 
| 172 | 
            +
              - - '>='
         | 
| 202 173 | 
             
                - !ruby/object:Gem::Version
         | 
| 203 174 | 
             
                  version: '0'
         | 
| 204 175 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 205 | 
            -
              none: false
         | 
| 206 176 | 
             
              requirements:
         | 
| 207 | 
            -
              - -  | 
| 177 | 
            +
              - - '>='
         | 
| 208 178 | 
             
                - !ruby/object:Gem::Version
         | 
| 209 179 | 
             
                  version: '0'
         | 
| 210 180 | 
             
            requirements: []
         | 
| 211 | 
            -
            rubyforge_project:  | 
| 212 | 
            -
            rubygems_version:  | 
| 181 | 
            +
            rubyforge_project: 
         | 
| 182 | 
            +
            rubygems_version: 2.0.14
         | 
| 213 183 | 
             
            signing_key: 
         | 
| 214 | 
            -
            specification_version:  | 
| 184 | 
            +
            specification_version: 4
         | 
| 215 185 | 
             
            summary: RForce is a simple, usable binding to the Salesforce API
         | 
| 216 186 | 
             
            test_files: []
         | 
| @@ -1,90 +0,0 @@ | |
| 1 | 
            -
            require 'hpricot'
         | 
| 2 | 
            -
            require 'cgi'
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            module RForce
         | 
| 6 | 
            -
              class SoapResponseHpricot
         | 
| 7 | 
            -
                # Parses an XML string into structured data.
         | 
| 8 | 
            -
                def initialize(content)
         | 
| 9 | 
            -
                  @content = content
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                # Digests an XML DOM node into nested Ruby types.
         | 
| 13 | 
            -
                def parse
         | 
| 14 | 
            -
                  document = Hpricot.XML(@content)
         | 
| 15 | 
            -
                  node = document % 'soapenv:Body'
         | 
| 16 | 
            -
                  self.class.node_to_ruby node
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                private
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                def self.unescapeXML(string)
         | 
| 22 | 
            -
                  CGI.unescapeHTML(string).gsub("'", "'")
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                def self.node_to_ruby(node)
         | 
| 26 | 
            -
                  # Convert text nodes into simple strings.
         | 
| 27 | 
            -
                  children = (node.children || []).reject do |c|
         | 
| 28 | 
            -
                    c.is_a?(Hpricot::Text) && c.to_s.strip.empty?
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  if node.is_a?(Hpricot::Text)
         | 
| 32 | 
            -
                    return convert(SoapResponseHpricot.unescapeXML(node.inspect[1..-2]))
         | 
| 33 | 
            -
                  end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                  if children.first.is_a?(Hpricot::Text)
         | 
| 36 | 
            -
                    return convert(SoapResponseHpricot.unescapeXML(children.first.inspect[1..-2]))
         | 
| 37 | 
            -
                  end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                  # Convert nodes with children into MethodHashes.
         | 
| 40 | 
            -
                  elements = MethodHash.new
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                  # Add all the element's children to the hash.
         | 
| 43 | 
            -
                  children.each do |e|
         | 
| 44 | 
            -
                    next if e.is_a?(Hpricot::Text) && e.to_s.strip.empty?
         | 
| 45 | 
            -
                    name = e.name
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                    if name.include? ':'
         | 
| 48 | 
            -
                      name = name.split(':').last
         | 
| 49 | 
            -
                    end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                    name = name.to_sym
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                    case elements[name]
         | 
| 54 | 
            -
                      # The most common case: unique child element tags.
         | 
| 55 | 
            -
                    when NilClass then
         | 
| 56 | 
            -
                      # <records> contents are always arrays
         | 
| 57 | 
            -
                      elements[name] = :records == name ? [node_to_ruby(e)] : node_to_ruby(e)
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                      # Non-unique child elements become arrays:
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                      # We've already created the array: just
         | 
| 62 | 
            -
                      # add the element.
         | 
| 63 | 
            -
                    when Array then
         | 
| 64 | 
            -
                      elements[name] << node_to_ruby(e)
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                      # We haven't created the array yet: do so,
         | 
| 67 | 
            -
                      # then put the existing element in, followed
         | 
| 68 | 
            -
                      # by the new one.
         | 
| 69 | 
            -
                    else
         | 
| 70 | 
            -
                      next if :Id == name # avoid duplicate <Id> tags
         | 
| 71 | 
            -
                      elements[name] = [elements[name]]
         | 
| 72 | 
            -
                      elements[name] << node_to_ruby(e)
         | 
| 73 | 
            -
                    end
         | 
| 74 | 
            -
                  end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                  return elements.empty? ? nil : elements
         | 
| 77 | 
            -
                end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                def self.convert(string)
         | 
| 80 | 
            -
                  return nil if string.nil?
         | 
| 81 | 
            -
                  s = string.strip
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                  case s
         | 
| 84 | 
            -
                  when '' then nil
         | 
| 85 | 
            -
                  when 'true', 'false' then ('true' == s)
         | 
| 86 | 
            -
                  else s
         | 
| 87 | 
            -
                  end
         | 
| 88 | 
            -
                end
         | 
| 89 | 
            -
              end
         | 
| 90 | 
            -
            end
         |