ruby-rapleafbg 0.2.3f
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 +45 -0
- data/Manifest.txt +10 -0
- data/README.txt +140 -0
- data/Rakefile +28 -0
- data/examples/person.rb +65 -0
- data/lib/rapleaf/exceptions.rb +61 -0
- data/lib/rapleaf/rapleaf.rb +153 -0
- data/lib/rapleaf/responses.rb +142 -0
- data/lib/ruby-rapleaf.rb +26 -0
- data/ruby-rapleaf.gemspec +38 -0
- metadata +132 -0
data/History.txt
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
=== 0.2.3 / 2010/11/17
|
2
|
+
|
3
|
+
* Updated for v4 methods.
|
4
|
+
|
5
|
+
=== 0.2.2 / 2010/10/18
|
6
|
+
|
7
|
+
* Allow specifying the read_timeout to pass through to Net::HTTP.
|
8
|
+
There are a few reasons why you might want to do this. One is that
|
9
|
+
Net::HTTP's read_timeout is implemented using timeout.rb, which is known
|
10
|
+
to have race conditions, and in particular is unsafe to use in
|
11
|
+
EventMachine (because it can sometimes throw exceptions in the main
|
12
|
+
event loop and kill the whole process); so this lets you disable the
|
13
|
+
timeout entirely.
|
14
|
+
|
15
|
+
* Ruby 1.9 compatibility tweak (thanks to Justin Ip)
|
16
|
+
|
17
|
+
=== 0.2.1 / 2010/04/27
|
18
|
+
|
19
|
+
* If unexpected response code, exception should include diagnostic info
|
20
|
+
|
21
|
+
=== 0.2.0 / 2010/04/24
|
22
|
+
|
23
|
+
* Support Person API lookup by site profile (e.g. Twitter username) for API v3.
|
24
|
+
|
25
|
+
=== 0.1.7 / 2010-04-14
|
26
|
+
|
27
|
+
* URLencode email addresses before sending them to Rapleaf.
|
28
|
+
|
29
|
+
* Remove workaround for mistakenly diagnosed problem (thought Rapleaf rejected emails containing '+', they just required encoding).
|
30
|
+
|
31
|
+
* Use existing PersonEmailHashNotFound exception for 404 when looking up by hash
|
32
|
+
|
33
|
+
* removed NotFound class added in 0.1.6
|
34
|
+
|
35
|
+
=== 0.1.6 / 2010-03-04
|
36
|
+
|
37
|
+
* Modified by Sam Stokes
|
38
|
+
|
39
|
+
* Support for Rapleaf Person API v3 (which is now the default)
|
40
|
+
|
41
|
+
* Work around Rapleaf bug: they think email addresses containing '+' are malformed, so for those we send them hashes instead.
|
42
|
+
|
43
|
+
=== 0.1.5 / 2008-08-28
|
44
|
+
|
45
|
+
* Original version by Glenn Rempe, with support for Rapleaf Person API v2
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
= ruby-rapleaf
|
2
|
+
|
3
|
+
* http://github.com/rapportive-oss/ruby-rapleaf
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Rapleaf's goal is to make the internet safe and transparent, by allowing you
|
8
|
+
to evaluate your web footprint across a variety of user-generated sites.
|
9
|
+
See http://www.rapleaf.com for more information.
|
10
|
+
|
11
|
+
== FEATURES/PROBLEMS:
|
12
|
+
|
13
|
+
This library was inspired by the sample code provided by Rapleaf at:
|
14
|
+
|
15
|
+
http://trac.rapleaf.com/ruby-api-kit/wiki
|
16
|
+
|
17
|
+
The code was extensively re-written by Glenn Rempe so it would work with the
|
18
|
+
then-current Rapleaf v2 API, and further modified by Sam Stokes to support the
|
19
|
+
v3 API.
|
20
|
+
|
21
|
+
Please direct any questions, patches, pull requests or bug reports to
|
22
|
+
Sam Stokes <sam@rapportive.com>.
|
23
|
+
|
24
|
+
This project is not affiliated with, or endorsed or supported by, Rapleaf.
|
25
|
+
|
26
|
+
=== Original (v2 API compatible)
|
27
|
+
|
28
|
+
http://github.com/grempe/ruby-rapleaf
|
29
|
+
|
30
|
+
Glenn Rempe
|
31
|
+
glenn@rempe.us
|
32
|
+
|
33
|
+
=== Updated (v3 API compatible)
|
34
|
+
|
35
|
+
http://github.com/rapportive-oss/ruby-rapleaf
|
36
|
+
|
37
|
+
Sam Stokes
|
38
|
+
sam@rapportive.com
|
39
|
+
|
40
|
+
== SYNOPSIS:
|
41
|
+
|
42
|
+
In order to use this API, you will need to get an API Key from Rapleaf. These
|
43
|
+
can be obtained free at http://www.rapleaf.com/.
|
44
|
+
|
45
|
+
To run the samples you will need to put your API Key in the
|
46
|
+
examples/person.rb file or the examples will fail.
|
47
|
+
|
48
|
+
To run any of the examples, simply run it like:
|
49
|
+
|
50
|
+
cd examples
|
51
|
+
ruby person.rb
|
52
|
+
|
53
|
+
(There are some known problems running the examples at the moment... sorry!)
|
54
|
+
|
55
|
+
== REQUIREMENTS:
|
56
|
+
|
57
|
+
The following gems are required for installation of the ruby-rapleaf gem.
|
58
|
+
|
59
|
+
* xml-simple
|
60
|
+
* builder
|
61
|
+
|
62
|
+
== INSTALL:
|
63
|
+
|
64
|
+
gem install ruby-rapleaf
|
65
|
+
|
66
|
+
You can build the gem yourself and install as a Ruby Gem with:
|
67
|
+
|
68
|
+
git clone git://github.com/rapportive-oss/ruby-rapleaf.git
|
69
|
+
cd ruby-rapleaf
|
70
|
+
gem build ruby-rapleaf.gemspec
|
71
|
+
gem install ruby-rapleaf-*.gem
|
72
|
+
|
73
|
+
== LICENSE:
|
74
|
+
|
75
|
+
This software is distributed under the Ruby License. A copy of which is
|
76
|
+
provided below.
|
77
|
+
|
78
|
+
RUBY LICENSE
|
79
|
+
|
80
|
+
Copyright (c) 2008-2010 Glenn Rempe, 2010 Sam Stokes, Justin Ip
|
81
|
+
|
82
|
+
http://www.ruby-lang.org/en/LICENSE.txt
|
83
|
+
|
84
|
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.co.jp>.
|
85
|
+
You can redistribute it and/or modify it under either the terms of the GPL
|
86
|
+
(see COPYING.txt file), or the conditions below:
|
87
|
+
|
88
|
+
1. You may make and give away verbatim copies of the source form of the
|
89
|
+
software without restriction, provided that you duplicate all of the
|
90
|
+
original copyright notices and associated disclaimers.
|
91
|
+
|
92
|
+
2. You may modify your copy of the software in any way, provided that
|
93
|
+
you do at least ONE of the following:
|
94
|
+
|
95
|
+
a) place your modifications in the Public Domain or otherwise
|
96
|
+
make them Freely Available, such as by posting said
|
97
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
98
|
+
the author to include your modifications in the software.
|
99
|
+
|
100
|
+
b) use the modified software only within your corporation or
|
101
|
+
organization.
|
102
|
+
|
103
|
+
c) rename any non-standard executables so the names do not conflict
|
104
|
+
with standard executables, which must also be provided.
|
105
|
+
|
106
|
+
d) make other distribution arrangements with the author.
|
107
|
+
|
108
|
+
3. You may distribute the software in object code or executable
|
109
|
+
form, provided that you do at least ONE of the following:
|
110
|
+
|
111
|
+
a) distribute the executables and library files of the software,
|
112
|
+
together with instructions (in the manual page or equivalent)
|
113
|
+
on where to get the original distribution.
|
114
|
+
|
115
|
+
b) accompany the distribution with the machine-readable source of
|
116
|
+
the software.
|
117
|
+
|
118
|
+
c) give non-standard executables non-standard names, with
|
119
|
+
instructions on where to get the original software distribution.
|
120
|
+
|
121
|
+
d) make other distribution arrangements with the author.
|
122
|
+
|
123
|
+
4. You may modify and include the part of the software into any other
|
124
|
+
software (possibly commercial). But some files in the distribution
|
125
|
+
are not written by the author, so that they are not under this terms.
|
126
|
+
|
127
|
+
They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
|
128
|
+
files under the ./missing directory. See each file for the copying
|
129
|
+
condition.
|
130
|
+
|
131
|
+
5. The scripts and library files supplied as input to or produced as
|
132
|
+
output from the software do not automatically fall under the
|
133
|
+
copyright of the software, but belong to whomever generated them,
|
134
|
+
and may be sold commercially, and may be aggregated with this
|
135
|
+
software.
|
136
|
+
|
137
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
138
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
139
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
140
|
+
PURPOSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/ruby-rapleaf.rb'
|
6
|
+
|
7
|
+
Hoe.new('ruby-rapleaf', Rapleaf::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'ruby-rapleaf' # if different than lowercase project name
|
9
|
+
p.developer('Glenn Rempe', 'glenn@rempe.us')
|
10
|
+
p.extra_deps = [['xml-simple', '>= 1.0.11'], ['builder', '>= 2.1.2']]
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :manifest do
|
14
|
+
desc 'Recreate Manifest.txt to include ALL files'
|
15
|
+
task :refresh do
|
16
|
+
`rake check_manifest | patch -p0 > Manifest.txt`
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :gemspec do
|
21
|
+
desc 'Refresh the gemspec file'
|
22
|
+
task :refresh do
|
23
|
+
`rake debug_gem > ruby-rapleaf.gemspec`
|
24
|
+
# remove the first line from the file which is an artifact of the gemspec generation
|
25
|
+
`perl -pi -e '$_ = "" if ($. == 1);' ruby-rapleaf.gemspec`
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/examples/person.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/ruby-rapleaf'
|
3
|
+
|
4
|
+
# Instanciate a Rapleaf object with your API Key.
|
5
|
+
@rapleaf = Rapleaf::Base.new('REPLACE_WITH_YOUR_API_KEY')
|
6
|
+
|
7
|
+
@person = @rapleaf.person(:email => 'dummy@rapleaf.com')
|
8
|
+
|
9
|
+
puts "\n\n"
|
10
|
+
puts "BASICS"
|
11
|
+
|
12
|
+
puts "\n@person.basics.name:"
|
13
|
+
puts @person.basics.name
|
14
|
+
|
15
|
+
puts "\n@person.basics.age:"
|
16
|
+
puts @person.basics.age
|
17
|
+
|
18
|
+
puts "\n@person.basics.gender:"
|
19
|
+
puts @person.basics.gender
|
20
|
+
|
21
|
+
puts "\n@person.basics.location:"
|
22
|
+
puts @person.basics.location
|
23
|
+
|
24
|
+
puts "\n@person.basics.occupations:"
|
25
|
+
if @person.basics.occupations
|
26
|
+
@person.basics.occupations.each do |occupation|
|
27
|
+
puts "occupation.job_title"
|
28
|
+
puts occupation.job_title
|
29
|
+
puts "occupation.company"
|
30
|
+
puts occupation.company
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
puts "\n@person.basics.universities:"
|
35
|
+
if @person.basics.universities
|
36
|
+
@person.basics.universities.each do |university|
|
37
|
+
puts "university:"
|
38
|
+
puts university
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "\n@person.basics.earliest_known_activity:"
|
43
|
+
puts @person.basics.earliest_known_activity
|
44
|
+
|
45
|
+
puts "\n@person.basics.latest_known_activity:"
|
46
|
+
puts @person.basics.latest_known_activity
|
47
|
+
|
48
|
+
puts "\n@person.basics.num_friends:"
|
49
|
+
puts @person.basics.num_friends
|
50
|
+
|
51
|
+
puts "\nMEMBERSHIPS"
|
52
|
+
|
53
|
+
puts "\n@person.memberships.inspect"
|
54
|
+
puts @person.memberships.inspect
|
55
|
+
|
56
|
+
puts "\n@person.memberships.primary.inspect"
|
57
|
+
puts @person.memberships.primary.inspect
|
58
|
+
|
59
|
+
puts "\n@person.memberships.primary.membership[0].site"
|
60
|
+
puts @person.memberships.primary.membership[0].site
|
61
|
+
|
62
|
+
# Look up a profile by hashed email address.
|
63
|
+
puts "\nLookup by hashed email:"
|
64
|
+
@person = @rapleaf.person(:email => '1147e414eec8b785fb760f13f7890a767ffaef6e')
|
65
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Rapleaf
|
2
|
+
|
3
|
+
# CLIENT SIDE ERRORS
|
4
|
+
|
5
|
+
# All of our errors are superclassed by Error < RuntimeError
|
6
|
+
class Error < RuntimeError #:nodoc:
|
7
|
+
end
|
8
|
+
|
9
|
+
# A client side only argument error
|
10
|
+
class ArgumentError < Error #:nodoc:
|
11
|
+
end
|
12
|
+
|
13
|
+
# SERVER SIDE ERRORS
|
14
|
+
|
15
|
+
# GENERAL API
|
16
|
+
# =============================================
|
17
|
+
|
18
|
+
# 401 Unauthorized
|
19
|
+
# API key was not provided or is invalid.
|
20
|
+
class AuthFailure < Error #:nodoc:
|
21
|
+
end
|
22
|
+
|
23
|
+
# 403 Forbidden
|
24
|
+
# Your query limit has been exceeded.
|
25
|
+
class ForbiddenQueryLimitExceeded < Error #:nodoc:
|
26
|
+
end
|
27
|
+
|
28
|
+
# 500 Internal Server Error
|
29
|
+
# There was an unexpected error on our server. This should be very
|
30
|
+
# rare and if you see it please contact developer@rapleaf.com.
|
31
|
+
class InternalServerError < Error #:nodoc:
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# PERSON API
|
36
|
+
# =============================================
|
37
|
+
|
38
|
+
# 202 Accepted
|
39
|
+
# This person is currently being searched. Check back shortly and we should have data.
|
40
|
+
class PersonAccepted < Error #:nodoc:
|
41
|
+
end
|
42
|
+
|
43
|
+
# 400 Bad Request
|
44
|
+
# Invalid email address.
|
45
|
+
class PersonBadRequestInvalidEmail < Error #:nodoc:
|
46
|
+
end
|
47
|
+
|
48
|
+
# 404 Not Found
|
49
|
+
# Only returned for lookup by hash. We do not have this email in our
|
50
|
+
# system and are not able to create a person using a hash. If you would
|
51
|
+
# like better results, consider supplying the unhashed email address.
|
52
|
+
class PersonEmailHashNotFound < Error #:nodoc:
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# ABOOK API
|
57
|
+
# =============================================
|
58
|
+
|
59
|
+
# TODO
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Rapleaf
|
5
|
+
class Base
|
6
|
+
|
7
|
+
def initialize(api_key, options = {})
|
8
|
+
#personalize.rlcdn.com
|
9
|
+
options = {
|
10
|
+
:api_host => API_HOST,
|
11
|
+
:api_host_v4 => API_HOST_V4,
|
12
|
+
:api_port => API_PORT,
|
13
|
+
:api_version => API_VERSION,
|
14
|
+
:api_read_timeout => 30,
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
@api_key = api_key
|
18
|
+
@host = options[:api_host]
|
19
|
+
@host_v4 = options[:api_host_v4]
|
20
|
+
@port = options[:api_port]
|
21
|
+
@version = options[:api_version]
|
22
|
+
@read_timeout = options[:api_read_timeout]
|
23
|
+
end
|
24
|
+
|
25
|
+
# This resource is used to retrieve information about a person, identified
|
26
|
+
# using an email address or email address hash.
|
27
|
+
# Examples:
|
28
|
+
# person(:email => 'dummy@rapleaf.com')
|
29
|
+
# person(:site => :twitter, :profile => 'samstokes')
|
30
|
+
# person(:sha1 => Digest::SHA1.hexdigest('dummy@rapleaf.com'))
|
31
|
+
# person(:md5 => Digest::MD5.hexdigest('dummy@rapleaf.com'))
|
32
|
+
def person( opts = {} )
|
33
|
+
resp = fetch_response(URI.parse(person_url(opts)))
|
34
|
+
|
35
|
+
case resp.code
|
36
|
+
when '200'
|
37
|
+
#return Response.parse(:xml => resp.body)
|
38
|
+
return ActiveSupport::JSON.decode(resp.body)
|
39
|
+
when '202'
|
40
|
+
raise PersonAccepted, 'This person is currently being searched. Check back shortly and we should have data.'
|
41
|
+
when '400'
|
42
|
+
raise PersonBadRequestInvalidEmail, 'Invalid email address.'
|
43
|
+
when '401'
|
44
|
+
raise AuthFailure, 'API key was not provided or is invalid.'
|
45
|
+
when '403'
|
46
|
+
raise ForbiddenQueryLimitExceeded, 'Your query limit has been exceeded. Contact developer@rapleaf.com if you would like to increase your limit.'
|
47
|
+
when '404'
|
48
|
+
raise PersonEmailHashNotFound, 'We do not have this email in our system and are not able to create a person using a hash. If you would like better results, consider supplying the unhashed email address.'
|
49
|
+
when '500'
|
50
|
+
raise InternalServerError, 'There was an unexpected error on our server. This should be very rare and if you see it please contact developer@rapleaf.com.'
|
51
|
+
else
|
52
|
+
msg = resp.body[0,50]
|
53
|
+
msg << "..." if 50 < resp.body.length
|
54
|
+
raise Error, %(Unexpected response code #{resp.code}: "#{msg}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def fetch_response(uri)
|
60
|
+
# Have to do this a verbose way in order to override Net::HTTP's
|
61
|
+
# default read_timeout
|
62
|
+
|
63
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
64
|
+
if uri.scheme == 'https'
|
65
|
+
http.use_ssl = true
|
66
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
67
|
+
end
|
68
|
+
http.read_timeout = @read_timeout
|
69
|
+
|
70
|
+
http.start { http.get(uri.path + '?' + uri.query) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def person_url(opts)
|
74
|
+
email = opts[:email]
|
75
|
+
|
76
|
+
site_profile = [opts[:site], opts[:profile]]
|
77
|
+
if site_profile.any?
|
78
|
+
raise ArgumentError, 'Require both :site and :profile if either is specified' unless site_profile.all?
|
79
|
+
else
|
80
|
+
site_profile = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
md5 = opts[:md5]
|
84
|
+
sha1 = opts[:sha1]
|
85
|
+
|
86
|
+
# Rapleaf requires email addresses be urlencoded
|
87
|
+
# Pass our own "unsafe regex" as URI.escape's default is too permissive
|
88
|
+
# (lets + through, but Rapleaf rejects it)
|
89
|
+
email = URI.escape(email, /[^a-zA-Z0-9.\-_]/) if email
|
90
|
+
|
91
|
+
selector = [email, site_profile, md5, sha1].compact
|
92
|
+
raise ArgumentError, 'Please provide only one of :email, [:site and :profile], :md5 or :sha1' if selector.size > 1
|
93
|
+
raise ArgumentError, 'Person selector must be provided' if selector.empty? || '' == selector[0]
|
94
|
+
|
95
|
+
case @version
|
96
|
+
when "v2"
|
97
|
+
if site_profile
|
98
|
+
raise ArgumentError, 'Query by website ID requires API v3 or greater'
|
99
|
+
end
|
100
|
+
person_url_v2_by_email_or_hash(email_or_hash[0])
|
101
|
+
when "v3"
|
102
|
+
if email
|
103
|
+
person_url_v3_by_email(email)
|
104
|
+
elsif site_profile
|
105
|
+
person_url_v3_by_site_profile(*site_profile)
|
106
|
+
elsif md5
|
107
|
+
person_url_v3_by_hash(:md5, md5)
|
108
|
+
else
|
109
|
+
person_url_v3_by_hash(:sha1, sha1)
|
110
|
+
end
|
111
|
+
when "v4"
|
112
|
+
if email
|
113
|
+
person_url_v4_by_email(email)
|
114
|
+
elsif site_profile
|
115
|
+
person_url_v4_by_site_profile(*site_profile)
|
116
|
+
elsif md5
|
117
|
+
person_url_v4_by_hash(:md5, md5)
|
118
|
+
else
|
119
|
+
person_url_v4_by_hash(:sha1, sha1)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
raise ArgumentError, "Person queries not supported for API version #{@version}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def person_url_v2_by_email_or_hash(email_or_hash)
|
127
|
+
"http://#{@host}:#{@port}/v2/person/#{email_or_hash}?api_key=#{@api_key}"
|
128
|
+
end
|
129
|
+
|
130
|
+
def person_url_v3_by_email(email)
|
131
|
+
"http://#{@host}:#{@port}/v3/person/email/#{email}?api_key=#{@api_key}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def person_url_v4_by_email(email)
|
135
|
+
"https://#{@host_v4}/v4/dr?email=#{email}&api_key=#{@api_key}"
|
136
|
+
end
|
137
|
+
|
138
|
+
def person_url_v3_by_site_profile(site, profile)
|
139
|
+
# TODO validate param formats
|
140
|
+
"http://#{@host}:#{@port}/v3/person/web/#{site}/#{profile}?api_key=#{@api_key}"
|
141
|
+
end
|
142
|
+
|
143
|
+
def person_url_v3_by_hash(algo, hash)
|
144
|
+
"http://#{@host}:#{@port}/v3/person/hash/#{algo}/#{hash}?api_key=#{@api_key}"
|
145
|
+
end
|
146
|
+
|
147
|
+
def person_url_v4_by_hash(algo, hash)
|
148
|
+
"https://#{@host_v4}/v4/dr?#{algo}=#{hash}&api_key=#{@api_key}"
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Rapleaf
|
2
|
+
|
3
|
+
# Credits :
|
4
|
+
# I learned the magic of making an OpenStruct object able to respond as a fully Enumerable
|
5
|
+
# object (responds to .each, etc.) thanks to a great blog article on Struct and OpenStruct
|
6
|
+
# at http://errtheblog.com/post/30
|
7
|
+
#
|
8
|
+
# Thanks to Sean Knapp for the XmlSimple response patch which greatly simplified the response
|
9
|
+
# mechanism for the whole library while making it more accurate and much less brittle to boot!
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
begin
|
14
|
+
require 'xmlsimple' unless defined? XmlSimple
|
15
|
+
rescue Exception => e
|
16
|
+
require 'xml-simple' unless defined? XmlSimple
|
17
|
+
end
|
18
|
+
|
19
|
+
class Response < OpenStruct
|
20
|
+
|
21
|
+
include Enumerable
|
22
|
+
|
23
|
+
def self.parse(options = {})
|
24
|
+
options = {
|
25
|
+
:xml => "",
|
26
|
+
:parse_options => { 'ForceArray' => ['item'], 'SuppressEmpty' => nil }
|
27
|
+
}.merge(options)
|
28
|
+
response = Response.new(XmlSimple.xml_in(options[:xml], options[:parse_options]))
|
29
|
+
|
30
|
+
# set the xml attribute of the response object to contain the original XML that was
|
31
|
+
# returned. This allows anyone to bypass our parsing if desired and just
|
32
|
+
# get right at the raw XML response.
|
33
|
+
response.xml = options[:xml]
|
34
|
+
return response
|
35
|
+
end
|
36
|
+
|
37
|
+
# Every member of an OpenStruct object has getters and setters, the latter of which
|
38
|
+
# has a method ending in "=". Find all of these methods, excluding those defined on
|
39
|
+
# parent classes.
|
40
|
+
def members
|
41
|
+
methods(false).sort.grep(/=/).map { |m| m[0...-1] }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Required by the Enumerable module. Iterate over each item in the members array
|
45
|
+
# and pass as a value the block passed to each using yield.
|
46
|
+
def each
|
47
|
+
members.each do |method|
|
48
|
+
yield send(method)
|
49
|
+
end
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Same as the each method, but with both key and value.
|
54
|
+
#
|
55
|
+
#Sample Use:
|
56
|
+
# obj.each_pair { |k,v| puts "key: #{k}, value: #{v}" }
|
57
|
+
def each_pair
|
58
|
+
members.each do |method|
|
59
|
+
yield method, send(method)
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Alternative method for getting members.
|
65
|
+
def [](member)
|
66
|
+
send(member)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Alternative method for setting members.
|
70
|
+
def []=(member, value)
|
71
|
+
send("#{member}=", value)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Helper for converting to string which support a long and short version
|
75
|
+
# to avoid recursion problems with parents.
|
76
|
+
def to_string(short=false)
|
77
|
+
s = "#<#{self.class}:0x#{(2 ** 32 + object_id).to_s(16).upcase}"
|
78
|
+
if (short)
|
79
|
+
s += " ..."
|
80
|
+
else
|
81
|
+
each_pair { |k,v|
|
82
|
+
if (v == self.parent && v.kind_of?(Response))
|
83
|
+
v = v.to_string(true)
|
84
|
+
elsif (v.kind_of?(String))
|
85
|
+
v = "\"#{v.gsub("\"", "\\\"")}\""
|
86
|
+
elsif (v.kind_of?(NilClass))
|
87
|
+
v = "nil"
|
88
|
+
end
|
89
|
+
s += " #{k}=#{v}"
|
90
|
+
}
|
91
|
+
end
|
92
|
+
s += ">"
|
93
|
+
return s
|
94
|
+
end
|
95
|
+
|
96
|
+
# Override of to string method.
|
97
|
+
def to_s
|
98
|
+
return to_string
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Initialize the object by passing data to the OpenStruct initialize method
|
104
|
+
# and then converting ourself to guarantee we have top-to-bottom data
|
105
|
+
# representation as a Response object.
|
106
|
+
def initialize(data, parent=nil)
|
107
|
+
super(data)
|
108
|
+
self.parent = parent
|
109
|
+
Response.convert(self, parent)
|
110
|
+
end
|
111
|
+
|
112
|
+
# The "brains" of our Response class. This method takes an arbitray object and
|
113
|
+
# depending on its class attempts to convert it.
|
114
|
+
def self.convert(obj, parent)
|
115
|
+
if (obj.kind_of?(Response))
|
116
|
+
# Recursively convert the object.
|
117
|
+
obj.each_pair { |k,v|
|
118
|
+
if (v != obj.parent)
|
119
|
+
obj[k] = convert(v, obj)
|
120
|
+
end
|
121
|
+
}
|
122
|
+
return obj
|
123
|
+
elsif (obj.kind_of?(Hash))
|
124
|
+
# Hashes make good Responses already thanks to OpenStruct.
|
125
|
+
return Response.new(obj, parent)
|
126
|
+
elsif (obj.kind_of?(Array))
|
127
|
+
# With arrays, make sure each element is appropriately converted.
|
128
|
+
new_arr = []
|
129
|
+
obj.each { |elem|
|
130
|
+
new_arr << convert(elem, parent)
|
131
|
+
}
|
132
|
+
return new_arr
|
133
|
+
else
|
134
|
+
# At this point we're out of ideas, so let's hope it is a string.
|
135
|
+
return obj
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end # class Response < OpenStruct
|
140
|
+
|
141
|
+
end # module
|
142
|
+
|
data/lib/ruby-rapleaf.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'cgi'
|
3
|
+
require 'openssl'
|
4
|
+
require 'digest/sha1'
|
5
|
+
require 'net/http'
|
6
|
+
#require 'net/https'
|
7
|
+
require 'builder'
|
8
|
+
require 'ostruct'
|
9
|
+
|
10
|
+
library_files = Dir[File.join(File.dirname(__FILE__), "/rapleaf/**/*.rb")]
|
11
|
+
library_files.each do |file|
|
12
|
+
require file.gsub(/\.rb$/, "")
|
13
|
+
end
|
14
|
+
|
15
|
+
module Rapleaf
|
16
|
+
|
17
|
+
VERSION = '0.2.3e'
|
18
|
+
|
19
|
+
# API Constants
|
20
|
+
API_HOST = 'api.rapleaf.com'
|
21
|
+
API_HOST_V4 = 'personalize.rlcdn.com'
|
22
|
+
API_PORT = 80
|
23
|
+
API_VERSION = 'v4'
|
24
|
+
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{ruby-rapleafbg}
|
3
|
+
s.version = "0.2.3f"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Glenn Rempe", "Sam Stokes", "Justin Ip", "Brad Gilreath"]
|
7
|
+
s.date = %q{2010-11-17}
|
8
|
+
s.description = %q{Rapleaf's goal is to make the internet safe and transparent, by allowing you to evaluate your web footprint across a variety of user-generated sites. See http://www.rapleaf.com for more information. Cheap update for API v4.}
|
9
|
+
s.email = ["glenn@rempe.us", "sam@rapportive.com", "bwgilreath@gmail.com"]
|
10
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
11
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "examples/person.rb", "lib/ruby-rapleaf.rb", "lib/rapleaf/exceptions.rb", "lib/rapleaf/rapleaf.rb", "lib/rapleaf/responses.rb", "ruby-rapleaf.gemspec"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.homepage = %q{http://github.com/rapportive-oss/ruby-rapleaf}
|
14
|
+
s.rdoc_options = ["--main", "README.txt"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubyforge_project = %q{ruby-rapleaf}
|
17
|
+
s.rubygems_version = %q{1.2.0}
|
18
|
+
s.summary = %q{Rapleaf's goal is to make the internet safe and transparent, by allowing you to evaluate your web footprint across a variety of user-generated sites}
|
19
|
+
|
20
|
+
if s.respond_to? :specification_version then
|
21
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
|
+
s.specification_version = 2
|
23
|
+
|
24
|
+
if current_version >= 3 then
|
25
|
+
s.add_runtime_dependency(%q<xml-simple>, [">= 1.0.11"])
|
26
|
+
s.add_runtime_dependency(%q<builder>, [">= 2.1.2"])
|
27
|
+
s.add_development_dependency(%q<hoe>, [">= 1.7.0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<xml-simple>, [">= 1.0.11"])
|
30
|
+
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
31
|
+
s.add_dependency(%q<hoe>, [">= 1.7.0"])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<xml-simple>, [">= 1.0.11"])
|
35
|
+
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
36
|
+
s.add_dependency(%q<hoe>, [">= 1.7.0"])
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-rapleafbg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 3450188
|
5
|
+
prerelease: true
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 3f
|
10
|
+
version: 0.2.3f
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Glenn Rempe
|
14
|
+
- Sam Stokes
|
15
|
+
- Justin Ip
|
16
|
+
- Brad Gilreath
|
17
|
+
autorequire:
|
18
|
+
bindir: bin
|
19
|
+
cert_chain: []
|
20
|
+
|
21
|
+
date: 2010-11-17 00:00:00 -05:00
|
22
|
+
default_executable:
|
23
|
+
dependencies:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: xml-simple
|
26
|
+
prerelease: false
|
27
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
hash: 1
|
33
|
+
segments:
|
34
|
+
- 1
|
35
|
+
- 0
|
36
|
+
- 11
|
37
|
+
version: 1.0.11
|
38
|
+
type: :runtime
|
39
|
+
version_requirements: *id001
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: builder
|
42
|
+
prerelease: false
|
43
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
hash: 15
|
49
|
+
segments:
|
50
|
+
- 2
|
51
|
+
- 1
|
52
|
+
- 2
|
53
|
+
version: 2.1.2
|
54
|
+
type: :runtime
|
55
|
+
version_requirements: *id002
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: hoe
|
58
|
+
prerelease: false
|
59
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 11
|
65
|
+
segments:
|
66
|
+
- 1
|
67
|
+
- 7
|
68
|
+
- 0
|
69
|
+
version: 1.7.0
|
70
|
+
type: :development
|
71
|
+
version_requirements: *id003
|
72
|
+
description: Rapleaf's goal is to make the internet safe and transparent, by allowing you to evaluate your web footprint across a variety of user-generated sites. See http://www.rapleaf.com for more information. Cheap update for API v4.
|
73
|
+
email:
|
74
|
+
- glenn@rempe.us
|
75
|
+
- sam@rapportive.com
|
76
|
+
- bwgilreath@gmail.com
|
77
|
+
executables: []
|
78
|
+
|
79
|
+
extensions: []
|
80
|
+
|
81
|
+
extra_rdoc_files:
|
82
|
+
- History.txt
|
83
|
+
- Manifest.txt
|
84
|
+
- README.txt
|
85
|
+
files:
|
86
|
+
- History.txt
|
87
|
+
- Manifest.txt
|
88
|
+
- README.txt
|
89
|
+
- Rakefile
|
90
|
+
- examples/person.rb
|
91
|
+
- lib/ruby-rapleaf.rb
|
92
|
+
- lib/rapleaf/exceptions.rb
|
93
|
+
- lib/rapleaf/rapleaf.rb
|
94
|
+
- lib/rapleaf/responses.rb
|
95
|
+
- ruby-rapleaf.gemspec
|
96
|
+
has_rdoc: true
|
97
|
+
homepage: http://github.com/rapportive-oss/ruby-rapleaf
|
98
|
+
licenses: []
|
99
|
+
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options:
|
102
|
+
- --main
|
103
|
+
- README.txt
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
version: "0"
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
hash: 3
|
121
|
+
segments:
|
122
|
+
- 0
|
123
|
+
version: "0"
|
124
|
+
requirements: []
|
125
|
+
|
126
|
+
rubyforge_project: ruby-rapleaf
|
127
|
+
rubygems_version: 1.3.7
|
128
|
+
signing_key:
|
129
|
+
specification_version: 2
|
130
|
+
summary: Rapleaf's goal is to make the internet safe and transparent, by allowing you to evaluate your web footprint across a variety of user-generated sites
|
131
|
+
test_files: []
|
132
|
+
|