merb-auth 0.1.0

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.
@@ -0,0 +1,166 @@
1
+ namespace :slices do
2
+ namespace :merb_auth do
3
+
4
+ desc "Install MerbAuth"
5
+ task :install => [:preflight, :setup_directories, :copy_assets, :migrate]
6
+
7
+ desc "Test for any dependencies"
8
+ task :preflight do # see slicetasks.rb
9
+ end
10
+
11
+ desc "Setup directories"
12
+ task :setup_directories do
13
+ puts "Creating directories for host application"
14
+ MerbAuth.mirrored_components.each do |type|
15
+ if File.directory?(MerbAuth.dir_for(type))
16
+ if !File.directory?(dst_path = MerbAuth.app_dir_for(type))
17
+ relative_path = dst_path.relative_path_from(Merb.root)
18
+ puts "- creating directory :#{type} #{File.basename(Merb.root) / relative_path}"
19
+ mkdir_p(dst_path)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ desc "Copy stub files to host application"
26
+ task :stubs do
27
+ puts "Copying stubs for MerbAuth - resolves any collisions"
28
+ copied, preserved = MerbAuth.mirror_stubs!
29
+ puts "- no files to copy" if copied.empty? && preserved.empty?
30
+ copied.each { |f| puts "- copied #{f}" }
31
+ preserved.each { |f| puts "! preserved override as #{f}" }
32
+ end
33
+
34
+ desc "Copy stub files and views to host application"
35
+ task :patch => [ "stubs", "freeze:views" ]
36
+
37
+ desc "Copy public assets to host application"
38
+ task :copy_assets do
39
+ puts "Copying assets for MerbAuth - resolves any collisions"
40
+ copied, preserved = MerbAuth.mirror_public!
41
+ puts "- no files to copy" if copied.empty? && preserved.empty?
42
+ copied.each { |f| puts "- copied #{f}" }
43
+ preserved.each { |f| puts "! preserved override as #{f}" }
44
+ end
45
+
46
+ desc "Migrate the database"
47
+ task :migrate do # see slicetasks.rb
48
+ end
49
+
50
+ desc "Freeze MerbAuth into your app (only merb-auth/app)"
51
+ task :freeze => [ "freeze:app" ]
52
+
53
+ namespace :freeze do
54
+
55
+ desc "Freezes MerbAuth by installing the gem into application/gems using merb-freezer"
56
+ task :gem do
57
+ begin
58
+ Object.const_get(:Freezer).freeze(ENV["GEM"] || "merb-auth", ENV["UPDATE"], ENV["MODE"] || 'rubygems')
59
+ rescue NameError
60
+ puts "! dependency 'merb-freezer' missing"
61
+ end
62
+ end
63
+
64
+ desc "Freezes MerbAuth by copying all files from merb-auth/app to your application"
65
+ task :app do
66
+ puts "Copying all merb-auth/app files to your application - resolves any collisions"
67
+ copied, preserved = MerbAuth.mirror_app!
68
+ puts "- no files to copy" if copied.empty? && preserved.empty?
69
+ copied.each { |f| puts "- copied #{f}" }
70
+ preserved.each { |f| puts "! preserved override as #{f}" }
71
+ end
72
+
73
+ desc "Freeze all views into your application for easy modification"
74
+ task :views do
75
+ puts "Copying all view templates to your application - resolves any collisions"
76
+ copied, preserved = MerbAuth.mirror_files_for :view
77
+ puts "- no files to copy" if copied.empty? && preserved.empty?
78
+ copied.each { |f| puts "- copied #{f}" }
79
+ preserved.each { |f| puts "! preserved override as #{f}" }
80
+ end
81
+
82
+ desc "Freeze all models into your application for easy modification"
83
+ task :models do
84
+ puts "Copying all models to your application - resolves any collisions"
85
+ copied, preserved = MerbAuth.mirror_files_for :model
86
+ puts "- no files to copy" if copied.empty? && preserved.empty?
87
+ copied.each { |f| puts "- copied #{f}" }
88
+ preserved.each { |f| puts "! preserved override as #{f}" }
89
+ end
90
+
91
+ desc "Freezes MerbAuth as a gem and copies over merb-auth/app"
92
+ task :app_with_gem => [:gem, :app]
93
+
94
+ desc "Freezes MerbAuth by unpacking all files into your application"
95
+ task :unpack do
96
+ puts "Unpacking MerbAuth files to your application - resolves any collisions"
97
+ copied, preserved = MerbAuth.unpack_slice!
98
+ puts "- no files to copy" if copied.empty? && preserved.empty?
99
+ copied.each { |f| puts "- copied #{f}" }
100
+ preserved.each { |f| puts "! preserved override as #{f}" }
101
+ end
102
+
103
+ end
104
+
105
+ desc "Run slice specs within the host application context"
106
+ task :spec => [ "spec:explain", "spec:default" ]
107
+
108
+ namespace :spec do
109
+
110
+ slice_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
111
+
112
+ task :explain do
113
+ puts "\nNote: By running MerbAuth specs inside the application context any\n" +
114
+ "overrides could break existing specs. This isn't always a problem,\n" +
115
+ "especially in the case of views. Use these spec tasks to check how\n" +
116
+ "well your application conforms to the original slice implementation."
117
+ end
118
+
119
+ Spec::Rake::SpecTask.new('default') do |t|
120
+ t.spec_opts = ["--format", "specdoc", "--colour"]
121
+ t.spec_files = Dir["#{slice_root}/spec/**/*_spec.rb"].sort
122
+ end
123
+
124
+ desc "Run all model specs, run a spec for a specific Model with MODEL=MyModel"
125
+ Spec::Rake::SpecTask.new('model') do |t|
126
+ t.spec_opts = ["--format", "specdoc", "--colour"]
127
+ if(ENV['MODEL'])
128
+ t.spec_files = Dir["#{slice_root}/spec/models/**/#{ENV['MODEL']}_spec.rb"].sort
129
+ else
130
+ t.spec_files = Dir["#{slice_root}/spec/models/**/*_spec.rb"].sort
131
+ end
132
+ end
133
+
134
+ desc "Run all controller specs, run a spec for a specific Controller with CONTROLLER=MyController"
135
+ Spec::Rake::SpecTask.new('controller') do |t|
136
+ t.spec_opts = ["--format", "specdoc", "--colour"]
137
+ if(ENV['CONTROLLER'])
138
+ t.spec_files = Dir["#{slice_root}/spec/controllers/**/#{ENV['CONTROLLER']}_spec.rb"].sort
139
+ else
140
+ t.spec_files = Dir["#{slice_root}/spec/controllers/**/*_spec.rb"].sort
141
+ end
142
+ end
143
+
144
+ desc "Run all view specs, run specs for a specific controller (and view) with CONTROLLER=MyController (VIEW=MyView)"
145
+ Spec::Rake::SpecTask.new('view') do |t|
146
+ t.spec_opts = ["--format", "specdoc", "--colour"]
147
+ if(ENV['CONTROLLER'] and ENV['VIEW'])
148
+ t.spec_files = Dir["#{slice_root}/spec/views/**/#{ENV['CONTROLLER']}/#{ENV['VIEW']}*_spec.rb"].sort
149
+ elsif(ENV['CONTROLLER'])
150
+ t.spec_files = Dir["#{slice_root}/spec/views/**/#{ENV['CONTROLLER']}/*_spec.rb"].sort
151
+ else
152
+ t.spec_files = Dir["#{slice_root}/spec/views/**/*_spec.rb"].sort
153
+ end
154
+ end
155
+
156
+ desc "Run all specs and output the result in html"
157
+ Spec::Rake::SpecTask.new('html') do |t|
158
+ t.spec_opts = ["--format", "html"]
159
+ t.libs = ['lib', 'server/lib' ]
160
+ t.spec_files = Dir["#{slice_root}/spec/**/*_spec.rb"].sort
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,80 @@
1
+ require 'digest/sha1'
2
+
3
+ module MerbAuth
4
+ def self.use_adapter(adapter)
5
+ require File.join(File.dirname(__FILE__), "adapter", adapter.to_s)
6
+ end
7
+
8
+ module BaseModel
9
+ def self.included(base)
10
+ base.send(:include, InstanceMethods)
11
+ base.send(:extend, ClassMethods)
12
+
13
+ base.class_eval do
14
+ attr_accessor :password, :password_confirmation
15
+ end
16
+ end
17
+
18
+ module InstanceMethods
19
+ def authenticated?(password)
20
+ crypted_password == encrypt(password)
21
+ end
22
+
23
+ # before filter
24
+ def encrypt_password
25
+ return if password.blank?
26
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{username}--") if new_record?
27
+ self.crypted_password = encrypt(password)
28
+ end
29
+
30
+ # Encrypts the password with the user salt
31
+ def encrypt(password)
32
+ self.class.encrypt(password, salt)
33
+ end
34
+
35
+ def remember_token?
36
+ remember_token_expires_at && Date.today < remember_token_expires_at
37
+ end
38
+
39
+ def remember_me_until(time)
40
+ self.remember_token_expires_at = time
41
+ self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
42
+ save
43
+ end
44
+
45
+ def remember_me_for(days)
46
+ remember_me_until (Date.today + days)
47
+ end
48
+
49
+ # These create and unset the fields required for remembering users between browser closes
50
+ # Default of 2 weeks
51
+ def remember_me
52
+ remember_me_for(14)
53
+ end
54
+
55
+ def forget_me
56
+ self.remember_token_expires_at = nil
57
+ self.remember_token = nil
58
+ self.save
59
+ end
60
+
61
+ protected
62
+ def password_required?
63
+ crypted_password.blank? || !password.blank?
64
+ end
65
+ end
66
+
67
+ module ClassMethods
68
+ # Encrypts some data with the salt.
69
+ def encrypt(password, salt)
70
+ Digest::SHA1.hexdigest("--#{salt}--#{password}--")
71
+ end
72
+
73
+ # Authenticates a user by their username and unencrypted password. Returns the user or nil.
74
+ def authenticate(username, password)
75
+ u = find_by_username(username) # need to get the salt
76
+ u && u.authenticated?(password) ? u : nil
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,18 @@
1
+ namespace :slices do
2
+ namespace :merb_auth do
3
+ # add your own tasks here
4
+
5
+ # implement this to test for structural/code dependencies
6
+ # like certain directories or availability of other files
7
+ desc "Test for any dependencies"
8
+ task :preflight do
9
+ end
10
+
11
+ # implement this to perform any database related setup steps
12
+ desc "Migrate the database"
13
+ task :migrate do
14
+ MerbAuth::User.create_db_table
15
+ end
16
+
17
+ end
18
+ end
data/lib/merb-auth.rb ADDED
@@ -0,0 +1,72 @@
1
+ if defined?(Merb::Plugins)
2
+
3
+ load_dependency 'merb-slices'
4
+ load_dependency 'merb_helpers'
5
+
6
+ require File.join(File.dirname(__FILE__), 'merb-auth', 'model')
7
+
8
+ Merb::Plugins.add_rakefiles "merb-auth/merbtasks", "merb-auth/slicetasks"
9
+
10
+ # Register the Slice for the current host application
11
+ Merb::Slices::register(__FILE__)
12
+
13
+ # Slice configuration - set this in a before_app_loads callback.
14
+ # By default a Slice uses its own layout.
15
+ Merb::Slices::config[:merb_auth][:layout] ||= :merb_auth
16
+
17
+ # Use a short name for the user model class. Set this to false to use MerbAuth::User
18
+ Merb::Slices::config[:merb_auth][:user_class_alias] = "User"
19
+
20
+ # All Slice code is expected to be namespaced inside a module
21
+ module MerbAuth
22
+ # Slice metadata
23
+ self.description = "MerbAuth is an user authentication Merb slice!"
24
+ self.version = "0.1.0"
25
+ self.author = "ctran@pragmaquest.com"
26
+
27
+ # Stub classes loaded hook - runs before LoadClasses BootLoader
28
+ # right after a slice's classes have been loaded internally.
29
+ def self.loaded
30
+ MerbAuth.use_adapter(Merb.orm_generator_scope) if Merb.orm_generator_scope != :merb_default
31
+ Object.const_set(Merb::Slices::config[:merb_auth][:user_class_alias], MerbAuth::User) if Merb::Slices::config[:merb_auth][:user_class_alias]
32
+ end
33
+
34
+ # Initialization hook - runs before AfterAppLoads BootLoader
35
+ def self.init
36
+ end
37
+
38
+ # Activation hook - runs after AfterAppLoads BootLoader
39
+ def self.activate
40
+ end
41
+
42
+ # Deactivation hook - triggered by Merb::Slices.deactivate(Bar)
43
+ def self.deactivate
44
+ end
45
+
46
+ # Setup routes inside the host application
47
+ #
48
+ # @param scope<Merb::Router::Behaviour>
49
+ # Routes will be added within this scope (namespace). In fact, any
50
+ # router behaviour is a valid namespace, so you can attach
51
+ # routes at any level of your router setup.
52
+ def self.setup_router(scope)
53
+ scope.match('/login').to(:controller => 'users', :action => 'login').name(:login)
54
+ scope.match('/logout').to(:controller => 'users', :action => 'logout').name(:logout)
55
+ scope.match('/signup').to(:controller => 'users', :action => 'signup').name(:signup)
56
+ end
57
+ end
58
+
59
+ # Setup the slice layout for MerbAuth
60
+ #
61
+ # Use MerbAuth.push_path and MerbAuth.push_app_path
62
+ # to set paths to merb-auth-level and app-level paths. Example:
63
+ #
64
+ # MerbAuth.push_path(:application, MerbAuth.root)
65
+ # MerbAuth.push_app_path(:application, Merb.root / 'slices' / 'merb-auth')
66
+ # ...
67
+ #
68
+ # Any component path that hasn't been set will default to MerbAuth.root
69
+ #
70
+ # Or just call setup_default_structure! to setup a basic Merb MVC structure.
71
+ MerbAuth.setup_default_structure!
72
+ end
@@ -0,0 +1,157 @@
1
+ body {
2
+ font-family: Arial, Verdana, sans-serif;
3
+ font-size: 14px;
4
+ background-color: #fff;
5
+ color: #000;
6
+ background-color: #fff;
7
+ }
8
+
9
+ html {
10
+ height: 100%;
11
+ }
12
+
13
+ hr {
14
+ border: 0px;
15
+ color: #ccc;
16
+ background-color: #cdcdcd;
17
+ height: 1px;
18
+ width: 100%;
19
+ text-align: left;
20
+ }
21
+
22
+ h1, h2, h3 {
23
+ color: #003399;
24
+ color: #09579A;
25
+ background-color: #fff;
26
+ font-family: Arial, Verdana, sans-serif;
27
+ font-weight: 300;
28
+ }
29
+
30
+ h1 {
31
+ font-size: 20px;
32
+ }
33
+ h2 {
34
+ font-size: 15px;
35
+ }
36
+ h3 {
37
+ font-size: 15px;
38
+ }
39
+
40
+ p {
41
+ line-height: 20px;
42
+ padding: 5px;
43
+ }
44
+
45
+ a, a:hover {
46
+ color: #0033CC;
47
+ background-color: #fff;
48
+ text-decoration: underline;
49
+ }
50
+
51
+ #container {
52
+ width: 95%;
53
+ text-align: left;
54
+ background-color: #fff;
55
+ margin-right: auto;
56
+ margin-left: auto;
57
+ }
58
+
59
+ #header-container {
60
+ width: 100%;
61
+ padding-top: 15px;
62
+ }
63
+
64
+ #header-container h1, #header-container h2 {
65
+ margin-left: 6px;
66
+ margin-bottom: 6px;
67
+ }
68
+
69
+ #main-container {
70
+ padding: 15px;
71
+ min-height: 400px;
72
+ }
73
+
74
+ #footer-container {
75
+ clear: both;
76
+ font-size: 12px;
77
+ font-family: Verdana, Arial, sans-serif;
78
+ }
79
+
80
+ #main-container ul {
81
+ margin-left: 3.0em;
82
+ }
83
+
84
+ .right {
85
+ float: right;
86
+ font-size: 100%;
87
+ margin-top: 5px;
88
+ color: #999;
89
+ background-color: #fff;
90
+ }
91
+ .left {
92
+ float: left;
93
+ font-size: 100%;
94
+ margin-top: 5px;
95
+ color: #999;
96
+ background-color: #fff;
97
+ }
98
+
99
+ a#google_signup {
100
+ background:transparent url(/images/btn-google-signup.png) no-repeat scroll 0% 0%;
101
+ color:#FFFFFF;
102
+ display:block;
103
+ font-size:14px;
104
+ height:67px;
105
+ line-height:22px;
106
+ margin:0pt;
107
+ padding:0px;
108
+ text-align:center;
109
+ text-decoration:none;
110
+ width:151px;
111
+ }
112
+
113
+ a#google_signup div {
114
+ padding-top:8px;
115
+ }
116
+
117
+ #openid_url, .openid_link {
118
+ background:#FFFFFF url(/images/openid-login.gif) no-repeat scroll 2px 50%;
119
+ padding-left:25px;
120
+ width:14.25em;
121
+ }
122
+
123
+ /** Form inputs **/
124
+ label {
125
+ font-weight: bold;
126
+ display: block;
127
+ }
128
+
129
+ #remember_me {
130
+ margin: 2px 5px 0px 0px;
131
+ float: left;
132
+ }
133
+
134
+ div.error {
135
+ background-color:#FCECEC;
136
+ }
137
+
138
+ div.error ul {
139
+ padding-bottom:20px;
140
+ }
141
+
142
+ .error {
143
+ background-color:#FCECEC;
144
+ }
145
+
146
+ .error h2 {
147
+ background: #CC0000 no-repeat scroll left center;
148
+ border-color: #CC9999;
149
+ color:#FFFFFF;
150
+ border:1px solid #CCCCCC;
151
+ font-size:14px;
152
+ padding:5px 5px 5px 10px;
153
+ }
154
+
155
+ .error li {
156
+ color: #CC0000;
157
+ }
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
2
+
3
+ prefix = 'merb-auth'
4
+
5
+ describe "Router.add_slice(:MerbAuth)" do
6
+ include Merb::Test::Rspec::RouteMatchers
7
+
8
+ before(:all) do
9
+ Merb::Router.prepare { |r| r.add_slice(:MerbAuth) } if standalone?
10
+ end
11
+
12
+ it "should have named routes for :login, :logout and :signup" do
13
+ [:login, :logout, :signup].each do |name|
14
+ url(name).should == "/#{prefix}/#{name}"
15
+ end
16
+ end
17
+
18
+ it "should route /#{prefix}/login to Session#new" do
19
+ request_to("/#{prefix}/login", :get).should route_to(MerbAuth::Users, :login)
20
+ end
21
+
22
+ it "should route /#{prefix}/login via post to Session#create" do
23
+ request_to("/#{prefix}/login", :post).should route_to(MerbAuth::Users, :login)
24
+ end
25
+
26
+ it "should route /#{prefix}/logout via delete to Session#destroy" do
27
+ request_to("/#{prefix}/logout", :delete).should route_to(MerbAuth::Users, :logout)
28
+ end
29
+ end
@@ -0,0 +1,87 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
2
+
3
+ describe "Session Controller", "index action" do
4
+ before(:all) do
5
+ Merb::Router.prepare { |r| r.add_slice(:MerbAuth) } if standalone?
6
+ end
7
+
8
+ def login_with(params = {}, &blk)
9
+ dispatch_to(MerbAuth::Users, :login, params, {:request_method => 'post'}, &blk)
10
+ end
11
+
12
+ def logout(&blk)
13
+ dispatch_to(MerbAuth::Users, :logout, {}, {}, &blk)
14
+ end
15
+
16
+ it 'logins and redirects' do
17
+ controller = login_with(:username => 'quentin', :password => 'test') {|c|
18
+ c.should_receive(:verify_login).with('quentin', 'test').and_return(mock("User", :id => 1, :name => 'quentin'))
19
+ }
20
+
21
+ controller.session[:user].should_not be_nil
22
+ controller.session[:user].should == 1
23
+ controller.should redirect_to("/")
24
+ end
25
+
26
+ it 'fails login and does not redirect' do
27
+ controller = login_with(:username => 'quentin', :password => 'bad password') {|c|
28
+ c.should_receive(:verify_login).with('quentin', 'bad password').and_return(nil)
29
+ }
30
+ controller.session[:user].should be_nil
31
+ controller.should be_successful
32
+ end
33
+
34
+ it 'logs out' do
35
+ controller = logout {|c|
36
+ c.stub!(:current_user).and_return(mock("User", :forget_me => true))
37
+ }
38
+ controller.session[:user].should be_nil
39
+ controller.should redirect
40
+ end
41
+
42
+ it 'remembers me' do
43
+ controller = login_with(:username => 'quentin', :password => 'test', :remember_me => "1") {|c|
44
+ user = mock("User", :id => 1)
45
+ c.should_receive(:verify_login).with('quentin', 'test').and_return(user)
46
+ user.should_receive(:remember_me)
47
+ user.should_receive(:remember_token).and_return("abc123")
48
+ user.should_receive(:remember_token_expires_at).and_return(Date.today)
49
+ }
50
+ controller.cookies["auth_token"].should_not be_nil
51
+ end
52
+
53
+ it 'does not remember me' do
54
+ controller = login_with(:username => 'quentin', :password => 'test', :remember_me => "0") {|c|
55
+ user = mock("User", :id => 1)
56
+ c.should_receive(:verify_login).with('quentin', 'test').and_return(user)
57
+ }
58
+ controller.cookies["auth_token"].should be_nil
59
+ end
60
+
61
+ it 'deletes token on logout' do
62
+ controller = logout {|c| controller.stub!(:current_user).and_return(@quentin) }
63
+ controller.cookies["auth_token"].should == nil
64
+ end
65
+
66
+
67
+ it 'logs in with cookie' do
68
+ controller = login_with do |c|
69
+ c.request.env[Merb::Const::HTTP_COOKIE] = "auth_token=abc123"
70
+ c.should_receive(:verify_login).and_return(nil)
71
+ user = mock("User", :id => 1, :remember_token? => true)
72
+ c.should_receive(:find_user_by_remember_token).with('abc123').and_return(user)
73
+ user.should_receive(:remember_me)
74
+ user.should_receive(:remember_token).and_return("abc123")
75
+ user.should_receive(:remember_token_expires_at).and_return(Date.today)
76
+ end
77
+ controller.should be_logged_in
78
+ end
79
+
80
+ def auth_token(token)
81
+ CGI::Cookie.new('name' => 'auth_token', 'value' => token)
82
+ end
83
+
84
+ def cookie_for(user)
85
+ auth_token user.remember_token
86
+ end
87
+ end
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
2
+
3
+ def user_hash(options = {})
4
+ { 'name' => 'ctran',
5
+ 'username' => "ctran",
6
+ 'email' => "ctran@example.com",
7
+ 'password' => "sekret",
8
+ 'password_confirmation' => "sekret"}.merge(options)
9
+ end
10
+
11
+ describe MerbAuth::Users do
12
+ before(:all) do
13
+ require 'dm-core'
14
+ DataMapper.setup(:default, 'sqlite3::memory:')
15
+ MerbAuth.use_adapter(:datamapper)
16
+
17
+ Merb::Router.prepare { |r| r.add_slice(:MerbAuth) } if standalone?
18
+ end
19
+
20
+ before(:each) do
21
+ @user = mock("User", user_hash)
22
+ MerbAuth::User.should_receive(:new).with(user_hash).and_return(@user)
23
+ end
24
+
25
+ it 'allows signup and redirect to /' do
26
+ @user.should_receive(:save).and_return(true)
27
+
28
+ controller = dispatch_to(MerbAuth::Users, :signup, {'merb_auth::user' => user_hash }, {:request_method => 'post'})
29
+ controller.assigns(:user).should == @user
30
+ controller.should redirect_to('/')
31
+ end
32
+
33
+ it 'reject signup and render errors in template' do
34
+ @user.should_receive(:save).and_return(false)
35
+ controller = dispatch_to(MerbAuth::Users, :signup, {'merb_auth::user' => user_hash}, {:request_method => 'post'}) {|c|
36
+ c.should_receive(:render)
37
+ }
38
+ controller.assigns(:user).should == @user
39
+ controller.should respond_successfully
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ module MerbAuth
4
+ class Main < Application
5
+ def index
6
+ 'index'
7
+ end
8
+ end
9
+ end
10
+
11
+ describe "MerbAuth::Main (controller)" do
12
+ before :all do
13
+ Merb::Router.prepare { |r| r.add_slice(:MerbAuth) } if standalone?
14
+ end
15
+
16
+ it "should have helper methods for dealing with public paths" do
17
+ controller = dispatch_to(MerbAuth::Main, :index)
18
+ controller.public_path_for(:image).should == "/slices/merb-auth/images"
19
+ controller.public_path_for(:javascript).should == "/slices/merb-auth/javascripts"
20
+ controller.public_path_for(:stylesheet).should == "/slices/merb-auth/stylesheets"
21
+ end
22
+
23
+ it "should have a slice-specific _template_root" do
24
+ MerbAuth::Main._template_root.should == MerbAuth.dir_for(:view)
25
+ MerbAuth::Main._template_root.should == MerbAuth::Application._template_root
26
+ end
27
+ end