dbalatero-rpx_now 0.4.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/README.markdown +95 -0
- data/VERSION.yml +4 -0
- data/lib/rpx_now.rb +164 -0
- data/spec/rpx_now_spec.rb +206 -0
- data/spec/spec_helper.rb +36 -0
- metadata +67 -0
data/README.markdown
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
Problem
|
2
|
+
=======
|
3
|
+
- OpenID is complex
|
4
|
+
- OpenID is not universally used
|
5
|
+
- Facebook / Myspace / MS-LiveId / AOL connections require different libraries and knowledge
|
6
|
+
- Multiple heterogenouse providers are hard to map to a single user
|
7
|
+
|
8
|
+
Solution
|
9
|
+
========
|
10
|
+
- Use [RPX](http://rpxnow.com) for universal and usable user login
|
11
|
+
- Use view/controller helpers for easy integration
|
12
|
+
|
13
|
+
Usage
|
14
|
+
=====
|
15
|
+
- Get an API key @ [RPX](http://rpxnow.com)
|
16
|
+
- Build login view
|
17
|
+
- Communicate with RPX API in controller to create or login User
|
18
|
+
- for more advanced features have a look at the [RPX API Docs](https://rpxnow.com/docs)
|
19
|
+
|
20
|
+
Install
|
21
|
+
=======
|
22
|
+
- As Rails plugin: `script/plugin install git://github.com/grosser/rpx_now.git `
|
23
|
+
- 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
|
+
|
26
|
+
Examples
|
27
|
+
========
|
28
|
+
|
29
|
+
View
|
30
|
+
----
|
31
|
+
#login.erb
|
32
|
+
#here 'mywebsite' is your subdomain/realm on RPX
|
33
|
+
<%=RPXNow.embed_code('mywebsite',rpx_token_sessions_url)%>
|
34
|
+
OR
|
35
|
+
<%=RPXNow.popup_code('Login here...','mywebsite',rpx_token_sessions_url,:language=>'de')%>
|
36
|
+
|
37
|
+
(`popup_code` can also be called with `:unobstrusive=>true`)
|
38
|
+
|
39
|
+
Controller
|
40
|
+
----------
|
41
|
+
# simple: use defaults
|
42
|
+
# user_data returns e.g. {:name=>'John Doe',:email=>'john@doe.com',:identifier=>'blug.google.com/openid/dsdfsdfs3f3'}
|
43
|
+
# when no user_data was found (invalid token supplied), data is empty, you may want to handle that seperatly...
|
44
|
+
# your user model must have an identifier column
|
45
|
+
def rpx_token
|
46
|
+
data = RPXNow.user_data(params[:token],'YOUR RPX API KEY')
|
47
|
+
self.current_user = User.find_by_identifier(data[:identifier]) || User.create!(data)
|
48
|
+
redirect_to '/'
|
49
|
+
end
|
50
|
+
|
51
|
+
# process the raw response yourself:
|
52
|
+
RPXNow.user_data(params[:token],'YOUR RPX API KEY'){|raw| {:email=>raw['profile']['verifiedEmail']}}
|
53
|
+
|
54
|
+
# request extended parameters (most users and APIs do not supply them)
|
55
|
+
RPXNow.user_data(params[:token],'YOUR RPX API KEY',:extended=>'true'){|raw| ...have a look at the RPX API DOCS...}
|
56
|
+
|
57
|
+
# you can provide the api key once, and leave it out on all following calls
|
58
|
+
RPXNow.api_key = 'YOUR RPX API KEY'
|
59
|
+
RPXNow.user_data(params[:token],:extended=>'true')
|
60
|
+
|
61
|
+
Advanced
|
62
|
+
--------
|
63
|
+
###Versions
|
64
|
+
The version of RPXNow api can be set globally:
|
65
|
+
RPXNow.api_version = 2
|
66
|
+
Or local on each call:
|
67
|
+
RPXNow.mappings(primary_key, :api_version=>1)
|
68
|
+
|
69
|
+
###Mappings
|
70
|
+
You can map your primary keys (e.g. user.id) to identifiers, so that
|
71
|
+
users can login to the same account with multiple identifiers.
|
72
|
+
#add a mapping
|
73
|
+
RPXNow.map(identifier,primary_key,'YOUR RPX API KEY')
|
74
|
+
|
75
|
+
#remove a mapping
|
76
|
+
RPXNow.unmap(identifier,primary_key,'YOUR RPX API KEY')
|
77
|
+
|
78
|
+
#show mappings
|
79
|
+
RPXNow.mappings(primary_key,'YOUR RPX API KEY') # [identifier1,identifier2,...]
|
80
|
+
|
81
|
+
After a primary key is mapped to an identifier, when a user logs in with this identifier,
|
82
|
+
`RPXNow.user_data` will contain his `primaryKey` as `:id`.
|
83
|
+
|
84
|
+
TODO
|
85
|
+
====
|
86
|
+
- validate RPXNow.com SSL certificate
|
87
|
+
|
88
|
+
Author
|
89
|
+
======
|
90
|
+
###Contributors
|
91
|
+
- [DBA](http://github.com/DBA)
|
92
|
+
|
93
|
+
[Michael Grosser](http://pragmatig.wordpress.com)
|
94
|
+
grosser.michael@gmail.com
|
95
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
data/VERSION.yml
ADDED
data/lib/rpx_now.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module RPXNow
|
4
|
+
extend self
|
5
|
+
|
6
|
+
attr_writer :api_key
|
7
|
+
attr_accessor :api_version
|
8
|
+
self.api_version = 2
|
9
|
+
|
10
|
+
# retrieve the users data, or return nil when nothing could be read/token was invalid
|
11
|
+
# or data was not found
|
12
|
+
def user_data(token, *args)
|
13
|
+
api_key, version, options = extract_key_version_and_options!(args)
|
14
|
+
options = {:token=>token,:apiKey=>api_key}.merge options
|
15
|
+
|
16
|
+
begin
|
17
|
+
data = secure_json_post("https://rpxnow.com/api/v#{version}/auth_info", options)
|
18
|
+
rescue ServerError
|
19
|
+
return nil if $!.to_s =~ /token/ or $!.to_s=~/Data not found/
|
20
|
+
raise
|
21
|
+
end
|
22
|
+
if block_given? then yield(data) else read_user_data_from_response(data) end
|
23
|
+
end
|
24
|
+
|
25
|
+
# maps an identifier to an primary-key (e.g. user.id)
|
26
|
+
def map(identifier, primary_key, *args)
|
27
|
+
api_key, version, options = extract_key_version_and_options!(args)
|
28
|
+
options = {:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge options
|
29
|
+
secure_json_post("https://rpxnow.com/api/v#{version}/map", options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# un-maps an identifier to an primary-key (e.g. user.id)
|
33
|
+
def unmap(identifier, primary_key, *args)
|
34
|
+
api_key, version, options = extract_key_version_and_options!(args)
|
35
|
+
options = {:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge options
|
36
|
+
secure_json_post("https://rpxnow.com/api/v#{version}/unmap", options)
|
37
|
+
end
|
38
|
+
|
39
|
+
# returns an array of identifiers which are mapped to one of your primary-keys (e.g. user.id)
|
40
|
+
def mappings(primary_key, *args)
|
41
|
+
api_key, version, options = extract_key_version_and_options!(args)
|
42
|
+
options = {:primaryKey=>primary_key,:apiKey=>api_key}.merge options
|
43
|
+
data = secure_json_post("https://rpxnow.com/api/v#{version}/mappings", options)
|
44
|
+
data['identifiers']
|
45
|
+
end
|
46
|
+
|
47
|
+
def embed_code(subdomain,url)
|
48
|
+
<<EOF
|
49
|
+
<iframe src="https://#{subdomain}.rpxnow.com/openid/embed?token_url=#{url}"
|
50
|
+
scrolling="no" frameBorder="no" style="width:400px;height:240px;">
|
51
|
+
</iframe>
|
52
|
+
EOF
|
53
|
+
end
|
54
|
+
|
55
|
+
def popup_code(text, subdomain, url, options = {})
|
56
|
+
if options[:unobtrusive]
|
57
|
+
unobtrusive_popup_code(text, subdomain, url, options)
|
58
|
+
else
|
59
|
+
obtrusive_popup_code(text, subdomain, url, options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def unobtrusive_popup_code(text, subdomain, url, options={})
|
66
|
+
version = extract_version! options
|
67
|
+
"<a class=\"rpxnow\" href=\"https://#{subdomain}.rpxnow.com/openid/v#{version}/signin?token_url=#{url}\">#{text}</a>"
|
68
|
+
end
|
69
|
+
|
70
|
+
def obtrusive_popup_code(text, subdomain, url, options = {})
|
71
|
+
version = extract_version! options
|
72
|
+
<<EOF
|
73
|
+
<a class="rpxnow" onclick="return false;" href="https://#{subdomain}.rpxnow.com/openid/v#{version}/signin?token_url=#{url}">
|
74
|
+
#{text}
|
75
|
+
</a>
|
76
|
+
<script src="https://rpxnow.com/openid/v#{version}/widget" type="text/javascript"></script>
|
77
|
+
<script type="text/javascript">
|
78
|
+
//<![CDATA[
|
79
|
+
RPXNOW.token_url = "#{url}";
|
80
|
+
|
81
|
+
RPXNOW.realm = "#{subdomain}";
|
82
|
+
RPXNOW.overlay = true;
|
83
|
+
RPXNOW.language_preference = '#{options[:language]||'en'}';
|
84
|
+
//]]>
|
85
|
+
</script>
|
86
|
+
EOF
|
87
|
+
end
|
88
|
+
|
89
|
+
def extract_key_version_and_options!(args)
|
90
|
+
key, options = extract_key_and_options(args)
|
91
|
+
version = extract_version! options
|
92
|
+
[key, version, options]
|
93
|
+
end
|
94
|
+
|
95
|
+
# [API_KEY,{options}] or
|
96
|
+
# [{options}] or
|
97
|
+
# []
|
98
|
+
def extract_key_and_options(args)
|
99
|
+
if args.length == 2
|
100
|
+
[args[0],args[1]]
|
101
|
+
elsif args.length==1
|
102
|
+
if args[0].is_a? Hash then [@api_key,args[0]] else [args[0],{}] end
|
103
|
+
else
|
104
|
+
raise unless @api_key
|
105
|
+
[@api_key,{}]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def extract_version!(options)
|
110
|
+
options.delete(:api_version) || api_version
|
111
|
+
end
|
112
|
+
|
113
|
+
def read_user_data_from_response(response)
|
114
|
+
user_data = response['profile']
|
115
|
+
data = {}
|
116
|
+
data[:identifier] = user_data['identifier']
|
117
|
+
data[:email] = user_data['verifiedEmail'] || user_data['email']
|
118
|
+
data[:name] = user_data['displayName'] || user_data['preferredUsername'] || data[:email].sub(/@.*/,'')
|
119
|
+
data[:id] = user_data['primaryKey'] unless user_data['primaryKey'].to_s.empty?
|
120
|
+
data
|
121
|
+
end
|
122
|
+
|
123
|
+
def secure_json_post(url,data={})
|
124
|
+
data = JSON.parse(post(url,data))
|
125
|
+
raise ServerError.new(data['err']) if data['err']
|
126
|
+
raise ServerError.new(data.inspect) unless data['stat']=='ok'
|
127
|
+
data
|
128
|
+
end
|
129
|
+
|
130
|
+
def post(url,data)
|
131
|
+
require 'net/http'
|
132
|
+
url = URI.parse(url)
|
133
|
+
http = Net::HTTP.new(url.host, url.port)
|
134
|
+
if url.scheme == 'https'
|
135
|
+
require 'net/https'
|
136
|
+
http.use_ssl = true
|
137
|
+
#TODO do we really want to verify the certificate? http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/
|
138
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
139
|
+
end
|
140
|
+
resp, data = http.post(url.path, to_query(data))
|
141
|
+
raise "POST FAILED:"+resp.inspect unless resp.is_a? Net::HTTPOK
|
142
|
+
data
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_query(data = {})
|
146
|
+
return data.to_query if Hash.respond_to? :to_query
|
147
|
+
return "" if data.empty?
|
148
|
+
|
149
|
+
#simpler to_query
|
150
|
+
query_data = []
|
151
|
+
data.each do |k, v|
|
152
|
+
query_data << "#{k}=#{v}"
|
153
|
+
end
|
154
|
+
|
155
|
+
return query_data.join('&')
|
156
|
+
end
|
157
|
+
|
158
|
+
class ServerError < Exception
|
159
|
+
#to_s returns message(which is a hash...)
|
160
|
+
def to_s
|
161
|
+
super.to_s
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
API_KEY = '4b339169026742245b754fa338b9b0aebbd0a733'
|
4
|
+
API_VERSION = RPXNow.api_version
|
5
|
+
|
6
|
+
describe RPXNow do
|
7
|
+
before do
|
8
|
+
RPXNow.api_key = nil
|
9
|
+
RPXNow.api_version = API_VERSION
|
10
|
+
end
|
11
|
+
|
12
|
+
describe :api_key= do
|
13
|
+
it "stores the api key, so i do not have to supply everytime" do
|
14
|
+
RPXNow.api_key='XX'
|
15
|
+
RPXNow.expects(:post).with{|x,data|data[:apiKey]=='XX'}.returns %Q({"stat":"ok"})
|
16
|
+
RPXNow.mappings(1)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe :api_version= do
|
21
|
+
it "can be set to a api_version globally" do
|
22
|
+
RPXNow.api_version = 5
|
23
|
+
RPXNow.popup_code('x','y','z').should =~ %r(/openid/v5/signin)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe :embed_code do
|
28
|
+
it "contains the subdomain" do
|
29
|
+
RPXNow.embed_code('xxx','my_url').should =~ /xxx/
|
30
|
+
end
|
31
|
+
|
32
|
+
it "contains the url" do
|
33
|
+
RPXNow.embed_code('xxx','my_url').should =~ /token_url=my_url/
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe :popup_code do
|
38
|
+
it "defaults to obtrusive output" do
|
39
|
+
RPXNow.popup_code('sign on', 'subdomain', 'http://fake.domain.com/').should =~ /script src=/
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can build an unobtrusive widget with specific version" do
|
43
|
+
expected = %Q(<a class="rpxnow" href="https://subdomain.rpxnow.com/openid/v300/signin?token_url=http://fake.domain.com/">sign on</a>)
|
44
|
+
RPXNow.popup_code('sign on', 'subdomain', 'http://fake.domain.com/', { :unobtrusive => true, :api_version => 300 }).should == expected
|
45
|
+
end
|
46
|
+
|
47
|
+
it "allows to specify the version of the widget" do
|
48
|
+
RPXNow.popup_code('x','y','z', :api_version => 300).should =~ %r(/openid/v300/signin)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "defaults to widget version 2" do
|
52
|
+
RPXNow.popup_code('x','y','z').should =~ %r(/openid/v2/signin)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "defaults to english" do
|
56
|
+
RPXNow.popup_code('x','y','z').should =~ /RPXNOW.language_preference = 'en'/
|
57
|
+
end
|
58
|
+
|
59
|
+
it "has a changeable language" do
|
60
|
+
RPXNow.popup_code('x','y','z',:language=>'de').should =~ /RPXNOW.language_preference = 'de'/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe :user_data do
|
65
|
+
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"})
|
67
|
+
end
|
68
|
+
|
69
|
+
it "is empty when used with an invalid token" do
|
70
|
+
RPXNow.user_data('xxxx',API_KEY).should == nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "is empty when used with an unknown token" do
|
74
|
+
RPXNow.user_data('60d8c6374f4e9d290a7b55f39da7cc6435aef3d3',API_KEY).should == nil
|
75
|
+
end
|
76
|
+
|
77
|
+
it "parses JSON response to user data" do
|
78
|
+
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"}
|
80
|
+
end
|
81
|
+
|
82
|
+
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'
|
85
|
+
end
|
86
|
+
|
87
|
+
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'
|
90
|
+
end
|
91
|
+
|
92
|
+
it "hands JSON response to supplied block" do
|
93
|
+
RPXNow.expects(:post).returns %Q({"x":"1","stat":"ok"})
|
94
|
+
response = nil
|
95
|
+
RPXNow.user_data('','x'){|data| response = data}
|
96
|
+
response.should == {"x" => "1", "stat" => "ok"}
|
97
|
+
end
|
98
|
+
|
99
|
+
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'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "can send additional parameters" do
|
105
|
+
RPXNow.expects(:post).with{|url,data|
|
106
|
+
data[:extended].should == 'true'
|
107
|
+
}.returns fake_response
|
108
|
+
RPXNow.user_data('','x',:extended=>'true')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe :read_user_data_from_response do
|
113
|
+
it "reads secondary names" do
|
114
|
+
RPXNow.send(:read_user_data_from_response,{'profile'=>{'preferredUsername'=>'1'}})[:name].should == '1'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "parses email when no name is found" do
|
118
|
+
RPXNow.send(:read_user_data_from_response,{'profile'=>{'email'=>'1@xxx.com'}})[:name].should == '1'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe :secure_json_post do
|
123
|
+
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"
|
126
|
+
end
|
127
|
+
|
128
|
+
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
|
131
|
+
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
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe :mappings do
|
140
|
+
it "parses JSON response to unmap data" do
|
141
|
+
RPXNow.expects(:post).returns %Q({"stat":"ok", "identifiers": ["http://test.myopenid.com/"]})
|
142
|
+
RPXNow.mappings(1, "x").should == ["http://test.myopenid.com/"]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe :map do
|
147
|
+
it "adds a mapping" do
|
148
|
+
RPXNow.expects(:post).returns %Q({"stat":"ok"})
|
149
|
+
RPXNow.map('http://test.myopenid.com',1, API_KEY)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe :unmap do
|
154
|
+
it "unmaps a indentifier" do
|
155
|
+
RPXNow.expects(:post).returns %Q({"stat":"ok"})
|
156
|
+
RPXNow.unmap('http://test.myopenid.com', 1, "x")
|
157
|
+
end
|
158
|
+
|
159
|
+
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"}
|
161
|
+
RPXNow.unmap('http://test.myopenid.com', 1, :api_key=>'xxx', :api_version=>300)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe :mapping_integration do
|
166
|
+
before do
|
167
|
+
@k1 = 'http://test.myopenid.com'
|
168
|
+
RPXNow.unmap(@k1, 1, API_KEY)
|
169
|
+
@k2 = 'http://test-2.myopenid.com'
|
170
|
+
RPXNow.unmap(@k2, 1, API_KEY)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "has no mappings when nothing was mapped" do
|
174
|
+
RPXNow.mappings(1,API_KEY).should == []
|
175
|
+
end
|
176
|
+
|
177
|
+
it "unmaps mapped keys" do
|
178
|
+
RPXNow.map(@k2, 1, API_KEY)
|
179
|
+
RPXNow.unmap(@k2, 1, API_KEY)
|
180
|
+
RPXNow.mappings(1, API_KEY).should == []
|
181
|
+
end
|
182
|
+
|
183
|
+
it "maps keys to a primary key and then retrieves them" do
|
184
|
+
RPXNow.map(@k1, 1, API_KEY)
|
185
|
+
RPXNow.map(@k2, 1, API_KEY)
|
186
|
+
RPXNow.mappings(1,API_KEY).sort.should == [@k2,@k1]
|
187
|
+
end
|
188
|
+
|
189
|
+
it "does not add duplicate mappings" do
|
190
|
+
RPXNow.map(@k1, 1, API_KEY)
|
191
|
+
RPXNow.map(@k1, 1, API_KEY)
|
192
|
+
RPXNow.mappings(1,API_KEY).should == [@k1]
|
193
|
+
end
|
194
|
+
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
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# ---- requirements
|
2
|
+
require 'rubygems'
|
3
|
+
require 'spec'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
|
7
|
+
|
8
|
+
|
9
|
+
# ---- rspec
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
config.mock_with :mocha
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
# ---- bugfix
|
16
|
+
#`exit?': undefined method `run?' for Test::Unit:Module (NoMethodError)
|
17
|
+
#can be solved with require test/unit but this will result in extra test-output
|
18
|
+
module Test
|
19
|
+
module Unit
|
20
|
+
def self.run?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# ---- setup environment/plugin
|
28
|
+
require File.expand_path("../init", File.dirname(__FILE__))
|
29
|
+
|
30
|
+
|
31
|
+
# ---- Helpers
|
32
|
+
def pending_it(text,&block)
|
33
|
+
it text do
|
34
|
+
pending(&block)
|
35
|
+
end
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dbalatero-rpx_now
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Grosser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: grosser.michael@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- VERSION.yml
|
35
|
+
- README.markdown
|
36
|
+
- lib/rpx_now.rb
|
37
|
+
- spec/rpx_now_spec.rb
|
38
|
+
- spec/spec_helper.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/grosser/rpx_now
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --inline-source
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Helper to simplify RPX Now user login/creation
|
66
|
+
test_files: []
|
67
|
+
|