atduskgreg-dm-fql-adapter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +15 -0
- data/PostInstall.txt +3 -0
- data/README.rdoc +14 -0
- data/Rakefile +27 -0
- data/example_app.rb +27 -0
- data/lib/dm-fql-adapter.rb +49 -0
- data/lib/dm-fql-adapter/facemask.rb +80 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/dm-fql-adapter_spec.rb +29 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/rspec.rake +21 -0
- metadata +80 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
example_app.rb
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
PostInstall.txt
|
5
|
+
README.rdoc
|
6
|
+
Rakefile
|
7
|
+
lib/dm-fql-adapter.rb
|
8
|
+
lib/dm-fql-adapter/facemask.rb
|
9
|
+
script/console
|
10
|
+
script/destroy
|
11
|
+
script/generate
|
12
|
+
spec/dm-fql-adapter_spec.rb
|
13
|
+
spec/spec.opts
|
14
|
+
spec/spec_helper.rb
|
15
|
+
tasks/rspec.rake
|
data/PostInstall.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
An FQL Adapter for DataMapper. Read-only.
|
2
|
+
|
3
|
+
FQL is the "Facebook Query Language": an API that allows you to send SQL-ish strings along with session information and API credentials to Facebook in order to query for information about users, comments, stream activity and more. See the FQL docs here: http://wiki.developers.facebook.com/index.php/FQL
|
4
|
+
|
5
|
+
For usage, see example_app.rb.
|
6
|
+
|
7
|
+
As of 7/16/09, this only ran on the DataMapper Next branch (i.e. 0.10). For details on how to upgrade to that branch, see here: http://sick.snusnu.info/2009/06/03/migrating-to-datamapper-0100/
|
8
|
+
|
9
|
+
At some point, I will probably factor this into a gem. You know, if people bug me.
|
10
|
+
|
11
|
+
Also, this repo includes Facemask, a more straightforward approach to querying the Facebook API than some of the more complex libs out there.
|
12
|
+
|
13
|
+
-- Greg Borenstein
|
14
|
+
7/16/09 in Portland, OR
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'hoe', '>= 2.1.0'
|
3
|
+
require 'hoe'
|
4
|
+
require 'fileutils'
|
5
|
+
require './lib/dm-fql-adapter'
|
6
|
+
|
7
|
+
Hoe.plugin :newgem
|
8
|
+
# Hoe.plugin :website
|
9
|
+
# Hoe.plugin :cucumberfeatures
|
10
|
+
|
11
|
+
# Generate all the Rake tasks
|
12
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
13
|
+
$hoe = Hoe.spec 'dm-fql-adapter' do
|
14
|
+
self.developer 'Greg Borenstein', 'greg.borenstein@gmail.com'
|
15
|
+
self.version = "0.0.1"
|
16
|
+
self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
17
|
+
self.summary = "FQL Adapter for DataMapper"
|
18
|
+
# self.extra_deps = [['activesupport','>= 2.0.2']]
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'newgem/tasks'
|
23
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
24
|
+
|
25
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
26
|
+
# remove_task :default
|
27
|
+
# task :default => [:spec, :features]
|
data/example_app.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'dm-core'
|
4
|
+
require 'dm-fql-adapter'
|
5
|
+
|
6
|
+
class User
|
7
|
+
include DataMapper::Resource
|
8
|
+
|
9
|
+
# NB: If you don't pick a key DM will act weird
|
10
|
+
property :uid, Integer, :key => true
|
11
|
+
property :name, String
|
12
|
+
property :sex, String
|
13
|
+
property :pic_big, String
|
14
|
+
end
|
15
|
+
|
16
|
+
post "/" do
|
17
|
+
adapter = DataMapper.setup(:default,
|
18
|
+
{:adapter => 'fql',
|
19
|
+
:api_key => "YOUR API KEY",
|
20
|
+
:secret_key => "YOUR SECRET KEY",
|
21
|
+
:session_key => params[:fb_sig_session_key]
|
22
|
+
}
|
23
|
+
)
|
24
|
+
|
25
|
+
user = User.get(546502145)
|
26
|
+
"#{user.name} - #{user.sex} <img src=\"#{user.pic_big}\" />"
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'dm-core'
|
5
|
+
require DataMapper.root / 'lib' / 'dm-core' / 'adapters' / 'abstract_adapter'
|
6
|
+
require DataMapper.root / 'lib' / 'dm-core' / 'adapters' / 'data_objects_adapter'
|
7
|
+
require File.expand_path(File.dirname(__FILE__)) + '/dm-fql-adapter/facemask.rb'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
module DataMapper
|
11
|
+
module Adapters
|
12
|
+
|
13
|
+
class DataObjectsAdapter
|
14
|
+
module SQL
|
15
|
+
def quote_name(name)
|
16
|
+
name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class FqlAdapter < AbstractAdapter
|
22
|
+
|
23
|
+
include DataMapper::Adapters::DataObjectsAdapter::SQL
|
24
|
+
|
25
|
+
def initialize(name, options={})
|
26
|
+
super
|
27
|
+
|
28
|
+
self.resource_naming_convention = DataMapper::NamingConventions::Resource::Underscored
|
29
|
+
|
30
|
+
@facebook = Facemask.new :api_key => options[:api_key],
|
31
|
+
:secret_key => options[:secret_key],
|
32
|
+
:session_key => options[:session_key]
|
33
|
+
end
|
34
|
+
|
35
|
+
def read(query)
|
36
|
+
q = select_statement(query).to_s
|
37
|
+
|
38
|
+
# hack around the mysterious '?'
|
39
|
+
q = q.gsub(/\?(\w*)/){"\"#{$1}\""}
|
40
|
+
|
41
|
+
results = @facebook.find_by_fql(q)
|
42
|
+
results = JSON.parse(results)
|
43
|
+
query.filter_records(results)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end # class FqlAdapter
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'md5'
|
2
|
+
require 'json'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rest_client'
|
5
|
+
|
6
|
+
class Facemask
|
7
|
+
class FaceFail < StandardError; end
|
8
|
+
|
9
|
+
attr_accessor :session_key, :api_key, :secret_key
|
10
|
+
|
11
|
+
def initialize opts={}
|
12
|
+
@api_key = opts[:api_key]
|
13
|
+
@secret_key = opts[:secret_key]
|
14
|
+
@session_key = opts[:session_key]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Execute raw FQL and return the results in JSON
|
18
|
+
def find_by_fql(query)
|
19
|
+
post('facebook.fql.query', :query => query, :format => "json")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sends a templatized feed for the given bundle_id with the given data hash.
|
23
|
+
def publish_user_feed(bundle_id, data)
|
24
|
+
post("facebook.feed.publishUserAction", {:template_bundle_id=> bundle_id,
|
25
|
+
:template_data => data.to_json} )
|
26
|
+
end
|
27
|
+
|
28
|
+
def publish_page_feed(data)
|
29
|
+
data[:title_template] ||= "{actor} Item"
|
30
|
+
post("facebook.feed.publishTemplatizedAction", data)
|
31
|
+
end
|
32
|
+
|
33
|
+
def post(method, params)
|
34
|
+
params.merge! generate_params(method)
|
35
|
+
params.merge! :sig => signature_for(params)
|
36
|
+
Facemask.execute(params)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
def self.execute(params)
|
42
|
+
begin
|
43
|
+
puts "[FBOOK REQUEST] #{params.inspect}"
|
44
|
+
result = RestClient.post("http://api.facebook.com/restserver.php", params)
|
45
|
+
rescue Errno::ECONNRESET, EOFError
|
46
|
+
if attempt == 0
|
47
|
+
attempt += 1
|
48
|
+
puts "Failed once, retrying..."
|
49
|
+
retry
|
50
|
+
end
|
51
|
+
rescue Exception => e
|
52
|
+
raise FaceFail.new(e)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def signature_for(params)
|
57
|
+
raw_string = params.inject([]) do |collection, pair|
|
58
|
+
collection << pair.join("=")
|
59
|
+
collection
|
60
|
+
end.sort.join
|
61
|
+
puts "ABOUT TO HEX"
|
62
|
+
puts raw_string
|
63
|
+
puts self.secret_key
|
64
|
+
Digest::MD5.hexdigest([raw_string, self.secret_key].join)
|
65
|
+
end
|
66
|
+
|
67
|
+
def generate_params(method)
|
68
|
+
result = {}
|
69
|
+
if session_key
|
70
|
+
result[:session_key] = session_key
|
71
|
+
end
|
72
|
+
|
73
|
+
result[:method] = method
|
74
|
+
result[:api_key] = api_key
|
75
|
+
result[:call_id] = Time.now.to_f.to_s
|
76
|
+
result[:v] = "1.0"
|
77
|
+
|
78
|
+
result
|
79
|
+
end
|
80
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/dm-fql-adapter.rb'}"
|
9
|
+
puts "Loading dm-fql-adapter gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'dm-core'
|
4
|
+
require File.expand_path(File.dirname(__FILE__)) + '/../lib/dm-fql-adapter.rb'
|
5
|
+
|
6
|
+
class User
|
7
|
+
include DataMapper::Resource
|
8
|
+
|
9
|
+
property :uid, Integer, :key => true # !important
|
10
|
+
property :name, String
|
11
|
+
property :sex, String
|
12
|
+
property :pic_big, String
|
13
|
+
end
|
14
|
+
|
15
|
+
describe DataMapper::Adapters::FqlAdapter do
|
16
|
+
before :all do
|
17
|
+
Facemask.stub!(:new).and_return(@f = mock('Facemask'))
|
18
|
+
|
19
|
+
@adapter = DataMapper.setup(:default, :adapter => 'fql',
|
20
|
+
:api_key => 'api',
|
21
|
+
:secret_key => 'secret')
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should generate the correct FQL" do
|
25
|
+
@f.should_receive(:find_by_fql).with("SELECT uid, name, sex, pic_big FROM user WHERE uid = \"12345\"").and_return('[{"name":"Cyndy Glucksman","pic_big":"http:\/\/profile.ak.fbcdn.net\/v227\/1454\/108\/n500409376_1710.jpg","sex":"female","uid":500409376}]')
|
26
|
+
User.get(12345)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require 'spec'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
rescue LoadError
|
10
|
+
puts <<-EOS
|
11
|
+
To use rspec for testing you must install rspec gem:
|
12
|
+
gem install rspec
|
13
|
+
EOS
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the specs under spec/models"
|
18
|
+
Spec::Rake::SpecTask.new do |t|
|
19
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
20
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: atduskgreg-dm-fql-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Greg Borenstein
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.3.2
|
24
|
+
version:
|
25
|
+
description: ""
|
26
|
+
email:
|
27
|
+
- greg.borenstein@gmail.com
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- PostInstall.txt
|
36
|
+
files:
|
37
|
+
- example_app.rb
|
38
|
+
- History.txt
|
39
|
+
- Manifest.txt
|
40
|
+
- PostInstall.txt
|
41
|
+
- README.rdoc
|
42
|
+
- Rakefile
|
43
|
+
- lib/dm-fql-adapter.rb
|
44
|
+
- lib/dm-fql-adapter/facemask.rb
|
45
|
+
- script/console
|
46
|
+
- script/destroy
|
47
|
+
- script/generate
|
48
|
+
- spec/dm-fql-adapter_spec.rb
|
49
|
+
- spec/spec.opts
|
50
|
+
- spec/spec_helper.rb
|
51
|
+
- tasks/rspec.rake
|
52
|
+
has_rdoc: true
|
53
|
+
homepage:
|
54
|
+
post_install_message: PostInstall.txt
|
55
|
+
rdoc_options:
|
56
|
+
- --main
|
57
|
+
- README.rdoc
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: dm-fql-adapter
|
75
|
+
rubygems_version: 1.2.0
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: FQL Adapter for DataMapper
|
79
|
+
test_files: []
|
80
|
+
|