merb-auth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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