atduskgreg-dm-fql-adapter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-07-16
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
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
@@ -0,0 +1,3 @@
1
+ For more information on dm-fql-adapter, see http://github.com/atduskgreg/dm-fql-adapter
2
+
3
+
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
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'dm-fql-adapter'
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
+