baloo 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in baloo.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 John Butler
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Baloo
2
+
3
+ The simple 'bear' necessities for working with graph.facebook.com
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'baloo'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install baloo
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ # configure
23
+ # only required if you're going to do stuff with your app access token later
24
+ Baloo.configure :app_id => '...', :app_secret => '...', app_namespace => '...'
25
+
26
+ #get /me
27
+ Baloo.get 'me', :query => {:access_token => '...'}
28
+ # => {...} # a facebook user hash
29
+
30
+ # post
31
+ Baloo.post 'me/albums', :body => {:access_token => '...', :name => 'Baloo Album'}
32
+ # => {"id": "..."}
33
+
34
+ # app access token / client credentials
35
+ # Baloo#app_token is an alias for Baloo#client_credentials
36
+ Baloo.app_token
37
+ # => "your_app_token"
38
+
39
+ Baloo.client_credentials
40
+ # => "same_thing"
41
+
42
+ Baloo.app_token(app_id, app_secret)
43
+ # => "app token for some other app"
44
+
45
+ # Batch Requests
46
+ batch = Baloo::BatchRequest.new
47
+ 25.times { batch.add :get, 'betapond' }
48
+ batch.perform {|res| puts res['body']['id'] }
49
+ # => 158724218692 (25 times)
50
+ ```
51
+
52
+ ## Contributing
53
+
54
+ 1. Fork it
55
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
56
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
57
+ 4. Push to the branch (`git push origin my-new-feature`)
58
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/baloo.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/baloo/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["John Butler"]
6
+ gem.email = ["johnnypez@gmail.com"]
7
+ gem.description = %q{The simple 'bear' necessities for working with graph.facebook.com}
8
+ gem.summary = %q{A simple Facebook Graph client}
9
+ gem.homepage = ""
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "baloo"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Baloo::VERSION
17
+
18
+ gem.add_dependency "httparty"
19
+ gem.add_dependency "activesupport"
20
+ end
@@ -0,0 +1,41 @@
1
+ require 'yajl'
2
+ module Baloo
3
+ class BatchRequest
4
+
5
+ Limit = 20
6
+
7
+ attr_accessor :requests, :responses
8
+
9
+ def initialize
10
+ @requests = []
11
+ @responses = []
12
+ end
13
+
14
+ def add(method, path, body = {})
15
+ request = { :method => method, :relative_url => path }
16
+ unless body.empty?
17
+ request[:body] = HTTParty::HashConversions.to_params(body)
18
+ end
19
+ @requests << request
20
+ end
21
+
22
+ # peform the batch request
23
+ # the passed block will recieve each response as it is parsed
24
+ def perform(&block)
25
+ raise Exception.new("You must have at least 2 requests") unless @requests.length > 1
26
+ @responses.clear
27
+ requests.each_slice(Limit).to_a.each do |batch|
28
+ body = {
29
+ :batch => Yajl::Encoder.encode(batch),
30
+ :access_token => Baloo.client_credentials
31
+ }
32
+ Client.post("/", :body => body).each do |response|
33
+ # response['headers'] = Yajl::Parser.parse(response['headers'])
34
+ response['body'] = Yajl::Parser.parse(response['body'])
35
+ yield response
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ module Baloo
2
+ class Client
3
+ include HTTParty
4
+
5
+ base_uri "https://graph.facebook.com"
6
+ parser Parser
7
+ format :plain
8
+
9
+ private
10
+ # overrides HTTParty#perform_request to handle exceptions and http errors
11
+ def self.perform_request(http_method, path, options, &block) #:nodoc:
12
+ response = super
13
+ case response.response
14
+ when Net::HTTPSuccess
15
+ response
16
+ when Net::HTTPClientError, Net::HTTPServerError
17
+ raise HTTPError.new(response)
18
+ else
19
+ # unknown http error, raise it
20
+ response.response.error!
21
+ end
22
+
23
+ rescue Net::ProtocolError, Timeout::Error, Errno::ETIMEDOUT, Errno::ECONNRESET
24
+ raise NetworkError.new
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Baloo
2
+ module Convenience
3
+
4
+ # get an app access token
5
+ def client_credentials(id = Baloo.app_id, secret = Baloo.app_secret)
6
+ @stored_client_credentials ||= {}
7
+ unless @stored_client_credentials[id]
8
+ params = {
9
+ :client_id => id,
10
+ :client_secret => secret,
11
+ :grant_type => 'client_credentials'
12
+ }
13
+ @stored_client_credentials[id] = get('oauth/access_token', :query => params).split("=")[1]
14
+ end
15
+
16
+ @stored_client_credentials[id]
17
+ end
18
+ alias :app_token :client_credentials
19
+
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module Baloo
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class HTTPError < Error
7
+ attr_reader :response
8
+ MessageFormat = "%s %s => %s \n %s"
9
+
10
+ def initialize(response)
11
+ @response = response
12
+ super sprintf(MessageFormat, response.request.http_method, response.request.uri, response.response.class, response.body)
13
+ end
14
+ end
15
+
16
+ class NetworkError < Error
17
+ attr_reader :original
18
+
19
+ def initialize(original = $!)
20
+ if original.nil?
21
+ super
22
+ else
23
+ super(original.message)
24
+ end
25
+ @original = original
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,23 @@
1
+ require 'yajl'
2
+ module Baloo
3
+ class Parser < HTTParty::Parser
4
+
5
+ def parse
6
+ if /^true|false$/.match(body)
7
+ bool
8
+ elsif /^\{|\[.+\}|\]$/.match(body)
9
+ json
10
+ else
11
+ body
12
+ end
13
+ end
14
+
15
+ def json
16
+ Yajl::Parser.parse(body)
17
+ end
18
+
19
+ def bool
20
+ body =~ /^true$/ ? true : false
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Baloo
2
+ VERSION = "0.1"
3
+ end
data/lib/baloo.rb ADDED
@@ -0,0 +1,50 @@
1
+ require "active_support/core_ext"
2
+ require "httparty"
3
+
4
+ require "baloo/error"
5
+ require "baloo/parser"
6
+ require "baloo/client"
7
+ require "baloo/version"
8
+ require "baloo/convenience"
9
+ require "baloo/batch_request"
10
+
11
+ module Baloo
12
+
13
+ class << self
14
+
15
+ attr_accessor :app_id
16
+ attr_accessor :app_secret
17
+ attr_accessor :app_namespace
18
+
19
+ include Convenience
20
+
21
+ def configure(options = {})
22
+ options.stringify_keys!
23
+ %w(app_id app_secret app_namespace).each {|opt| send("#{opt}=", options[opt])}
24
+ end
25
+
26
+ %w(get post put delete head).each do |http_method|
27
+ define_method "#{http_method}" do |*args|
28
+ slasherize args
29
+ response = Client.send(http_method, *args)
30
+ if block_given?
31
+ yield response.parsed_response
32
+ else
33
+ response.parsed_response
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # ensure path starts with a forwardslash
41
+ def slasherize(args)
42
+ if args.first && args.first.is_a?(String)
43
+ args[0] = ("/" << args.first) unless args.first =~ /^\//
44
+ end
45
+
46
+ args
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Baloo::BatchRequest do
4
+
5
+ it "should bloody well work!" do
6
+ Baloo.configure :app_id => "204876786306406", :app_secret => "34dc50cea8b8bbdf1dba1018c9aebc90", :app_namespace => "baloo_test"
7
+
8
+ batch = Baloo::BatchRequest.new
9
+ batch.add :get, '582470824'
10
+ batch.add :post, '582470824/albums', :name => "Foo Album"
11
+ 25.times { batch.add :get, 'betapond' }
12
+
13
+ responses = []
14
+ batch.perform do |response|
15
+ responses << response
16
+ response['code'].class.should eq Fixnum
17
+ end
18
+
19
+ responses.count.should eq 27
20
+ responses[0]['body'].class.should eq Hash
21
+ responses[0]['headers'].class.should eq Array
22
+
23
+ responses[0]['body']['username'].should eq 'johnnypez'
24
+ responses[1]['code'].should eq 400 # no access token was give so Bad Request is expected
25
+ responses[3]['code'].should eq 200
26
+ end
27
+
28
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Baloo do
4
+
5
+ it "should allow configuration for a fb app" do
6
+ Baloo.app_id.should be nil
7
+ Baloo.app_secret.should be nil
8
+ Baloo.app_namespace.should be nil
9
+
10
+ Baloo.configure :app_id => 1, :app_secret => 2, :app_namespace => "test"
11
+
12
+ Baloo.app_id.should eq 1
13
+ Baloo.app_secret.should eq 2
14
+ Baloo.app_namespace.should eq "test"
15
+ end
16
+
17
+ it "should allow starting forwardslash or not" do
18
+ res = Baloo.get 'theo2'
19
+ res.class.should eq Hash
20
+ Baloo.get(res['id'])['id'].should eq res['id']
21
+ Baloo.get('/theo2')['id'].should eq res['id']
22
+ end
23
+
24
+ it "should allow t/f in the response" do
25
+ res = Baloo.get 'boylesports'
26
+ res.class.should eq FalseClass
27
+ end
28
+
29
+ it "should handle errors like a boss!" do
30
+ expect { Baloo.get 'me' }.to raise_error Baloo::HTTPError
31
+ end
32
+
33
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Baloo::Convenience do
4
+
5
+ it "should support retrieval of app access tokens" do
6
+ Baloo.configure :app_id => "204876786306406", :app_secret => "34dc50cea8b8bbdf1dba1018c9aebc90", :app_namespace => "baloo_test"
7
+ Baloo.client_credentials.should match(/^204876786306406\|.+/)
8
+ end
9
+
10
+ end
@@ -0,0 +1,13 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+ end
12
+
13
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/baloo")
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: baloo
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - John Butler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-16 00:00:00.000000000 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: httparty
17
+ requirement: &70121616862160 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *70121616862160
26
+ - !ruby/object:Gem::Dependency
27
+ name: activesupport
28
+ requirement: &70121616861140 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *70121616861140
37
+ description: The simple 'bear' necessities for working with graph.facebook.com
38
+ email:
39
+ - johnnypez@gmail.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - .rspec
46
+ - Gemfile
47
+ - LICENSE
48
+ - README.md
49
+ - Rakefile
50
+ - baloo.gemspec
51
+ - lib/baloo.rb
52
+ - lib/baloo/batch_request.rb
53
+ - lib/baloo/client.rb
54
+ - lib/baloo/convenience.rb
55
+ - lib/baloo/error.rb
56
+ - lib/baloo/parser.rb
57
+ - lib/baloo/version.rb
58
+ - spec/batch_request_spec.rb
59
+ - spec/client_spec.rb
60
+ - spec/convenience_spec.rb
61
+ - spec/spec_helper.rb
62
+ has_rdoc: true
63
+ homepage: ''
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.6.2
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: A simple Facebook Graph client
87
+ test_files:
88
+ - spec/batch_request_spec.rb
89
+ - spec/client_spec.rb
90
+ - spec/convenience_spec.rb
91
+ - spec/spec_helper.rb