grosser-rpx_now 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +25 -33
- data/VERSION.yml +2 -2
- data/lib/rpx_now.rb +45 -43
- data/spec/rpx_now_spec.rb +69 -42
- metadata +3 -3
data/README.markdown
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
Problem
|
2
2
|
=======
|
3
|
-
- OpenID is complex
|
4
|
-
-
|
5
|
-
- Facebook / Myspace / MS-LiveId / AOL connections require different libraries and knowledge
|
3
|
+
- OpenID is complex, limited and hard to use for users
|
4
|
+
- Facebook / Twitter / Myspace / Google / MS-LiveId / AOL connections require different libraries and knowledge
|
6
5
|
- Multiple heterogenouse providers are hard to map to a single user
|
7
6
|
|
8
7
|
Solution
|
@@ -10,9 +9,13 @@ Solution
|
|
10
9
|
- Use [RPX](http://rpxnow.com) for universal and usable user login
|
11
10
|
- Use view/controller helpers for easy integration
|
12
11
|
|
12
|
+
![Single Interface for all providers](https://rpxnow.com/images/how_diagram.png)
|
13
|
+
![Visitors choose from providers they already have](https://rpxnow.com/images/6providers.png?2)
|
14
|
+
|
13
15
|
Usage
|
14
16
|
=====
|
15
17
|
- Get an API key @ [RPX](http://rpxnow.com)
|
18
|
+
- run [MIGRATION](http://github.com/grosser/rpx_now/raw/master/MIGRATION)
|
16
19
|
- Build login view
|
17
20
|
- Communicate with RPX API in controller to create or login User
|
18
21
|
- for more advanced features have a look at the [RPX API Docs](https://rpxnow.com/docs)
|
@@ -21,70 +24,59 @@ Install
|
|
21
24
|
=======
|
22
25
|
- As Rails plugin: `script/plugin install git://github.com/grosser/rpx_now.git `
|
23
26
|
- As gem: `sudo gem install grosser-rpx_now --source http://gems.github.com/`
|
24
|
-
- As gem from source: `git clone git://github.com/grosser/rpx_now.git`,`cd rpx_now && rake install`
|
25
27
|
|
26
28
|
Examples
|
27
29
|
========
|
28
30
|
|
29
31
|
View
|
30
32
|
----
|
31
|
-
#
|
32
|
-
#here 'mywebsite' is your subdomain/realm on RPX
|
33
|
+
#'mywebsite' is your subdomain/realm on RPX
|
33
34
|
<%=RPXNow.embed_code('mywebsite',rpx_token_sessions_url)%>
|
34
35
|
OR
|
35
36
|
<%=RPXNow.popup_code('Login here...','mywebsite',rpx_token_sessions_url,:language=>'de')%>
|
36
37
|
|
37
|
-
|
38
|
+
`popup_code` can also be called with `:unobstrusive=>true`
|
38
39
|
|
39
40
|
Controller
|
40
41
|
----------
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
42
|
+
RPXNow.api_key = "YOU RPX API KEY"
|
43
|
+
|
44
|
+
# user_data
|
45
|
+
# found: {:name=>'John Doe', :username => 'john', :email=>'john@doe.com', :identifier=>'blug.google.com/openid/dsdfsdfs3f3'}
|
46
|
+
# not found: nil (can happen with e.g. invalid tokens)
|
46
47
|
def rpx_token
|
47
|
-
data = RPXNow.user_data(params[:token]
|
48
|
+
raise "hackers?" unless data = RPXNow.user_data(params[:token])
|
48
49
|
self.current_user = User.find_by_identifier(data[:identifier]) || User.create!(data)
|
49
50
|
redirect_to '/'
|
50
51
|
end
|
51
52
|
|
52
|
-
#
|
53
|
-
RPXNow.user_data(params[:token]
|
54
|
-
|
55
|
-
# request extended parameters (most users and APIs do not supply them)
|
56
|
-
RPXNow.user_data(params[:token],'YOUR RPX API KEY',:extended=>'true'){|raw| ...have a look at the RPX API DOCS...}
|
53
|
+
# raw request processing
|
54
|
+
RPXNow.user_data(params[:token]){|raw| {:email=>raw['profile']['verifiedEmail']} }
|
57
55
|
|
58
|
-
#
|
59
|
-
RPXNow.
|
60
|
-
RPXNow.user_data(params[:token],:extended=>'true')
|
56
|
+
# raw request with extended parameters (most users and APIs do not supply them)
|
57
|
+
RPXNow.user_data(params[:token], :extended=>'true'){|raw| ...have a look at the RPX API DOCS...}
|
61
58
|
|
62
59
|
Advanced
|
63
60
|
--------
|
64
61
|
###Versions
|
65
|
-
The version of RPXNow api can be set globally:
|
66
62
|
RPXNow.api_version = 2
|
67
|
-
Or local on each call:
|
68
|
-
RPXNow.mappings(primary_key, :api_version=>1)
|
69
63
|
|
70
64
|
###Mappings
|
71
65
|
You can map your primary keys (e.g. user.id) to identifiers, so that
|
72
66
|
users can login to the same account with multiple identifiers.
|
73
|
-
#add a mapping
|
74
|
-
RPXNow.
|
75
|
-
|
76
|
-
#remove a mapping
|
77
|
-
RPXNow.unmap(identifier,primary_key,'YOUR RPX API KEY')
|
78
|
-
|
79
|
-
#show mappings
|
80
|
-
RPXNow.mappings(primary_key,'YOUR RPX API KEY') # [identifier1,identifier2,...]
|
67
|
+
RPXNow.map(identifier, primary_key) #add a mapping
|
68
|
+
RPXNow.unmap(identifier, primary_key) #remove a mapping
|
69
|
+
RPXNow.mappings(primary_key) # [identifier1,identifier2,...]
|
81
70
|
|
82
71
|
After a primary key is mapped to an identifier, when a user logs in with this identifier,
|
83
72
|
`RPXNow.user_data` will contain his `primaryKey` as `:id`.
|
84
73
|
|
85
74
|
TODO
|
86
75
|
====
|
87
|
-
-
|
76
|
+
- add provider?
|
77
|
+
- add get_contacts (premium rpx service)
|
78
|
+
- add all_mappings
|
79
|
+
|
88
80
|
|
89
81
|
Author
|
90
82
|
======
|
data/VERSION.yml
CHANGED
data/lib/rpx_now.rb
CHANGED
@@ -3,7 +3,10 @@ require 'json'
|
|
3
3
|
module RPXNow
|
4
4
|
extend self
|
5
5
|
|
6
|
-
|
6
|
+
HOST = 'rpxnow.com'
|
7
|
+
SSL_CERT = File.join(File.dirname(__FILE__), '..', 'certs', 'ssl_cert.pem')
|
8
|
+
|
9
|
+
attr_accessor :api_key
|
7
10
|
attr_accessor :api_version
|
8
11
|
self.api_version = 2
|
9
12
|
|
@@ -14,9 +17,9 @@ module RPXNow
|
|
14
17
|
options = {:token=>token,:apiKey=>api_key}.merge options
|
15
18
|
|
16
19
|
begin
|
17
|
-
data = secure_json_post("
|
20
|
+
data = secure_json_post("/api/v#{version}/auth_info", options)
|
18
21
|
rescue ServerError
|
19
|
-
return nil if $!.to_s
|
22
|
+
return nil if $!.to_s=~/Data not found/
|
20
23
|
raise
|
21
24
|
end
|
22
25
|
if block_given? then yield(data) else read_user_data_from_response(data) end
|
@@ -26,27 +29,27 @@ module RPXNow
|
|
26
29
|
def map(identifier, primary_key, *args)
|
27
30
|
api_key, version, options = extract_key_version_and_options!(args)
|
28
31
|
options = {:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge options
|
29
|
-
secure_json_post("
|
32
|
+
secure_json_post("/api/v#{version}/map", options)
|
30
33
|
end
|
31
34
|
|
32
35
|
# un-maps an identifier to an primary-key (e.g. user.id)
|
33
36
|
def unmap(identifier, primary_key, *args)
|
34
37
|
api_key, version, options = extract_key_version_and_options!(args)
|
35
38
|
options = {:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge options
|
36
|
-
secure_json_post("
|
39
|
+
secure_json_post("/api/v#{version}/unmap", options)
|
37
40
|
end
|
38
41
|
|
39
42
|
# returns an array of identifiers which are mapped to one of your primary-keys (e.g. user.id)
|
40
43
|
def mappings(primary_key, *args)
|
41
44
|
api_key, version, options = extract_key_version_and_options!(args)
|
42
45
|
options = {:primaryKey=>primary_key,:apiKey=>api_key}.merge options
|
43
|
-
data = secure_json_post("
|
46
|
+
data = secure_json_post("/api/v#{version}/mappings", options)
|
44
47
|
data['identifiers']
|
45
48
|
end
|
46
49
|
|
47
50
|
def embed_code(subdomain,url)
|
48
51
|
<<EOF
|
49
|
-
<iframe src="https://#{subdomain}
|
52
|
+
<iframe src="https://#{subdomain}.#{HOST}/openid/embed?token_url=#{url}"
|
50
53
|
scrolling="no" frameBorder="no" style="width:400px;height:240px;">
|
51
54
|
</iframe>
|
52
55
|
EOF
|
@@ -64,16 +67,16 @@ EOF
|
|
64
67
|
|
65
68
|
def unobtrusive_popup_code(text, subdomain, url, options={})
|
66
69
|
version = extract_version! options
|
67
|
-
"<a class=\"rpxnow\" href=\"https://#{subdomain}
|
70
|
+
"<a class=\"rpxnow\" href=\"https://#{subdomain}.#{HOST}/openid/v#{version}/signin?token_url=#{url}\">#{text}</a>"
|
68
71
|
end
|
69
72
|
|
70
73
|
def obtrusive_popup_code(text, subdomain, url, options = {})
|
71
74
|
version = extract_version! options
|
72
75
|
<<EOF
|
73
|
-
<a class="rpxnow" onclick="return false;" href="https://#{subdomain}
|
76
|
+
<a class="rpxnow" onclick="return false;" href="https://#{subdomain}.#{HOST}/openid/v#{version}/signin?token_url=#{url}">
|
74
77
|
#{text}
|
75
78
|
</a>
|
76
|
-
<script src="https
|
79
|
+
<script src="https://#{HOST}/openid/v#{version}/widget" type="text/javascript"></script>
|
77
80
|
<script type="text/javascript">
|
78
81
|
//<![CDATA[
|
79
82
|
RPXNOW.token_url = "#{url}";
|
@@ -115,51 +118,50 @@ EOF
|
|
115
118
|
data = {}
|
116
119
|
data[:identifier] = user_data['identifier']
|
117
120
|
data[:email] = user_data['verifiedEmail'] || user_data['email']
|
118
|
-
data[:username] = user_data['preferredUsername'] || data[:email].sub(/@.*/,'')
|
121
|
+
data[:username] = user_data['preferredUsername'] || data[:email].to_s.sub(/@.*/,'')
|
119
122
|
data[:name] = user_data['displayName'] || data[:username]
|
120
123
|
data[:id] = user_data['primaryKey'] unless user_data['primaryKey'].to_s.empty?
|
121
124
|
data
|
122
125
|
end
|
123
126
|
|
124
|
-
def secure_json_post(
|
125
|
-
|
126
|
-
raise ServerError.new(data['err']) if data['err']
|
127
|
-
raise ServerError.new(data.inspect) unless data['stat']=='ok'
|
128
|
-
data
|
127
|
+
def secure_json_post(path, data)
|
128
|
+
parse_response(post(path,data))
|
129
129
|
end
|
130
130
|
|
131
|
-
def post(
|
131
|
+
def post(path, data)
|
132
132
|
require 'net/http'
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
http.use_ssl = true
|
138
|
-
#TODO do we really want to verify the certificate? http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/
|
139
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
140
|
-
end
|
141
|
-
resp, data = http.post(url.path, to_query(data))
|
142
|
-
raise "POST FAILED:"+resp.inspect unless resp.is_a? Net::HTTPOK
|
143
|
-
data
|
133
|
+
require 'net/https'
|
134
|
+
request = Net::HTTP::Get.new(path)
|
135
|
+
request.form_data = data
|
136
|
+
make_request(request)
|
144
137
|
end
|
145
138
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
query_data << "#{k}=#{v}"
|
154
|
-
end
|
155
|
-
|
156
|
-
return query_data.join('&')
|
139
|
+
def make_request(request)
|
140
|
+
http = Net::HTTP.new(HOST, 443)
|
141
|
+
http.use_ssl = true
|
142
|
+
http.ca_file = SSL_CERT
|
143
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
144
|
+
http.verify_depth = 5
|
145
|
+
http.request(request)
|
157
146
|
end
|
158
147
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
148
|
+
def parse_response(response)
|
149
|
+
if response.code.to_i >= 400
|
150
|
+
raise ServiceUnavailableError, "The RPX service is temporarily unavailable. (4XX)"
|
151
|
+
else
|
152
|
+
result = JSON.parse(response.body)
|
153
|
+
return result unless result['err']
|
154
|
+
|
155
|
+
code = result['err']['code']
|
156
|
+
if code == -1
|
157
|
+
raise ServiceUnavailableError, "The RPX service is temporarily unavailable."
|
158
|
+
else
|
159
|
+
raise ApiError, "Got error: #{result['err']['msg']} (code: #{code}), HTTP status: #{response.code}"
|
160
|
+
end
|
163
161
|
end
|
164
162
|
end
|
163
|
+
|
164
|
+
class ServerError < Exception; end #backwards compatibility / catch all
|
165
|
+
class ApiError < ServerError; end
|
166
|
+
class ServiceUnavailableError < ServerError; end
|
165
167
|
end
|
data/spec/rpx_now_spec.rb
CHANGED
@@ -5,14 +5,14 @@ API_VERSION = RPXNow.api_version
|
|
5
5
|
|
6
6
|
describe RPXNow do
|
7
7
|
before do
|
8
|
-
RPXNow.api_key =
|
8
|
+
RPXNow.api_key = API_KEY
|
9
9
|
RPXNow.api_version = API_VERSION
|
10
10
|
end
|
11
11
|
|
12
12
|
describe :api_key= do
|
13
13
|
it "stores the api key, so i do not have to supply everytime" do
|
14
14
|
RPXNow.api_key='XX'
|
15
|
-
RPXNow.expects(:post).with{|x,data|data[:apiKey]=='XX'}.returns
|
15
|
+
RPXNow.expects(:post).with{|x,data|data[:apiKey]=='XX'}.returns mock(:code=>'200', :body=>%Q({"stat":"ok"}))
|
16
16
|
RPXNow.mappings(1)
|
17
17
|
end
|
18
18
|
end
|
@@ -62,50 +62,77 @@ describe RPXNow do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
describe :user_data do
|
65
|
+
before do
|
66
|
+
@response_body = %Q({"profile":{"verifiedEmail":"grosser.michael@googlemail.com","displayName":"Michael Grosser","preferredUsername":"grosser.michael","identifier":"https:\/\/www.google.com\/accounts\/o8\/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM","email":"grosser.michael@gmail.com"},"stat":"ok"})
|
67
|
+
@fake_user_data = {'profile'=>{}}
|
68
|
+
end
|
69
|
+
|
65
70
|
def fake_response
|
66
|
-
|
71
|
+
mock(:code=>"200",:body=>@response_body)
|
67
72
|
end
|
68
73
|
|
69
|
-
it "
|
70
|
-
|
74
|
+
it "raises ApiError when used with an invalid token" do
|
75
|
+
lambda{
|
76
|
+
RPXNow.user_data('xxxx')
|
77
|
+
}.should raise_error(RPXNow::ApiError)
|
71
78
|
end
|
72
79
|
|
73
80
|
it "is empty when used with an unknown token" do
|
74
|
-
RPXNow.user_data('60d8c6374f4e9d290a7b55f39da7cc6435aef3d3'
|
81
|
+
RPXNow.user_data('60d8c6374f4e9d290a7b55f39da7cc6435aef3d3').should == nil
|
75
82
|
end
|
76
83
|
|
77
84
|
it "parses JSON response to user data" do
|
78
85
|
RPXNow.expects(:post).returns fake_response
|
79
|
-
RPXNow.user_data(''
|
86
|
+
RPXNow.user_data('').should == {:name=>'Michael Grosser',:email=>'grosser.michael@googlemail.com',:identifier=>"https://www.google.com/accounts/o8/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM", :username => 'grosser.michael'}
|
80
87
|
end
|
81
88
|
|
82
89
|
it "adds a :id when primaryKey was returned" do
|
83
|
-
|
84
|
-
RPXNow.
|
90
|
+
@response_body.sub!(%Q("verifiedEmail"), %Q("primaryKey":"2","verifiedEmail"))
|
91
|
+
RPXNow.expects(:post).returns fake_response
|
92
|
+
RPXNow.user_data('')[:id].should == '2'
|
85
93
|
end
|
86
94
|
|
87
95
|
it "handles primaryKeys that are not numeric" do
|
88
|
-
|
89
|
-
RPXNow.
|
96
|
+
@response_body.sub!(%Q("verifiedEmail"), %Q("primaryKey":"dbalatero","verifiedEmail"))
|
97
|
+
RPXNow.expects(:post).returns fake_response
|
98
|
+
RPXNow.user_data('')[:id].should == 'dbalatero'
|
90
99
|
end
|
91
100
|
|
92
101
|
it "hands JSON response to supplied block" do
|
93
|
-
RPXNow.expects(:post).returns
|
102
|
+
RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"x":"1","stat":"ok"}))
|
94
103
|
response = nil
|
95
|
-
RPXNow.user_data(''
|
104
|
+
RPXNow.user_data(''){|data| response = data}
|
96
105
|
response.should == {"x" => "1", "stat" => "ok"}
|
97
106
|
end
|
98
107
|
|
99
108
|
it "returns what the supplied block returned" do
|
100
|
-
RPXNow.expects(:post).returns
|
101
|
-
RPXNow.user_data(''
|
109
|
+
RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"x":"1","stat":"ok"}))
|
110
|
+
RPXNow.user_data(''){|data| "x"}.should == 'x'
|
102
111
|
end
|
103
112
|
|
104
113
|
it "can send additional parameters" do
|
105
114
|
RPXNow.expects(:post).with{|url,data|
|
106
115
|
data[:extended].should == 'true'
|
107
116
|
}.returns fake_response
|
108
|
-
RPXNow.user_data(''
|
117
|
+
RPXNow.user_data('',:extended=>'true')
|
118
|
+
end
|
119
|
+
|
120
|
+
it "works with api key as 2nd parameter (backwards compatibility)" do
|
121
|
+
RPXNow.expects(:secure_json_post).with('/api/v2/auth_info', :apiKey=>'THE KEY', :token=>'id').returns @fake_user_data
|
122
|
+
RPXNow.user_data('id', 'THE KEY')
|
123
|
+
RPXNow.api_key.should == API_KEY
|
124
|
+
end
|
125
|
+
|
126
|
+
it "works with api key as 2nd parameter and options (backwards compatibility)" do
|
127
|
+
RPXNow.expects(:secure_json_post).with('/api/v2/auth_info', :apiKey=>'THE KEY', :extended=>'abc', :token=>'id' ).returns @fake_user_data
|
128
|
+
RPXNow.user_data('id', 'THE KEY', :extended=>'abc')
|
129
|
+
RPXNow.api_key.should == API_KEY
|
130
|
+
end
|
131
|
+
|
132
|
+
it "works with api version as option (backwards compatibility)" do
|
133
|
+
RPXNow.expects(:secure_json_post).with('/api/v123/auth_info', :apiKey=>API_KEY, :token=>'id', :extended=>'abc').returns @fake_user_data
|
134
|
+
RPXNow.user_data('id', :extended=>'abc', :api_version=>123)
|
135
|
+
RPXNow.api_version.should == API_VERSION
|
109
136
|
end
|
110
137
|
end
|
111
138
|
|
@@ -119,45 +146,56 @@ describe RPXNow do
|
|
119
146
|
end
|
120
147
|
end
|
121
148
|
|
122
|
-
describe :
|
149
|
+
describe :parse_response do
|
123
150
|
it "parses json when status is ok" do
|
124
|
-
|
125
|
-
RPXNow.send(:
|
151
|
+
response = mock(:code=>'200', :body=>%Q({"stat":"ok","data":"xx"}))
|
152
|
+
RPXNow.send(:parse_response, response)['data'].should == "xx"
|
126
153
|
end
|
127
|
-
|
154
|
+
|
128
155
|
it "raises when there is a communication error" do
|
129
|
-
|
130
|
-
lambda{
|
156
|
+
response = stub(:code=>'200', :body=>%Q({"err":"wtf","stat":"ok"}))
|
157
|
+
lambda{
|
158
|
+
RPXNow.send(:parse_response,response)
|
159
|
+
}.should raise_error(RPXNow::ApiError)
|
131
160
|
end
|
132
|
-
|
133
|
-
it "raises when
|
134
|
-
|
135
|
-
lambda{
|
161
|
+
|
162
|
+
it "raises when service has downtime" do
|
163
|
+
response = stub(:code=>'200', :body=>%Q({"err":{"code":-1},"stat":"ok"}))
|
164
|
+
lambda{
|
165
|
+
RPXNow.send(:parse_response,response)
|
166
|
+
}.should raise_error(RPXNow::ServiceUnavailableError)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "raises when service is down" do
|
170
|
+
response = stub(:code=>'400',:body=>%Q({"stat":"err"}))
|
171
|
+
lambda{
|
172
|
+
RPXNow.send(:parse_response,response)
|
173
|
+
}.should raise_error(RPXNow::ServiceUnavailableError)
|
136
174
|
end
|
137
175
|
end
|
138
176
|
|
139
177
|
describe :mappings do
|
140
178
|
it "parses JSON response to unmap data" do
|
141
|
-
RPXNow.expects(:post).returns
|
179
|
+
RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"stat":"ok", "identifiers": ["http://test.myopenid.com/"]}))
|
142
180
|
RPXNow.mappings(1, "x").should == ["http://test.myopenid.com/"]
|
143
181
|
end
|
144
182
|
end
|
145
183
|
|
146
184
|
describe :map do
|
147
185
|
it "adds a mapping" do
|
148
|
-
RPXNow.expects(:post).returns
|
186
|
+
RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"stat":"ok"}))
|
149
187
|
RPXNow.map('http://test.myopenid.com',1, API_KEY)
|
150
188
|
end
|
151
189
|
end
|
152
190
|
|
153
191
|
describe :unmap do
|
154
192
|
it "unmaps a indentifier" do
|
155
|
-
RPXNow.expects(:post).returns
|
193
|
+
RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"stat":"ok"}))
|
156
194
|
RPXNow.unmap('http://test.myopenid.com', 1, "x")
|
157
195
|
end
|
158
196
|
|
159
197
|
it "can be called with a specific version" do
|
160
|
-
RPXNow.expects(:secure_json_post).with{|a,b|a == "
|
198
|
+
RPXNow.expects(:secure_json_post).with{|a,b|a == "/api/v300/unmap"}
|
161
199
|
RPXNow.unmap('http://test.myopenid.com', 1, :api_key=>'xxx', :api_version=>300)
|
162
200
|
end
|
163
201
|
end
|
@@ -192,15 +230,4 @@ describe RPXNow do
|
|
192
230
|
RPXNow.mappings(1,API_KEY).should == [@k1]
|
193
231
|
end
|
194
232
|
end
|
195
|
-
|
196
|
-
describe :to_query do
|
197
|
-
it "should not depend on active support" do
|
198
|
-
RPXNow.send('to_query', {:one => " abc"}).should == "one= abc"
|
199
|
-
end
|
200
|
-
|
201
|
-
it "should use ActiveSupport core extensions" do
|
202
|
-
require 'activesupport'
|
203
|
-
RPXNow.send('to_query', {:one => " abc"}).should == "one=+abc"
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
233
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grosser-rpx_now
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-17 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -61,7 +61,7 @@ requirements: []
|
|
61
61
|
rubyforge_project:
|
62
62
|
rubygems_version: 1.2.0
|
63
63
|
signing_key:
|
64
|
-
specification_version:
|
64
|
+
specification_version: 2
|
65
65
|
summary: Helper to simplify RPX Now user login/creation
|
66
66
|
test_files:
|
67
67
|
- spec/rpx_now_spec.rb
|