koala 2.5.0 → 3.0.0.beta1
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 +4 -4
- data/.travis.yml +4 -2
- data/Gemfile +1 -1
- data/changelog.md +26 -0
- data/lib/koala/api/batch_operation.rb +3 -6
- data/lib/koala/api/graph_api.rb +6 -45
- data/lib/koala/api/graph_batch_api.rb +1 -2
- data/lib/koala/api/graph_collection.rb +1 -5
- data/lib/koala/api/graph_error_checker.rb +1 -1
- data/lib/koala/api.rb +3 -7
- data/lib/koala/errors.rb +1 -1
- data/lib/koala/http_service/multipart_request.rb +6 -10
- data/lib/koala/http_service/request.rb +139 -0
- data/lib/koala/http_service/response.rb +0 -4
- data/lib/koala/http_service/uploadable_io.rb +0 -4
- data/lib/koala/http_service.rb +16 -68
- data/lib/koala/oauth.rb +3 -3
- data/lib/koala/version.rb +1 -1
- data/lib/koala.rb +2 -1
- data/readme.md +5 -26
- data/spec/cases/api_spec.rb +1 -7
- data/spec/cases/graph_api_batch_spec.rb +12 -22
- data/spec/cases/graph_api_spec.rb +0 -19
- data/spec/cases/graph_collection_spec.rb +18 -18
- data/spec/cases/graph_error_checker_spec.rb +6 -1
- data/spec/cases/http_service/request_spec.rb +240 -0
- data/spec/cases/http_service_spec.rb +102 -296
- data/spec/cases/koala_spec.rb +6 -1
- data/spec/cases/oauth_spec.rb +1 -1
- data/spec/cases/test_users_spec.rb +4 -1
- data/spec/cases/uploadable_io_spec.rb +31 -31
- data/spec/fixtures/mock_facebook_responses.yml +0 -37
- data/spec/spec_helper.rb +2 -2
- data/spec/support/graph_api_shared_examples.rb +6 -142
- data/spec/support/koala_test.rb +6 -6
- data/spec/support/mock_http_service.rb +6 -6
- data/spec/support/uploadable_io_shared_examples.rb +4 -4
- metadata +7 -7
- data/lib/koala/api/rest_api.rb +0 -135
- data/spec/support/rest_api_shared_examples.rb +0 -168
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 04714e9f9ae4e70420567406530119f6560518d1
         | 
| 4 | 
            +
              data.tar.gz: 92ec819da43149fc5de98f6ec931afc6736c8199
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 51df761c7444da9dfb2c78b1fc30216b6fb3e5463c8e3bda322cae0f01e5e6fde5eecd62fc63f81527d25277972ff8ec00db71ca56aae9322bcfa626484e2470
         | 
| 7 | 
            +
              data.tar.gz: f0545dd4651b30877186dd1f9bf3abe921a73a73f778980434536d4ad7923e17085fa64df53f7f449986d4fe5c460e08e6ceba605ddcc4a70de90c1ed21881c7
         | 
    
        data/.travis.yml
    CHANGED
    
    | @@ -6,12 +6,14 @@ rvm: | |
| 6 6 | 
             
              - 2.0
         | 
| 7 7 | 
             
              - 2.1
         | 
| 8 8 | 
             
              - 2.2
         | 
| 9 | 
            -
              - 2.3. | 
| 9 | 
            +
              - 2.3.1
         | 
| 10 10 | 
             
              # Rubinius is failing due to segfaults on Travis (and takes significantly longer to run)
         | 
| 11 11 | 
             
              # those builds will be restored later
         | 
| 12 12 | 
             
              # jruby
         | 
| 13 | 
            -
              - jruby-19mode
         | 
| 13 | 
            +
              # - jruby-19mode
         | 
| 14 14 | 
             
            bundler_args: --without development
         | 
| 15 15 | 
             
            addons:
         | 
| 16 16 | 
             
              code_climate:
         | 
| 17 17 | 
             
                repo_token: 7af99d9225b4c14640f9ec3cb2e24d2f7103ac49417b0bd989188fb6c25f2909
         | 
| 18 | 
            +
            after_success:
         | 
| 19 | 
            +
                - bundle exec codeclimate-test-reporter
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/changelog.md
    CHANGED
    
    | @@ -1,3 +1,29 @@ | |
| 1 | 
            +
            v3.0.0
         | 
| 2 | 
            +
            ======
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Key breaking changes:
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            * HTTPService.make_request now requires an HTTPService::Request object (Koala.make_request does
         | 
| 7 | 
            +
              not)
         | 
| 8 | 
            +
            * HTTPService behavior *should not* change, but in edge cases might. (If so, please let me know.)
         | 
