acts_as_current 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.
- data/.gitignore +2 -0
- data/MIT-LICENSE +26 -0
- data/README.rdoc +113 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/acts_as_current.gemspec +64 -0
- data/init.rb +1 -0
- data/lib/acts_as_current.rb +12 -0
- data/lib/acts_as_current/base.rb +59 -0
- data/lib/acts_as_current/class_methods.rb +39 -0
- data/lib/acts_as_current/instance_methods.rb +28 -0
- data/rails/init.rb +1 -0
- data/test/acts_as_current/base_test.rb +37 -0
- data/test/acts_as_current/simple_test.rb +86 -0
- data/test/acts_as_current/sti_test.rb +86 -0
- data/test/test_helper.rb +110 -0
- metadata +104 -0
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2010 Coroutine LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
--------------------------------------------------------------------
|
23
|
+
|
24
|
+
acts_as_current was inspired by sentient_user.
|
25
|
+
|
26
|
+
Copyright (c) 2009 bokmann, also released under the MIT license.
|
data/README.rdoc
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
= acts_as_current
|
2
|
+
|
3
|
+
This library extends ActiveRecord classes so they can carry a reference to the
|
4
|
+
instance defined as current for the given request.
|
5
|
+
|
6
|
+
<tt>acts_as_current</tt> can be applied to any model, but it's most common use case is
|
7
|
+
storing the authenticated user on the corresponding User model. Doing so allows other models
|
8
|
+
and observers to access information about the user who made the request. This is particularly
|
9
|
+
useful for auditing, versioning, etc.
|
10
|
+
|
11
|
+
Here's how you'd set up the user example.
|
12
|
+
|
13
|
+
First, extend the User model.
|
14
|
+
|
15
|
+
class User < ActiveRecord::Base
|
16
|
+
acts_as_current
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
Then, tell your application controller to set the current user before all requests. (The controller
|
21
|
+
method can obviously be anything you want. Here, we use <tt>:current_user</tt> because that's our
|
22
|
+
convention at Coroutine.)
|
23
|
+
|
24
|
+
class ApplicationController < ActionController::Base
|
25
|
+
|
26
|
+
before_filter { |controller| User.current = controller.send(:current_user) }
|
27
|
+
|
28
|
+
def current_user
|
29
|
+
# return user or nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
Finally, in your observer, you can retrieve the value of current_user by using the accessor mixed
|
35
|
+
into the model class.
|
36
|
+
|
37
|
+
class AuditObserver < ActiveRecord::Observer
|
38
|
+
observe :account, :balance
|
39
|
+
|
40
|
+
def after_update(record)
|
41
|
+
AuditTrail.new({ :record => record, :action => :update, :whodunnit => User.current })
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
== Design Notes
|
49
|
+
|
50
|
+
<tt>acts_as_current</tt> uses the hash Thread.current to store the current value for each class
|
51
|
+
extended by the library. Many consider this technique a hack, but for now, it is the only thread
|
52
|
+
safe way to store such data. By coding the technique as a model extension, <tt>acts_as_current</tt>
|
53
|
+
abstracts reads and writes against Thread.current, greatly reducing the likelihood of
|
54
|
+
conflicts and errors.
|
55
|
+
|
56
|
+
We think the real benefits outweigh the perceived risks.
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
== Helpful Links
|
62
|
+
|
63
|
+
* <b>Repository:</b> http://github.com/coroutine/acts_as_current
|
64
|
+
* <b>Gem:</b> http://rubygems.org/gems/acts_as_current
|
65
|
+
* <b>Authors:</b> http://coroutine.com
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
== Installation & Generators
|
71
|
+
|
72
|
+
Install me from RubyGems.org and add a gem dependency in your configuration file.
|
73
|
+
|
74
|
+
$ sudo gem install acts_as_current
|
75
|
+
|
76
|
+
Or install me as a plugin.
|
77
|
+
|
78
|
+
$ script/plugin install git://github.com/coroutine/acts_as_current.git
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
== Simple Controller Recipe
|
84
|
+
|
85
|
+
He's an example of how you might set a current instance on a User class via a
|
86
|
+
current_user method, using a before filter in the application controller.
|
87
|
+
|
88
|
+
before_filter { |controller| User.current = controller.send(:current_user) }
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
== Why Doesn't the Library Handle the Controller Logic For Me?
|
94
|
+
|
95
|
+
Primarily, because we think ActiveRecord extensions have no business altering
|
96
|
+
controller logic. Doing so couples aspects of your application that Rails is going
|
97
|
+
out of its way to separate.
|
98
|
+
|
99
|
+
But also because the before_filter syntax is already configurable and extremely expressive.
|
100
|
+
Writing the before filter is no harder than writing a module include statement, but the former
|
101
|
+
tells a code maintainer <b>considerably</b> more information than the latter.
|
102
|
+
|
103
|
+
In summary, suck it up and write the controller code yourself. :-)
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
== License
|
109
|
+
|
110
|
+
Copyright (c) 2010 {Coroutine LLC}[http://coroutine.com], released under the MIT license.
|
111
|
+
|
112
|
+
acts_as_current was inspired by sentient_user, copyright (c) 2009 bokmann, also released under the
|
113
|
+
MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'jeweler'
|
5
|
+
|
6
|
+
|
7
|
+
desc 'Default: run tests.'
|
8
|
+
task :default => [:test]
|
9
|
+
|
10
|
+
|
11
|
+
desc 'Test the plugin.'
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
desc 'Generate documentation for the plugin.'
|
20
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
21
|
+
rdoc.rdoc_dir = 'rdoc'
|
22
|
+
rdoc.title = 'acts_as_current'
|
23
|
+
rdoc.options << '--line-numbers --inline-source'
|
24
|
+
rdoc.rdoc_files.include('README')
|
25
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
begin
|
30
|
+
Jeweler::Tasks.new do |gemspec|
|
31
|
+
gemspec.authors = ["Coroutine", "John Dugan"]
|
32
|
+
gemspec.description = "This acts_as extension modifies ActiveRecord classes so they can carry a reference to the instance defined as current for the given request. The library is particularly useful for providing the authenticated user object to models."
|
33
|
+
gemspec.email = "gem@coroutine.com"
|
34
|
+
gemspec.homepage = "http://github.com/coroutine/acts_as_current"
|
35
|
+
gemspec.name = "acts_as_current"
|
36
|
+
gemspec.summary = "Gem version of acts_as_current Rails plugin."
|
37
|
+
|
38
|
+
gemspec.add_dependency("activerecord")
|
39
|
+
gemspec.add_development_dependency("activesupport")
|
40
|
+
gemspec.files.include("lib/**/*.rb")
|
41
|
+
end
|
42
|
+
Jeweler::GemcutterTasks.new
|
43
|
+
rescue LoadError
|
44
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
45
|
+
end
|
46
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{acts_as_current}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Coroutine", "John Dugan"]
|
12
|
+
s.date = %q{2010-04-06}
|
13
|
+
s.description = %q{This acts_as extension modifies ActiveRecord classes so they can carry a reference to the instance defined as current for the given request. The library is particularly useful for providing the authenticated user object to models.}
|
14
|
+
s.email = %q{gem@coroutine.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"MIT-LICENSE",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"acts_as_current.gemspec",
|
25
|
+
"init.rb",
|
26
|
+
"lib/acts_as_current.rb",
|
27
|
+
"lib/acts_as_current/base.rb",
|
28
|
+
"lib/acts_as_current/class_methods.rb",
|
29
|
+
"lib/acts_as_current/instance_methods.rb",
|
30
|
+
"rails/init.rb",
|
31
|
+
"test/acts_as_current/base_test.rb",
|
32
|
+
"test/acts_as_current/simple_test.rb",
|
33
|
+
"test/acts_as_current/sti_test.rb",
|
34
|
+
"test/test_helper.rb"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/coroutine/acts_as_current}
|
37
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.6}
|
40
|
+
s.summary = %q{Gem version of acts_as_current Rails plugin.}
|
41
|
+
s.test_files = [
|
42
|
+
"test/acts_as_current/base_test.rb",
|
43
|
+
"test/acts_as_current/simple_test.rb",
|
44
|
+
"test/acts_as_current/sti_test.rb",
|
45
|
+
"test/test_helper.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<activesupport>, [">= 0"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
57
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
61
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init.rb"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# external gems
|
2
|
+
require "active_record"
|
3
|
+
|
4
|
+
|
5
|
+
# acts_as_current extension
|
6
|
+
require File.dirname(__FILE__) + "/acts_as_current/base"
|
7
|
+
require File.dirname(__FILE__) + "/acts_as_current/class_methods"
|
8
|
+
require File.dirname(__FILE__) + "/acts_as_current/instance_methods"
|
9
|
+
|
10
|
+
|
11
|
+
# add extensions to active record
|
12
|
+
::ActiveRecord::Base.send(:include, Coroutine::ActsAsCurrent::Base)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Coroutine
|
2
|
+
|
3
|
+
# This module is an acts_as extension that teaches an ActiveRecord model how to provide a reference
|
4
|
+
# to the instance owned by the current thread through a class method.
|
5
|
+
#
|
6
|
+
# The module includes class methods and instance methods that simplify the process of storing the
|
7
|
+
# current reference in a thread safe manner.
|
8
|
+
#
|
9
|
+
# Because acts_as_current relies on the Thread.current hash, it should probably be used sparingly.
|
10
|
+
#
|
11
|
+
module ActsAsCurrent
|
12
|
+
|
13
|
+
# This module provides the base functionality for the acts_as_current extension. It declares the
|
14
|
+
# class method acts_as_current and handles including all necessary sub modules when the class
|
15
|
+
# method is invoked.
|
16
|
+
#
|
17
|
+
module Base
|
18
|
+
|
19
|
+
def self.included(klass) #:nodoc:
|
20
|
+
klass.class_eval do
|
21
|
+
|
22
|
+
# This class method extends an ActiveRecord class with behavior appropriate for providing a
|
23
|
+
# current instance to the request.
|
24
|
+
#
|
25
|
+
# Including this method in a model definition adds two public class methods and two public
|
26
|
+
# instance methods to the model. See modules below for method defintions. Here's a simple
|
27
|
+
# skeleton that demonstrates the resulting interface.
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# class MyClass < ActiveRecord::Base
|
31
|
+
#
|
32
|
+
# def self.current
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# def self.current=(instance)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def current?
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# def current!
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
def self.acts_as_current
|
47
|
+
|
48
|
+
# mixin methods
|
49
|
+
extend Coroutine::ActsAsCurrent::ClassMethods
|
50
|
+
include Coroutine::ActsAsCurrent::InstanceMethods
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Coroutine
|
2
|
+
module ActsAsCurrent
|
3
|
+
|
4
|
+
# This module defines methods that will be mixed into the class definition when acts_as_current
|
5
|
+
# is invoked.
|
6
|
+
#
|
7
|
+
# The notation used below assumes the module will be invoked using the :extend method, ensuring
|
8
|
+
# the wrapping scope is the class object.
|
9
|
+
#
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
# This method returns the reference to the instance defined as current.
|
13
|
+
#
|
14
|
+
def current
|
15
|
+
Thread.current[acts_as_current_symbol]
|
16
|
+
end
|
17
|
+
|
18
|
+
# This method sets the reference to the instance defined as current.
|
19
|
+
#
|
20
|
+
def current=(instance)
|
21
|
+
unless (instance.is_a?(self) || instance.nil?)
|
22
|
+
raise(ArgumentError, "The method expected an instance of class '#{name}', but instead was given #{instance.inspect}")
|
23
|
+
end
|
24
|
+
Thread.current[acts_as_current_symbol] = instance
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# This method returns the singularized, underscored symbol for the class.
|
31
|
+
#
|
32
|
+
def acts_as_current_symbol
|
33
|
+
name.underscore.to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Coroutine
|
2
|
+
module ActsAsCurrent
|
3
|
+
|
4
|
+
# This module defines methods that will be mixed into the instance when acts_as_current is invoked.
|
5
|
+
#
|
6
|
+
# The notation used below assumes the module will be invoked using the :include method, ensuring
|
7
|
+
# the wrapping scope is the instance object.
|
8
|
+
#
|
9
|
+
module InstanceMethods
|
10
|
+
|
11
|
+
# This method returns a boolean indicating whether or not the instance is defined
|
12
|
+
# as the current instance of the class.
|
13
|
+
#
|
14
|
+
def current?
|
15
|
+
!self.class.current.nil? && self.id == self.class.current.id
|
16
|
+
end
|
17
|
+
|
18
|
+
# This method forces the instance to become the defined current instance of the
|
19
|
+
# class.
|
20
|
+
#
|
21
|
+
def current!
|
22
|
+
self.class.current = self
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "acts_as_current"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#---------------------------------------------------------
|
2
|
+
# Requirements
|
3
|
+
#---------------------------------------------------------
|
4
|
+
|
5
|
+
# all generic stuff required by test helper
|
6
|
+
require "test/test_helper"
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
#---------------------------------------------------------
|
11
|
+
# Tests
|
12
|
+
#---------------------------------------------------------
|
13
|
+
|
14
|
+
class ActsAsCurrentBaseTest < ActiveSupport::TestCase
|
15
|
+
|
16
|
+
#---------------------------------------------
|
17
|
+
# setup and teardown delegations
|
18
|
+
#---------------------------------------------
|
19
|
+
|
20
|
+
def setup
|
21
|
+
setup_db
|
22
|
+
end
|
23
|
+
def teardown
|
24
|
+
teardown_db
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#---------------------------------------------
|
30
|
+
# test composition
|
31
|
+
#---------------------------------------------
|
32
|
+
|
33
|
+
def test_composition_of_class
|
34
|
+
assert_respond_to ::ActiveRecord::Base, :acts_as_current
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#---------------------------------------------------------
|
2
|
+
# Requirements
|
3
|
+
#---------------------------------------------------------
|
4
|
+
|
5
|
+
# all generic stuff required by test helper
|
6
|
+
require "test/test_helper"
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
#---------------------------------------------------------
|
11
|
+
# Tests
|
12
|
+
#---------------------------------------------------------
|
13
|
+
|
14
|
+
class ActsAsCurrentSimpleTest < ActiveSupport::TestCase
|
15
|
+
|
16
|
+
#---------------------------------------------
|
17
|
+
# setup and teardown delegations
|
18
|
+
#---------------------------------------------
|
19
|
+
|
20
|
+
def setup
|
21
|
+
setup_db
|
22
|
+
end
|
23
|
+
def teardown
|
24
|
+
teardown_db
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#---------------------------------------------
|
30
|
+
# test composition
|
31
|
+
#---------------------------------------------
|
32
|
+
|
33
|
+
def test_composition_of_class
|
34
|
+
assert User.respond_to?(:current)
|
35
|
+
assert User.respond_to?(:current=)
|
36
|
+
|
37
|
+
assert User.respond_to?(:acts_as_current_symbol, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def test_composition_of_instance
|
42
|
+
seed_users
|
43
|
+
@one = User.first
|
44
|
+
|
45
|
+
assert @one.respond_to?(:current?)
|
46
|
+
assert @one.respond_to?(:current!)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
#---------------------------------------------
|
52
|
+
# test symbol method
|
53
|
+
#---------------------------------------------
|
54
|
+
|
55
|
+
def test_symbol_method
|
56
|
+
assert_equal :user, User.send(:acts_as_current_symbol) # this notation bypasses privacy
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
#---------------------------------------------
|
62
|
+
# test current methods
|
63
|
+
#---------------------------------------------
|
64
|
+
|
65
|
+
def test_current_methods
|
66
|
+
seed_users
|
67
|
+
@one = User.first
|
68
|
+
@two = User.last
|
69
|
+
|
70
|
+
# starts as nil
|
71
|
+
assert User.current.nil?
|
72
|
+
|
73
|
+
# set current to one explicitly (instances agree)
|
74
|
+
User.current = @one
|
75
|
+
assert_equal User.current, @one
|
76
|
+
assert @one.current?
|
77
|
+
assert !@two.current?
|
78
|
+
|
79
|
+
# set current to two by conversion (instances agree)
|
80
|
+
@two.current!
|
81
|
+
assert_equal User.current, @two
|
82
|
+
assert !@one.current?
|
83
|
+
assert @two.current?
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#---------------------------------------------------------
|
2
|
+
# Requirements
|
3
|
+
#---------------------------------------------------------
|
4
|
+
|
5
|
+
# all generic stuff required by test helper
|
6
|
+
require "test/test_helper"
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
#---------------------------------------------------------
|
11
|
+
# Tests
|
12
|
+
#---------------------------------------------------------
|
13
|
+
|
14
|
+
class ActsAsCurrentStiTest < ActiveSupport::TestCase
|
15
|
+
|
16
|
+
#---------------------------------------------
|
17
|
+
# setup and teardown delegations
|
18
|
+
#---------------------------------------------
|
19
|
+
|
20
|
+
def setup
|
21
|
+
setup_db
|
22
|
+
end
|
23
|
+
def teardown
|
24
|
+
teardown_db
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#---------------------------------------------
|
30
|
+
# test composition
|
31
|
+
#---------------------------------------------
|
32
|
+
|
33
|
+
def test_composition_of_class
|
34
|
+
assert BillingFrequency.respond_to?(:current)
|
35
|
+
assert BillingFrequency.respond_to?(:current=)
|
36
|
+
|
37
|
+
assert BillingFrequency.respond_to?(:acts_as_current_symbol, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def test_composition_of_instance
|
42
|
+
seed_billing_frequencies
|
43
|
+
@one = BillingFrequency.first
|
44
|
+
|
45
|
+
assert @one.respond_to?(:current?)
|
46
|
+
assert @one.respond_to?(:current!)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
#---------------------------------------------
|
52
|
+
# test symbol method
|
53
|
+
#---------------------------------------------
|
54
|
+
|
55
|
+
def test_symbol_method
|
56
|
+
assert_equal :billing_frequency, BillingFrequency.send(:acts_as_current_symbol) # this notation bypasses privacy
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
#---------------------------------------------
|
62
|
+
# test current methods
|
63
|
+
#---------------------------------------------
|
64
|
+
|
65
|
+
def test_current_methods
|
66
|
+
seed_billing_frequencies
|
67
|
+
@one = BillingFrequency.first
|
68
|
+
@two = BillingFrequency.last
|
69
|
+
|
70
|
+
# starts as nil
|
71
|
+
assert BillingFrequency.current.nil?
|
72
|
+
|
73
|
+
# set current to one explicitly (instances agree)
|
74
|
+
BillingFrequency.current = @one
|
75
|
+
assert_equal BillingFrequency.current, @one
|
76
|
+
assert @one.current?
|
77
|
+
assert !@two.current?
|
78
|
+
|
79
|
+
# set current to two by conversion (instances agree)
|
80
|
+
@two.current!
|
81
|
+
assert_equal BillingFrequency.current, @two
|
82
|
+
assert !@one.current?
|
83
|
+
assert @two.current?
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#----------------------------------------------------------
|
2
|
+
# Requirements
|
3
|
+
#----------------------------------------------------------
|
4
|
+
|
5
|
+
# rails stuff
|
6
|
+
require "rubygems"
|
7
|
+
require "active_record"
|
8
|
+
require "active_support"
|
9
|
+
require "active_support/test_case"
|
10
|
+
require "test/unit"
|
11
|
+
|
12
|
+
# the plugin itself
|
13
|
+
require "#{File.dirname(__FILE__)}/../init"
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
#---------------------------------------------------------
|
18
|
+
# Database config
|
19
|
+
#---------------------------------------------------------
|
20
|
+
|
21
|
+
# establish db connection
|
22
|
+
begin
|
23
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
24
|
+
rescue ArgumentError
|
25
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# define and seed tables
|
30
|
+
def setup_db
|
31
|
+
ActiveRecord::Schema.define(:version => 1) do
|
32
|
+
create_table :users do |t|
|
33
|
+
t.string :email, :limit => 255
|
34
|
+
t.string :crypted_password, :limit => 255
|
35
|
+
|
36
|
+
t.timestamps
|
37
|
+
end
|
38
|
+
add_index :users, :email, :unique
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveRecord::Schema.define(:version => 1) do
|
42
|
+
create_table :labels do |t|
|
43
|
+
t.string :type, :limit => 255
|
44
|
+
t.string :system_label, :limit => 255
|
45
|
+
t.string :label, :limit => 255
|
46
|
+
|
47
|
+
t.timestamps
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# seed users
|
54
|
+
def seed_users
|
55
|
+
User.create!({ :email => "user_1@coroutine.com", :crypted_password => "not_crypted_but_does_not_matter_here" })
|
56
|
+
User.create!({ :email => "user_2@coroutine.com", :crypted_password => "not_crypted_but_does_not_matter_here" })
|
57
|
+
end
|
58
|
+
|
59
|
+
# seed billing frequencies
|
60
|
+
def seed_billing_frequencies
|
61
|
+
BillingFrequency.create!({ :system_label => "MONTHLY", :label => "Monthly" })
|
62
|
+
BillingFrequency.create!({ :system_label => "YEARLY", :label => "Yearly" })
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# drop all tables
|
67
|
+
def teardown_db
|
68
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
69
|
+
ActiveRecord::Base.connection.drop_table(table)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
#---------------------------------------------------------
|
76
|
+
# Model definitions
|
77
|
+
#---------------------------------------------------------
|
78
|
+
|
79
|
+
# users (simple case)
|
80
|
+
class User < ActiveRecord::Base
|
81
|
+
acts_as_current
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# labels (sti base)
|
86
|
+
class Label < ActiveRecord::Base
|
87
|
+
acts_as_current
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# billing frequencies (sti extension)
|
92
|
+
class BillingFrequency < Label
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
#----------------------------------------------------------
|
98
|
+
# Define global methods
|
99
|
+
#----------------------------------------------------------
|
100
|
+
|
101
|
+
class ActiveSupport::TestCase
|
102
|
+
|
103
|
+
# This method allows us to use a convenient notation for testing
|
104
|
+
# model validations.
|
105
|
+
def assert_not_valid(object, msg="Object is valid when it should be invalid")
|
106
|
+
assert(!object.valid?, msg)
|
107
|
+
end
|
108
|
+
alias :assert_invalid :assert_not_valid
|
109
|
+
|
110
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_current
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Coroutine
|
13
|
+
- John Dugan
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-04-06 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activerecord
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activesupport
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :development
|
44
|
+
version_requirements: *id002
|
45
|
+
description: This acts_as extension modifies ActiveRecord classes so they can carry a reference to the instance defined as current for the given request. The library is particularly useful for providing the authenticated user object to models.
|
46
|
+
email: gem@coroutine.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.rdoc
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- MIT-LICENSE
|
56
|
+
- README.rdoc
|
57
|
+
- Rakefile
|
58
|
+
- VERSION
|
59
|
+
- acts_as_current.gemspec
|
60
|
+
- init.rb
|
61
|
+
- lib/acts_as_current.rb
|
62
|
+
- lib/acts_as_current/base.rb
|
63
|
+
- lib/acts_as_current/class_methods.rb
|
64
|
+
- lib/acts_as_current/instance_methods.rb
|
65
|
+
- rails/init.rb
|
66
|
+
- test/acts_as_current/base_test.rb
|
67
|
+
- test/acts_as_current/simple_test.rb
|
68
|
+
- test/acts_as_current/sti_test.rb
|
69
|
+
- test/test_helper.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://github.com/coroutine/acts_as_current
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.3.6
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: Gem version of acts_as_current Rails plugin.
|
100
|
+
test_files:
|
101
|
+
- test/acts_as_current/base_test.rb
|
102
|
+
- test/acts_as_current/simple_test.rb
|
103
|
+
- test/acts_as_current/sti_test.rb
|
104
|
+
- test/test_helper.rb
|