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 CHANGED
@@ -1,8 +1,7 @@
1
1
  Problem
2
2
  =======
3
- - OpenID is complex
4
- - OpenID is not universally used
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
- #login.erb
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
- (`popup_code` can also be called with `:unobstrusive=>true`)
38
+ `popup_code` can also be called with `:unobstrusive=>true`
38
39
 
39
40
  Controller
40
41
  ----------
41
- # simple: use defaults
42
- # user_data returns e.g.
43
- # {:name=>'John Doe', :username => 'john', :email=>'john@doe.com', :identifier=>'blug.google.com/openid/dsdfsdfs3f3'}
44
- # when no user_data was found (invalid token supplied), data is empty, you may want to handle that seperatly...
45
- # your user model must have an identifier column
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],'YOUR RPX API KEY')
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
- # process the raw response yourself:
53
- RPXNow.user_data(params[:token],'YOUR RPX API KEY'){|raw| {:email=>raw['profile']['verifiedEmail']}}
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
- # you can provide the api key once, and leave it out on all following calls
59
- RPXNow.api_key = 'YOUR RPX API KEY'
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.map(identifier,primary_key,'YOUR RPX API KEY')
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
- - validate RPXNow.com SSL certificate
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
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 4
3
- :patch: 2
2
+ :minor: 5
3
+ :patch: 0
4
4
  :major: 0
data/lib/rpx_now.rb CHANGED
@@ -3,7 +3,10 @@ require 'json'
3
3
  module RPXNow
4
4
  extend self
5
5
 
6
- attr_writer :api_key
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("https://rpxnow.com/api/v#{version}/auth_info", options)
20
+ data = secure_json_post("/api/v#{version}/auth_info", options)
18
21
  rescue ServerError
19
- return nil if $!.to_s =~ /token/ or $!.to_s=~/Data not found/
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("https://rpxnow.com/api/v#{version}/map", options)
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("https://rpxnow.com/api/v#{version}/unmap", options)
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("https://rpxnow.com/api/v#{version}/mappings", options)
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}.rpxnow.com/openid/embed?token_url=#{url}"
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}.rpxnow.com/openid/v#{version}/signin?token_url=#{url}\">#{text}</a>"
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}.rpxnow.com/openid/v#{version}/signin?token_url=#{url}">
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://rpxnow.com/openid/v#{version}/widget" type="text/javascript"></script>
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(url,data={})
125
- data = JSON.parse(post(url,data))
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(url,data)
131
+ def post(path, data)
132
132
  require 'net/http'
133
- url = URI.parse(url)
134
- http = Net::HTTP.new(url.host, url.port)
135
- if url.scheme == 'https'
136
- require 'net/https'
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 to_query(data = {})
147
- return data.to_query if Hash.respond_to? :to_query
148
- return "" if data.empty?
149
-
150
- #simpler to_query
151
- query_data = []
152
- data.each do |k, v|
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
- class ServerError < Exception
160
- #to_s returns message(which is a hash...)
161
- def to_s
162
- super.to_s
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 = nil
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 %Q({"stat":"ok"})
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
- %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"})
71
+ mock(:code=>"200",:body=>@response_body)
67
72
  end
68
73
 
69
- it "is empty when used with an invalid token" do
70
- RPXNow.user_data('xxxx',API_KEY).should == nil
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',API_KEY).should == nil
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('','x').should == {:name=>'Michael Grosser',:email=>'grosser.michael@googlemail.com',:identifier=>"https://www.google.com/accounts/o8/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM", :username => 'grosser.michael'}
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
- RPXNow.expects(:post).returns fake_response.sub(%Q("verifiedEmail"), %Q("primaryKey":"2","verifiedEmail"))
84
- RPXNow.user_data('','x')[:id].should == '2'
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
- RPXNow.expects(:post).returns fake_response.sub(%Q("verifiedEmail"), %Q("primaryKey":"dbalatero","verifiedEmail"))
89
- RPXNow.user_data('','x')[:id].should == 'dbalatero'
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 %Q({"x":"1","stat":"ok"})
102
+ RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"x":"1","stat":"ok"}))
94
103
  response = nil
95
- RPXNow.user_data('','x'){|data| response = 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 %Q({"x":"1","stat":"ok"})
101
- RPXNow.user_data('','x'){|data| "x"}.should == 'x'
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('','x',:extended=>'true')
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 :secure_json_post do
149
+ describe :parse_response do
123
150
  it "parses json when status is ok" do
124
- RPXNow.expects(:post).returns %Q({"stat":"ok","data":"xx"})
125
- RPXNow.send(:secure_json_post, %Q("yy"))['data'].should == "xx"
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
- RPXNow.expects(:post).returns %Q({"err":"wtf","stat":"ok"})
130
- lambda{RPXNow.send(:secure_json_post,'xx')}.should raise_error RPXNow::ServerError
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 status is not ok" do
134
- RPXNow.expects(:post).returns %Q({"stat":"err"})
135
- lambda{RPXNow.send(:secure_json_post,'xx')}.should raise_error RPXNow::ServerError
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 %Q({"stat":"ok", "identifiers": ["http://test.myopenid.com/"]})
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 %Q({"stat":"ok"})
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 %Q({"stat":"ok"})
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 == "https://rpxnow.com/api/v300/unmap"}
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.2
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-05-22 00:00:00 -07:00
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: 3
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