| 9 | 
            +
            * Empty response bodies in batch API calls will raise a JSON parse error rather than returning nil
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Removed features:
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            * Removed support for the Rest API, since Facebook removed support for it (#568)
         | 
| 14 | 
            +
            * Removed support for FQL, which Facebook removed on August 8, 2016 (#569)
         | 
| 15 | 
            +
            * Removed legacy duplication of serveral constants in the Koala module (#569)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Internal improvements:
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            * Completely rewrote HTTPService.make_request and several others, extracting most logic into
         | 
| 20 | 
            +
              HTTPService::Request (#566)
         | 
| 21 | 
            +
            * Use the more secure JSON.parse instead of JSON.load (thanks, lautis!) (#567)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            Testing improvements:
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            * Fixed a bunch of failing specs
         | 
| 26 | 
            +
             | 
| 1 27 | 
             
            v2.5.0
         | 
| 2 28 | 
             
            ======
         | 
| 3 29 |  | 
| @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'koala/api'
         | 
| 2 | 
            +
            require 'koala/api/graph_batch_api'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Koala
         | 
| 4 5 | 
             
              module Facebook
         | 
| @@ -65,13 +66,13 @@ module Koala | |
| 65 66 | 
             
                    def process_binary_args
         | 
| 66 67 | 
             
                      # collect binary files
         | 
| 67 68 | 
             
                      @args.each_pair do |key, value|
         | 
| 68 | 
            -
                        if UploadableIO.binary_content?(value)
         | 
| 69 | 
            +
                        if HTTPService::UploadableIO.binary_content?(value)
         | 
| 69 70 | 
             
                          @files ||= {}
         | 
| 70 71 | 
             
                          # we use a class-level counter to ensure unique file identifiers across multiple batch operations
         | 
| 71 72 | 
             
                          # (this is thread safe, since we just care about uniqueness)
         | 
| 72 73 | 
             
                          # so remove the file from the original hash and add it to the file store
         | 
| 73 74 | 
             
                          id = "op#{identifier}_file#{@files.keys.length}"
         | 
| 74 | 
            -
                          @files[id] = @args.delete(key).is_a?(UploadableIO) ? value : UploadableIO.new(value)
         | 
| 75 | 
            +
                          @files[id] = @args.delete(key).is_a?(HTTPService::UploadableIO) ? value : HTTPService::UploadableIO.new(value)
         | 
| 75 76 | 
             
                        end
         | 
| 76 77 | 
             
                      end
         | 
| 77 78 | 
             
                    end
         | 
| @@ -81,9 +82,5 @@ module Koala | |
| 81 82 | 
             
                    end
         | 
| 82 83 | 
             
                  end
         | 
| 83 84 | 
             
                end
         | 
| 84 | 
            -
             | 
| 85 | 
            -
                # @private
         | 
| 86 | 
            -
                # legacy support for when BatchOperation lived directly under Koala::Facebook
         | 
| 87 | 
            -
                BatchOperation = GraphBatchAPI::BatchOperation
         | 
| 88 85 | 
             
              end
         | 
| 89 86 | 
             
            end
         | 
    
        data/lib/koala/api/graph_api.rb
    CHANGED
    
    | @@ -359,45 +359,6 @@ module Koala | |
| 359 359 | 
             
                  # except to support cases where the Facebook API requires non-standard input
         | 
| 360 360 | 
             
                  # such as JSON-encoding arguments, posts directly to objects, etc.
         | 
| 361 361 |  | 
| 362 | 
            -
                  # Make an FQL query.
         | 
| 363 | 
            -
                  # Convenience method equivalent to get_object("fql", :q => query).
         | 
| 364 | 
            -
                  #
         | 
| 365 | 
            -
                  # @param query the FQL query to perform
         | 
| 366 | 
            -
                  # @param args (see #get_object)
         | 
| 367 | 
            -
                  # @param options (see #get_object)
         | 
| 368 | 
            -
                  # @param block (see Koala::Facebook::API#api)
         | 
| 369 | 
            -
                  #
         | 
| 370 | 
            -
                  # @return the result of the FQL query.
         | 
| 371 | 
            -
                  def fql_query(query, args = {}, options = {}, &block)
         | 
| 372 | 
            -
                    get_object("fql", args.merge(:q => query), options, &block)
         | 
| 373 | 
            -
                  end
         | 
| 374 | 
            -
             | 
| 375 | 
            -
                  # Make an FQL multiquery.
         | 
| 376 | 
            -
                  # This method simplifies the result returned from multiquery into a more logical format.
         | 
| 377 | 
            -
                  #
         | 
| 378 | 
            -
                  # @param queries a hash of query names => FQL queries
         | 
| 379 | 
            -
                  # @param args (see #get_object)
         | 
| 380 | 
            -
                  # @param options (see #get_object)
         | 
| 381 | 
            -
                  # @param block (see Koala::Facebook::API#api)
         | 
| 382 | 
            -
                  #
         | 
| 383 | 
            -
                  # @example
         | 
| 384 | 
            -
                  #     @api.fql_multiquery({
         | 
| 385 | 
            -
                  #       "query1" => "select post_id from stream where source_id = me()",
         | 
| 386 | 
            -
                  #       "query2" => "select fromid from comment where post_id in (select post_id from #query1)"
         | 
| 387 | 
            -
                  #     })
         | 
| 388 | 
            -
                  #     # returns {"query1" => [obj1, obj2, ...], "query2" => [obj3, ...]}
         | 
| 389 | 
            -
                  #     # instead of [{"name":"query1", "fql_result_set":[]},{"name":"query2", "fql_result_set":[]}]
         | 
| 390 | 
            -
                  #
         | 
| 391 | 
            -
                  # @return a hash of FQL results keyed to the appropriate query
         | 
| 392 | 
            -
                  def fql_multiquery(queries = {}, args = {}, options = {}, &block)
         | 
| 393 | 
            -
                    resolved_results = if results = get_object("fql", args.merge(:q => JSON.dump(queries)), options)
         | 
| 394 | 
            -
                      # simplify the multiquery result format
         | 
| 395 | 
            -
                      results.inject({}) {|outcome, data| outcome[data["name"]] = data["fql_result_set"]; outcome}
         | 
| 396 | 
            -
                    end
         | 
| 397 | 
            -
             | 
| 398 | 
            -
                    block ? block.call(resolved_results) : resolved_results
         | 
| 399 | 
            -
                  end
         | 
| 400 | 
            -
             | 
| 401 362 | 
             
                  # Get a page's access token, allowing you to act as the page.
         | 
| 402 363 | 
             
                  # Convenience method for @api.get_object(page_id, :fields => "access_token").
         | 
| 403 364 | 
             
                  #
         | 
| @@ -463,13 +424,13 @@ module Koala | |
| 463 424 | 
             
                  # Those methods use get_page to request another set of results from Facebook.
         | 
| 464 425 | 
             
                  #
         | 
| 465 426 | 
             
                  # @note You'll rarely need to use this method unless you're using Sinatra or another non-Rails framework
         | 
| 466 | 
            -
                  #       (see {Koala::Facebook::GraphCollection GraphCollection} for more information).
         | 
| 427 | 
            +
                  #       (see {Koala::Facebook::API::GraphCollection GraphCollection} for more information).
         | 
| 467 428 | 
             
                  #
         | 
| 468 429 | 
             
                  # @param params an array of arguments to graph_call
         | 
| 469 | 
            -
                  #               as returned by {Koala::Facebook::GraphCollection.parse_page_url}.
         | 
| 430 | 
            +
                  #               as returned by {Koala::Facebook::API::GraphCollection.parse_page_url}.
         | 
| 470 431 | 
             
                  # @param block (see Koala::Facebook::API#api)
         | 
| 471 432 | 
             
                  #
         | 
| 472 | 
            -
                  # @return Koala::Facebook::GraphCollection the appropriate page of results (an empty array if there are none)
         | 
| 433 | 
            +
                  # @return Koala::Facebook::API::GraphCollection the appropriate page of results (an empty array if there are none)
         | 
| 473 434 | 
             
                  def get_page(params, &block)
         | 
| 474 435 | 
             
                    graph_call(*params, &block)
         | 
| 475 436 | 
             
                  end
         | 
| @@ -529,7 +490,7 @@ module Koala | |
| 529 490 | 
             
                  # @yield response when making a batch API call, you can pass in a block
         | 
| 530 491 | 
             
                  #        that parses the results, allowing for cleaner code.
         | 
| 531 492 | 
             
                  #        The block's return value is returned in the batch results.
         | 
| 532 | 
            -
                  #        See the code for {#get_picture}  | 
| 493 | 
            +
                  #        See the code for {#get_picture} for examples.
         | 
| 533 494 | 
             
                  #        (Not needed in regular calls; you'll probably rarely use this.)
         | 
| 534 495 | 
             
                  #
         | 
| 535 496 | 
             
                  # @raise [Koala::Facebook::APIError] if Facebook returns an error
         | 
| @@ -544,7 +505,7 @@ module Koala | |
| 544 505 | 
             
                    end
         | 
| 545 506 |  | 
| 546 507 | 
             
                    # turn this into a GraphCollection if it's pageable
         | 
| 547 | 
            -
                    result = GraphCollection.evaluate(result, self)
         | 
| 508 | 
            +
                    result = API::GraphCollection.evaluate(result, self)
         | 
| 548 509 |  | 
| 549 510 | 
             
                    # now process as appropriate for the given call (get picture header, etc.)
         | 
| 550 511 | 
             
                    post_processing ? post_processing.call(result) : result
         | 
| @@ -573,7 +534,7 @@ module Koala | |
| 573 534 | 
             
                      fb_expected_arg_name = method == "photos" ? :url : :file_url
         | 
| 574 535 | 
             
                      args.merge!(fb_expected_arg_name => media_args.first)
         | 
| 575 536 | 
             
                    else
         | 
| 576 | 
            -
                      args["source"] = Koala::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
         | 
| 537 | 
            +
                      args["source"] = Koala::HTTPService::UploadableIO.new(*media_args.slice(0, 1 + args_offset))
         | 
| 577 538 | 
             
                    end
         | 
| 578 539 |  | 
| 579 540 | 
             
                    [target_id, method, args, options]
         | 
| @@ -75,7 +75,7 @@ module Koala | |
| 75 75 | 
             
                            raw_result = error
         | 
| 76 76 | 
             
                          else
         | 
| 77 77 | 
             
                            # (see note in regular api method about JSON parsing)
         | 
| 78 | 
            -
                            body = JSON. | 
| 78 | 
            +
                            body = JSON.parse("[#{call_result['body'].to_s}]")[0]
         | 
| 79 79 |  | 
| 80 80 | 
             
                            # Get the HTTP component they want
         | 
| 81 81 | 
             
                            raw_result = case batch_op.http_options[:http_component]
         | 
| @@ -101,7 +101,6 @@ module Koala | |
| 101 101 | 
             
                      end
         | 
| 102 102 | 
             
                    end
         | 
| 103 103 | 
             
                  end
         | 
| 104 | 
            -
             | 
| 105 104 | 
             
                end
         | 
| 106 105 | 
             
              end
         | 
| 107 106 | 
             
            end
         | 
| @@ -23,7 +23,7 @@ module Koala | |
| 23 23 | 
             
                    # @param api the Graph {Koala::Facebook::API API} instance to use to make calls
         | 
| 24 24 | 
             
                    #            (usually the API that made the original call).
         | 
| 25 25 | 
             
                    #
         | 
| 26 | 
            -
                    # @return [Koala::Facebook::GraphCollection] an initialized GraphCollection
         | 
| 26 | 
            +
                    # @return [Koala::Facebook::API::GraphCollection] an initialized GraphCollection
         | 
| 27 27 | 
             
                    #         whose paging, summary, raw_response, and api attributes are populated.
         | 
| 28 28 | 
             
                    def initialize(response, api)
         | 
| 29 29 | 
             
                      super response["data"]
         | 
| @@ -113,9 +113,5 @@ module Koala | |
| 113 113 | 
             
                    end
         | 
| 114 114 | 
             
                  end
         | 
| 115 115 | 
             
                end
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                # @private
         | 
| 118 | 
            -
                # legacy support for when GraphCollection lived directly under Koala::Facebook
         | 
| 119 | 
            -
                GraphCollection = API::GraphCollection
         | 
| 120 116 | 
             
              end
         | 
| 121 117 | 
             
            end
         | 
    
        data/lib/koala/api.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # graph_batch_api and legacy are required at the bottom, since they depend on API being defined
         | 
| 2 2 | 
             
            require 'koala/api/graph_api'
         | 
| 3 | 
            -
            require 'koala/api/ | 
| 3 | 
            +
            require 'koala/api/graph_collection'
         | 
| 4 4 | 
             
            require 'openssl'
         | 
| 5 5 |  | 
| 6 6 | 
             
            module Koala
         | 
| @@ -23,13 +23,11 @@ module Koala | |
| 23 23 | 
             
                  attr_reader :access_token, :app_secret
         | 
| 24 24 |  | 
| 25 25 | 
             
                  include GraphAPIMethods
         | 
| 26 | 
            -
                  include RestAPIMethods
         | 
| 27 26 |  | 
| 28 27 | 
             
                  # Makes a request to the appropriate Facebook API.
         | 
| 29 28 | 
             
                  # @note You'll rarely need to call this method directly.
         | 
| 30 29 | 
             
                  #
         | 
| 31 30 | 
             
                  # @see GraphAPIMethods#graph_call
         | 
| 32 | 
            -
                  # @see RestAPIMethods#rest_call
         | 
| 33 31 | 
             
                  #
         | 
| 34 32 | 
             
                  # @param path the server path for this request (leading / is prepended if not present)
         | 
| 35 33 | 
             
                  # @param args arguments to be sent to Facebook
         | 
| @@ -85,9 +83,9 @@ module Koala | |
| 85 83 | 
             
                    else
         | 
| 86 84 | 
             
                      # parse the body as JSON and run it through the error checker (if provided)
         | 
| 87 85 | 
             
                      # Note: Facebook sometimes sends results like "true" and "false", which are valid[RFC7159]
         | 
| 88 | 
            -
                      # but unsupported by Ruby's stdlib[RFC4627] and cause JSON. | 
| 86 | 
            +
                      # but unsupported by Ruby's stdlib[RFC4627] and cause JSON.parse to fail -- so we account for
         | 
| 89 87 | 
             
                      # that by wrapping the result in []
         | 
| 90 | 
            -
                      JSON. | 
| 88 | 
            +
                      JSON.parse("[#{result.body.to_s}]")[0]
         | 
| 91 89 | 
             
                    end
         | 
| 92 90 | 
             
                  end
         | 
| 93 91 |  | 
| @@ -117,5 +115,3 @@ module Koala | |
| 117 115 | 
             
                end
         | 
| 118 116 | 
             
              end
         | 
| 119 117 | 
             
            end
         | 
| 120 | 
            -
             | 
| 121 | 
            -
            require 'koala/api/graph_batch_api'
         | 
    
        data/lib/koala/errors.rb
    CHANGED
    
    
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            require 'faraday'
         | 
| 2 2 |  | 
| 3 | 
            -
            module Koala | 
| 3 | 
            +
            module Koala
         | 
| 4 4 | 
             
              module HTTPService
         | 
| 5 5 | 
             
                class MultipartRequest < Faraday::Request::Multipart
         | 
| 6 6 | 
             
                  # Facebook expects nested parameters to be passed in a certain way
         | 
| @@ -8,15 +8,15 @@ module Koala | |
| 8 8 | 
             
                  # Faraday needs two changes to make that work:
         | 
| 9 9 | 
             
                  # 1) [] need to be escaped (e.g. params[foo]=bar ==> params%5Bfoo%5D=bar)
         | 
| 10 10 | 
             
                  # 2) such messages need to be multipart-encoded
         | 
| 11 | 
            -
             | 
| 11 | 
            +
             | 
| 12 12 | 
             
                  self.mime_type = 'multipart/form-data'.freeze
         | 
| 13 | 
            -
             | 
| 13 | 
            +
             | 
| 14 14 | 
             
                  def process_request?(env)
         | 
| 15 15 | 
             
                    # if the request values contain any hashes or arrays, multipart it
         | 
| 16 16 | 
             
                    super || !!(env[:body].respond_to?(:values) && env[:body].values.find {|v| v.is_a?(Hash) || v.is_a?(Array)})
         | 
| 17 | 
            -
                  end | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 20 20 | 
             
                  def process_params(params, prefix = nil, pieces = nil, &block)
         | 
| 21 21 | 
             
                    params.inject(pieces || []) do |all, (key, value)|
         | 
| 22 22 | 
             
                      key = "#{prefix}%5B#{key}%5D" if prefix
         | 
| @@ -34,8 +34,4 @@ module Koala | |
| 34 34 | 
             
                  end
         | 
| 35 35 | 
             
                end
         | 
| 36 36 | 
             
              end
         | 
| 37 | 
            -
              
         | 
| 38 | 
            -
              # @private
         | 
| 39 | 
            -
              # legacy support for when MultipartRequest lived directly under Koala
         | 
| 40 | 
            -
              MultipartRequest = HTTPService::MultipartRequest  
         | 
| 41 37 | 
             
            end
         | 
| @@ -0,0 +1,139 @@ | |
| 1 | 
            +
            module Koala
         | 
| 2 | 
            +
              module HTTPService
         | 
| 3 | 
            +
                class Request
         | 
| 4 | 
            +
                  attr_reader :raw_path, :raw_args, :raw_verb, :raw_options
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  # @param path the server path for this request
         | 
| 7 | 
            +
                  # @param args (see Koala::Facebook::API#api)
         | 
| 8 | 
            +
                  # @param verb the HTTP method to use.
         | 
| 9 | 
            +
                  #             If not get or post, this will be turned into a POST request with the appropriate :method
         | 
| 10 | 
            +
                  #             specified in the arguments.
         | 
| 11 | 
            +
                  # @param options various flags to indicate which server to use. (see Koala::Facebook::API#api)
         | 
| 12 | 
            +
                  # @param options
         | 
| 13 | 
            +
                  # @option options :video use the server designated for video uploads
         | 
| 14 | 
            +
                  # @option options :beta use the beta tier
         | 
| 15 | 
            +
                  # @option options :use_ssl force https, even if not needed
         | 
| 16 | 
            +
                  # @option options :json whether or not to send JSON to Facebook
         | 
| 17 | 
            +
                  def initialize(path: nil, args: {}, verb: nil, options: {})
         | 
| 18 | 
            +
                    # we still support Ruby 2.0 so we can't use required keyword arguments
         | 
| 19 | 
            +
                    raise ArgumentError, "Missing required argument verb" unless verb
         | 
| 20 | 
            +
                    raise ArgumentError, "Missing required argument path" unless path
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    @raw_path = path
         | 
| 23 | 
            +
                    @raw_args = args
         | 
| 24 | 
            +
                    @raw_verb = verb
         | 
| 25 | 
            +
                    @raw_options = options
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # Determines which type of request to send to Facebook. Facebook natively accepts GETs and POSTs, for others we have to include the method in the post body.
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  # @return one of get or post
         | 
| 31 | 
            +
                  def verb
         | 
| 32 | 
            +
                    ["get", "post"].include?(raw_verb) ? raw_verb : "post"
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  # Determines the path to be requested on Facebook, incorporating an API version if specified.
         | 
| 36 | 
            +
                  #
         | 
| 37 | 
            +
                  # @return the original path, with API version if appropriate.
         | 
| 38 | 
            +
                  def path
         | 
| 39 | 
            +
                    # if an api_version is specified and the path does not already contain
         | 
| 40 | 
            +
                    # one, prepend it to the path
         | 
| 41 | 
            +
                    api_version = raw_options[:api_version] || Koala.config.api_version
         | 
| 42 | 
            +
                    if api_version && !path_contains_api_version?
         | 
| 43 | 
            +
                      begins_with_slash = raw_path[0] == "/"
         | 
| 44 | 
            +
                      divider = begins_with_slash ? "" : "/"
         | 
| 45 | 
            +
                      "/#{api_version}#{divider}#{raw_path}"
         | 
| 46 | 
            +
                    else
         | 
| 47 | 
            +
                      raw_path
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  # Determines any arguments to be sent in a POST body.
         | 
| 52 | 
            +
                  #
         | 
| 53 | 
            +
                  # @return {} for GET; the provided args for POST; those args with the method parameter for
         | 
| 54 | 
            +
                  # other values
         | 
| 55 | 
            +
                  def post_args
         | 
| 56 | 
            +
                    if raw_verb == "get"
         | 
| 57 | 
            +
                      {}
         | 
| 58 | 
            +
                    elsif raw_verb == "post"
         | 
| 59 | 
            +
                      args
         | 
| 60 | 
            +
                    else
         | 
| 61 | 
            +
                      args.merge(method: raw_verb)
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def get_args
         | 
| 66 | 
            +
                    raw_verb == "get" ? args : {}
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  # Calculates a set of request options to pass to Faraday.
         | 
| 70 | 
            +
                  #
         | 
| 71 | 
            +
                  # @return a hash combining GET parameters (if appropriate), default options, and
         | 
| 72 | 
            +
                  # any specified for the request.
         | 
| 73 | 
            +
                  def options
         | 
| 74 | 
            +
                    # figure out our options for this request
         | 
| 75 | 
            +
                    add_ssl_options(
         | 
| 76 | 
            +
                      # for GETs, we pass the params to Faraday to encode
         | 
| 77 | 
            +
                      {params: get_args}.merge(HTTPService.http_options).merge(raw_options)
         | 
| 78 | 
            +
                    )
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  # Whether or not this request should use JSON.
         | 
| 82 | 
            +
                  #
         | 
| 83 | 
            +
                  # @return true or false
         | 
| 84 | 
            +
                  def json?
         | 
| 85 | 
            +
                    raw_options[:format] == :json
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  # The address of the appropriate Facebook server.
         | 
| 89 | 
            +
                  #
         | 
| 90 | 
            +
                  # @return a complete server address with protocol
         | 
| 91 | 
            +
                  def server
         | 
| 92 | 
            +
                    uri = "#{options[:use_ssl] ? "https" : "http"}://#{Koala.config.graph_server}"
         | 
| 93 | 
            +
                    # if we want to use the beta tier or the video server, make those substitutions as
         | 
| 94 | 
            +
                    # appropriate
         | 
| 95 | 
            +
                    replace_server_component(
         | 
| 96 | 
            +
                      replace_server_component(uri, options[:video], Koala.config.video_replace),
         | 
| 97 | 
            +
                      options[:beta],
         | 
| 98 | 
            +
                      Koala.config.beta_replace
         | 
| 99 | 
            +
                    )
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  protected
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  # The arguments to include in the request.
         | 
| 105 | 
            +
                  def args
         | 
| 106 | 
            +
                    raw_args.inject({}) do |hash, (key, value)|
         | 
| 107 | 
            +
                      # Resolve UploadableIOs into data Facebook can work with
         | 
| 108 | 
            +
                      hash.merge(key => value.is_a?(UploadableIO) ? value.to_upload_io : value)
         | 
| 109 | 
            +
                    end
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  def add_ssl_options(opts)
         | 
| 113 | 
            +
                    # require https if there's a token
         | 
| 114 | 
            +
                    return opts unless raw_args["access_token"]
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    {
         | 
| 117 | 
            +
                      use_ssl: true,
         | 
| 118 | 
            +
                      ssl: {verify: true}.merge(opts[:ssl] || {})
         | 
| 119 | 
            +
                    }.merge(opts)
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  # Determines whether a given path already contains an API version.
         | 
| 123 | 
            +
                  #
         | 
| 124 | 
            +
                  # @param path the URL path.
         | 
| 125 | 
            +
                  #
         | 
| 126 | 
            +
                  # @return true or false accordingly.
         | 
| 127 | 
            +
                  def path_contains_api_version?
         | 
| 128 | 
            +
                    # looks for "/$MAJOR[.$MINOR]/" in the path
         | 
| 129 | 
            +
                    match = /^\/?(v\d+(?:\.\d+)?)\//.match(raw_path)
         | 
| 130 | 
            +
                    !!(match && match[1])
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  def replace_server_component(host, condition_met, replacement)
         | 
| 134 | 
            +
                    return host unless condition_met
         | 
| 135 | 
            +
                    host.gsub(Koala.config.host_path_matcher, replacement)
         | 
| 136 | 
            +
                  end
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
              end
         | 
| 139 | 
            +
            end
         | 
    
        data/lib/koala/http_service.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ require 'faraday' | |
| 2 2 | 
             
            require 'koala/http_service/multipart_request'
         | 
| 3 3 | 
             
            require 'koala/http_service/uploadable_io'
         | 
| 4 4 | 
             
            require 'koala/http_service/response'
         | 
| 5 | 
            +
            require 'koala/http_service/request'
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Koala
         | 
| 7 8 | 
             
              module HTTPService
         | 
| @@ -28,7 +29,6 @@ module Koala | |
| 28 29 | 
             
                DEFAULT_SERVERS = {
         | 
| 29 30 | 
             
                  :graph_server => 'graph.facebook.com',
         | 
| 30 31 | 
             
                  :dialog_host => 'www.facebook.com',
         | 
| 31 | 
            -
                  :rest_server => 'api.facebook.com',
         | 
| 32 32 | 
             
                  # certain Facebook services (beta, video) require you to access different
         | 
| 33 33 | 
             
                  # servers. If you're using your own servers, for instance, for a proxy,
         | 
| 34 34 | 
             
                  # you can change both the matcher and the replacement values.
         | 
| @@ -40,81 +40,36 @@ module Koala | |
| 40 40 | 
             
                  :beta_replace => '.beta.facebook'
         | 
| 41 41 | 
             
                }
         | 
| 42 42 |  | 
| 43 | 
            -
                # The address of the appropriate Facebook server.
         | 
| 44 | 
            -
                #
         | 
| 45 | 
            -
                # @param options various flags to indicate which server to use.
         | 
| 46 | 
            -
                # @option options :rest_api use the old REST API instead of the Graph API
         | 
| 47 | 
            -
                # @option options :video use the server designated for video uploads
         | 
| 48 | 
            -
                # @option options :beta use the beta tier
         | 
| 49 | 
            -
                # @option options :use_ssl force https, even if not needed
         | 
| 50 | 
            -
                #
         | 
| 51 | 
            -
                # @return a complete server address with protocol
         | 
| 52 | 
            -
                def self.server(options = {})
         | 
| 53 | 
            -
                  server = "#{options[:rest_api] ? Koala.config.rest_server : Koala.config.graph_server}"
         | 
| 54 | 
            -
                  server.gsub!(Koala.config.host_path_matcher, Koala.config.video_replace) if options[:video]
         | 
| 55 | 
            -
                  server.gsub!(Koala.config.host_path_matcher, Koala.config.beta_replace) if options[:beta]
         | 
| 56 | 
            -
                  "#{options[:use_ssl] ? "https" : "http"}://#{server}"
         | 
| 57 | 
            -
                end
         | 
| 58 | 
            -
             | 
| 59 43 | 
             
                # Makes a request directly to Facebook.
         | 
| 60 44 | 
             
                # @note You'll rarely need to call this method directly.
         | 
| 61 45 | 
             
                #
         | 
| 62 46 | 
             
                # @see Koala::Facebook::API#api
         | 
| 63 47 | 
             
                # @see Koala::Facebook::GraphAPIMethods#graph_call
         | 
| 64 | 
            -
                # @see Koala::Facebook::RestAPIMethods#rest_call
         | 
| 65 48 | 
             
                #
         | 
| 66 | 
            -
                # @param  | 
| 67 | 
            -
                # @param args (see Koala::Facebook::API#api)
         | 
| 68 | 
            -
                # @param verb the HTTP method to use.
         | 
| 69 | 
            -
                #             If not get or post, this will be turned into a POST request with the appropriate :method
         | 
| 70 | 
            -
                #             specified in the arguments.
         | 
| 71 | 
            -
                # @param options (see Koala::Facebook::API#api)
         | 
| 49 | 
            +
                # @param request a Koala::HTTPService::Request object
         | 
| 72 50 | 
             
                #
         | 
| 73 51 | 
             
                # @raise an appropriate connection error if unable to make the request to Facebook
         | 
| 74 52 | 
             
                #
         | 
| 75 53 | 
             
                # @return [Koala::HTTPService::Response] a response object representing the results from Facebook
         | 
| 76 | 
            -
                def self.make_request( | 
| 77 | 
            -
                  # if the verb isn't get or post, send it as a post argument with a method param
         | 
| 78 | 
            -
                  args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                  # turn all the keys to strings (Faraday has issues with symbols under 1.8.7) and resolve UploadableIOs
         | 
| 81 | 
            -
                  params = args.inject({}) {|hash, kv| hash[kv.first.to_s] = kv.last.is_a?(UploadableIO) ? kv.last.to_upload_io : kv.last; hash}
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                  # figure out our options for this request
         | 
| 84 | 
            -
                  request_options = {:params => (verb == "get" ? params : {})}.merge(http_options || {}).merge(options)
         | 
| 85 | 
            -
                  request_options[:use_ssl] = true if args["access_token"] # require https if there's a token
         | 
| 86 | 
            -
                  if request_options[:use_ssl]
         | 
| 87 | 
            -
                    ssl = (request_options[:ssl] ||= {})
         | 
| 88 | 
            -
                    ssl[:verify] = true unless ssl.has_key?(:verify)
         | 
| 89 | 
            -
                  end
         | 
| 90 | 
            -
             | 
| 91 | 
            -
                  # if an api_version is specified and the path does not already contain
         | 
| 92 | 
            -
                  # one, prepend it to the path
         | 
| 93 | 
            -
                  api_version = request_options[:api_version] || Koala.config.api_version
         | 
| 94 | 
            -
                  if api_version && !path_contains_api_version?(path)
         | 
| 95 | 
            -
                    begins_with_slash = path[0] == "/"
         | 
| 96 | 
            -
                    divider = begins_with_slash ? "" : "/"
         | 
| 97 | 
            -
                    path = "/#{api_version}#{divider}#{path}"
         | 
| 98 | 
            -
                  end
         | 
| 99 | 
            -
             | 
| 54 | 
            +
                def self.make_request(request)
         | 
| 100 55 | 
             
                  # set up our Faraday connection
         | 
| 101 | 
            -
                   | 
| 102 | 
            -
                  conn = Faraday.new(server(request_options), faraday_options(request_options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
         | 
| 56 | 
            +
                  conn = Faraday.new(request.server, faraday_options(request.options), &(faraday_middleware || DEFAULT_MIDDLEWARE))
         | 
| 103 57 |  | 
| 104 | 
            -
                   | 
| 105 | 
            -
             | 
| 58 | 
            +
                  if request.verb == "post" && request.json?
         | 
| 59 | 
            +
                    # JSON requires a bit more handling
         | 
| 60 | 
            +
                    # remember, all non-GET requests are turned into POSTs, so this covers everything but GETs
         | 
| 106 61 | 
             
                    response = conn.post do |req|
         | 
| 107 | 
            -
                      req.path = path
         | 
| 62 | 
            +
                      req.path = request.path
         | 
| 108 63 | 
             
                      req.headers["Content-Type"] = "application/json"
         | 
| 109 | 
            -
                      req.body =  | 
| 64 | 
            +
                      req.body = request.post_args.to_json
         | 
| 110 65 | 
             
                      req
         | 
| 111 66 | 
             
                    end
         | 
| 112 67 | 
             
                  else
         | 
| 113 | 
            -
                    response = conn.send(verb, path,  | 
| 68 | 
            +
                    response = conn.send(request.verb, request.path, request.post_args)
         | 
| 114 69 | 
             
                  end
         | 
| 115 70 |  | 
| 116 71 | 
             
                  # Log URL information
         | 
| 117 | 
            -
                  Koala::Utils.debug "#{verb.upcase}: #{path} params: #{ | 
| 72 | 
            +
                  Koala::Utils.debug "#{request.verb.upcase}: #{request.path} params: #{request.raw_args.inspect}"
         | 
| 118 73 | 
             
                  Koala::HTTPService::Response.new(response.status.to_i, response.body, response.headers)
         | 
| 119 74 | 
             
                end
         | 
| 120 75 |  | 
| @@ -130,21 +85,14 @@ module Koala | |
| 130 85 | 
             
                # @return the appropriately-encoded string
         | 
| 131 86 | 
             
                def self.encode_params(param_hash)
         | 
| 132 87 | 
             
                  ((param_hash || {}).sort_by{|k, v| k.to_s}.collect do |key_and_value|
         | 
| 133 | 
            -
                     | 
| 134 | 
            -
                     | 
| 88 | 
            +
                    value = key_and_value[1]
         | 
| 89 | 
            +
                    unless value.is_a? String
         | 
| 90 | 
            +
                      value = value.to_json
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                    "#{key_and_value[0].to_s}=#{CGI.escape value}"
         | 
| 135 93 | 
             
                  end).join("&")
         | 
| 136 94 | 
             
                end
         | 
| 137 95 |  | 
| 138 | 
            -
                # Determines whether a given path already contains an API version.
         | 
| 139 | 
            -
                #
         | 
| 140 | 
            -
                # @param path the URL path.
         | 
| 141 | 
            -
                #
         | 
| 142 | 
            -
                # @return true or false accordingly.
         | 
| 143 | 
            -
                def self.path_contains_api_version?(path)
         | 
| 144 | 
            -
                  match = /^\/?(v\d+(?:\.\d+)?)\//.match(path)
         | 
| 145 | 
            -
                  !!(match && match[1])
         | 
| 146 | 
            -
                end
         | 
| 147 | 
            -
             | 
| 148 96 | 
             
                private
         | 
| 149 97 |  | 
| 150 98 | 
             
                def self.faraday_options(options)
         | 
    
        data/lib/koala/oauth.rb
    CHANGED
    
    | @@ -134,7 +134,7 @@ module Koala | |
| 134 134 | 
             
                    if response == ''
         | 
| 135 135 | 
             
                      raise BadFacebookResponse.new(200, '', 'generate_client_code received an error: empty response body')
         | 
| 136 136 | 
             
                    else
         | 
| 137 | 
            -
                      result = JSON. | 
| 137 | 
            +
                      result = JSON.parse(response)
         | 
| 138 138 | 
             
                    end
         | 
| 139 139 |  | 
| 140 140 | 
             
                    result.has_key?('code') ? result['code'] : raise(Koala::KoalaError.new("Facebook returned a valid response without the expected 'code' in the body (response = #{response})"))
         | 
| @@ -240,7 +240,7 @@ module Koala | |
| 240 240 | 
             
                    raise OAuthSignatureError, 'Invalid (incomplete) signature data' unless encoded_sig && encoded_envelope
         | 
| 241 241 |  | 
| 242 242 | 
             
                    signature = base64_url_decode(encoded_sig).unpack("H*").first
         | 
| 243 | 
            -
                    envelope = JSON. | 
| 243 | 
            +
                    envelope = JSON.parse(base64_url_decode(encoded_envelope))
         | 
| 244 244 |  | 
| 245 245 | 
             
                    raise OAuthSignatureError, "Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'
         | 
| 246 246 |  | 
| @@ -260,7 +260,7 @@ module Koala | |
| 260 260 | 
             
                  end
         | 
| 261 261 |  | 
| 262 262 | 
             
                  def parse_access_token(response_text)
         | 
| 263 | 
            -
                    JSON. | 
| 263 | 
            +
                    JSON.parse(response_text)
         | 
| 264 264 | 
             
                  rescue JSON::ParserError
         | 
| 265 265 | 
             
                    response_text.split("&").inject({}) do |hash, bit|
         | 
| 266 266 | 
             
                      key, value = bit.split("=")
         | 
    
        data/lib/koala/version.rb
    CHANGED
    
    
    
        data/lib/koala.rb
    CHANGED
    
    | @@ -5,6 +5,7 @@ require 'json' | |
| 5 5 | 
             
            # include koala modules
         | 
| 6 6 | 
             
            require 'koala/errors'
         | 
| 7 7 | 
             
            require 'koala/api'
         | 
| 8 | 
            +
            require 'koala/api/graph_batch_api'
         | 
| 8 9 | 
             
            require 'koala/oauth'
         | 
| 9 10 | 
             
            require 'koala/realtime_updates'
         | 
| 10 11 | 
             
            require 'koala/test_users'
         | 
| @@ -61,7 +62,7 @@ module Koala | |
| 61 62 |  | 
| 62 63 | 
             
              # An convenenient alias to Koala.http_service.make_request.
         | 
| 63 64 | 
             
              def self.make_request(path, args, verb, options = {})
         | 
| 64 | 
            -
                http_service.make_request(path, args, verb, options)
         | 
| 65 | 
            +
                http_service.make_request(HTTPService::Request.new(path: path, args: args, verb: verb, options: options))
         | 
| 65 66 | 
             
              end
         | 
| 66 67 |  | 
| 67 68 | 
             
              # we use Faraday as our main service, with mock as the other main one
         |