dm-actionstamps 0.0.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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +180 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/dm-actionstamps.gemspec +56 -0
- data/lib/dm-actionstamps.rb +16 -0
- data/lib/dm-actionstamps/actionstamps.rb +152 -0
- data/lib/dm-actionstamps/version.rb +5 -0
- data/spec/integration/actionstamps_spec.rb +576 -0
- data/spec/spec_helper.rb +29 -0
- metadata +88 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 kematzy
|
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.
|
data/README.rdoc
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
= dm-actionstamps
|
2
|
+
|
3
|
+
A DataMapper plugin that works similar to the dm-timestamps in that it 'automagically' adds/updates the
|
4
|
+
created_?, updated_? fields of your models.
|
5
|
+
|
6
|
+
This is a completely rewritten version of the "rlivesey's"[http://github.com/rlivsey/] <tt>"dm-userstamp"[http://github.com/rlivsey/dm-userstamp]</tt> gem.
|
7
|
+
|
8
|
+
It was rewritten and given a new new when I made more dynamic in nature than dm-userstamp.
|
9
|
+
|
10
|
+
|
11
|
+
== Installation
|
12
|
+
|
13
|
+
$ (sudo)? gem install dm-actionstamps
|
14
|
+
|
15
|
+
<b>NB! Depends upon the whole DataMapper suite being installed, and has ONLY been tested with DM 0.10.2.</b>
|
16
|
+
|
17
|
+
|
18
|
+
== Getting Started
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Require <tt>dm-actionstamps</tt> in your app.
|
23
|
+
|
24
|
+
require 'dm-core' # must be required first
|
25
|
+
require 'dm-actionstamps'
|
26
|
+
|
27
|
+
|
28
|
+
Lets say we have a User class and we want to track the user actions in our other models. Just do as follows:
|
29
|
+
|
30
|
+
class User
|
31
|
+
include DataMapper::Resource
|
32
|
+
property :id, Serial
|
33
|
+
property :name, String
|
34
|
+
|
35
|
+
provides_actionstamps
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
By declaring <tt>:provides_actionstamps</tt> in your User model, you get the following functionality free.
|
41
|
+
|
42
|
+
User.current_user = new user...
|
43
|
+
|
44
|
+
User.current_user => retrieves the current_user
|
45
|
+
|
46
|
+
|
47
|
+
You can then use it as follows:
|
48
|
+
|
49
|
+
@user = User.create(:id => 99, :name => "Joe")
|
50
|
+
|
51
|
+
User.current_user = @user
|
52
|
+
|
53
|
+
|
54
|
+
# retrieve the current user info.
|
55
|
+
User.current_user.id => returns 99
|
56
|
+
|
57
|
+
|
58
|
+
OK, so far not so exciting, but lets say we have an Article class, and we want to track the User that
|
59
|
+
created the Article and the last User that updated the Article. It's easy too:
|
60
|
+
|
61
|
+
class Article
|
62
|
+
include DataMapper::Resource
|
63
|
+
property :id, Serial
|
64
|
+
property :title, String
|
65
|
+
...<snip>
|
66
|
+
|
67
|
+
actionstamps :by, User
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
Once you have your Article model we can create our Articles just as normal:
|
72
|
+
|
73
|
+
@article = Article.create(:title => 'Example 1')
|
74
|
+
|
75
|
+
|
76
|
+
The instance of <tt>Article.get(1)</tt> now has the following things for free:
|
77
|
+
|
78
|
+
* a <tt>:created_by</tt> attribute with the value of <tt>User.current_user.id</tt> if set. Default value is <tt>nil</tt>.
|
79
|
+
|
80
|
+
* a <tt>:updated_by</tt> attribute with the value of <tt>User.current_user.id</tt> if set. Default value is <tt>nil</tt>.
|
81
|
+
|
82
|
+
|
83
|
+
So given this usage scenario:
|
84
|
+
|
85
|
+
@user = User.create(:id => 99, :name => "Joe")
|
86
|
+
User.current_user = @user
|
87
|
+
|
88
|
+
@article = Article.create(:title => 'Example 2')
|
89
|
+
|
90
|
+
|
91
|
+
The Article instance should have the following:
|
92
|
+
|
93
|
+
@article.created_by => 99
|
94
|
+
@article.updated_by => 99
|
95
|
+
|
96
|
+
|
97
|
+
== Customisations
|
98
|
+
|
99
|
+
<tt>dm-actionstamps</tt> plugin/gem was created because I needed to track the actions of Client, Staff and other 'User' models,
|
100
|
+
and the <tt>"dm-userstamp"[http://github.com/rlivsey/dm-userstamp]</tt> gem was hardcoded to the <tt>User</tt> model.
|
101
|
+
|
102
|
+
To support more flexible declarations, I have separated out the functionality into two parts:
|
103
|
+
|
104
|
+
* Provider Model
|
105
|
+
* Receiver Model
|
106
|
+
|
107
|
+
|
108
|
+
The Provider Model provides the actionstamps, and can be declared like this:
|
109
|
+
|
110
|
+
class Client
|
111
|
+
include DataMapper::Resource
|
112
|
+
property :id, Serial
|
113
|
+
property :name, String
|
114
|
+
|
115
|
+
provides_actionstamps
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
In difference to the examples above, the <tt>current_?</tt> methods takes the name of the Model that was given the provider status (via the <tt>:provides_actionstamps</tt> method):
|
120
|
+
|
121
|
+
Client.current_client = Client.create(:id => 88, :name => "Happy")
|
122
|
+
|
123
|
+
Client.current_client => returns the Client
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
The Receiver Model receives the actionstamps and can be declared like this:
|
128
|
+
|
129
|
+
|
130
|
+
class Bill
|
131
|
+
include DataMapper::Resource
|
132
|
+
property :id, Serial
|
133
|
+
property :amount, Integer
|
134
|
+
...<snip>
|
135
|
+
|
136
|
+
actionstamps :by, Client
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
So when we create a new instance of Bill, we get the values from the Client.current_client method:
|
142
|
+
|
143
|
+
@bill = Bill.create(:amount => "100")
|
144
|
+
|
145
|
+
@bill.created_by => 88
|
146
|
+
|
147
|
+
|
148
|
+
== TODO
|
149
|
+
|
150
|
+
* Contemplate if there is ever a scenario where you need to track two different models updating the same record? (Seller vs Buyers ?)
|
151
|
+
|
152
|
+
* Think of some clever way to automagically set "User.current_user = @user" when you load or create a new User in your enclosing application.
|
153
|
+
|
154
|
+
* Any other improvements that you can think of?
|
155
|
+
|
156
|
+
|
157
|
+
== RTFM
|
158
|
+
|
159
|
+
For a better understanding of this gem/plugin, make sure you study the '<tt>dm-actionstamps/spec/integration/actionstamps_spec.rb</tt>' file.
|
160
|
+
|
161
|
+
|
162
|
+
== Errors / Bugs
|
163
|
+
|
164
|
+
If something is not behaving intuitively, it is a bug, and should be reported.
|
165
|
+
Report it here: http://github.com/kematzy/dm-actionstamps/issues
|
166
|
+
|
167
|
+
== Note on Patches/Pull Requests
|
168
|
+
|
169
|
+
* Fork the project.
|
170
|
+
* Make your feature addition or bug fix.
|
171
|
+
* Add tests for it. This is important so I don't break it in a
|
172
|
+
future version unintentionally.
|
173
|
+
* Commit, do not mess with rakefile, version, or history.
|
174
|
+
* (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
175
|
+
* Send me a pull request. Bonus points for topic branches.
|
176
|
+
|
177
|
+
== Copyright
|
178
|
+
|
179
|
+
Copyright (c) 2010 kematzy. Released under the MIT license.
|
180
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "dm-actionstamps"
|
8
|
+
gem.summary = %Q{A DataMapper plugin that automatically adds/updates the created_?, updated_? fields of your models.}
|
9
|
+
gem.description = %Q{A DataMapper plugin that works similar to the dm-timestamps in that it 'automagically' adds/updates the created_?, updated_? fields of your models.}
|
10
|
+
gem.email = "kematzy@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/kematzy/dm-actionstamps"
|
12
|
+
gem.authors = ["kematzy"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_opts = ["--color", "--format", "nested", "--require", "spec/spec_helper.rb"]
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "dm-actionstamps #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,56 @@
|
|
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{dm-actionstamps}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["kematzy"]
|
12
|
+
s.date = %q{2010-05-17}
|
13
|
+
s.description = %q{A DataMapper plugin that works similar to the dm-timestamps in that it 'automagically' adds/updates the created_?, updated_? fields of your models.}
|
14
|
+
s.email = %q{kematzy@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"dm-actionstamps.gemspec",
|
27
|
+
"lib/dm-actionstamps.rb",
|
28
|
+
"lib/dm-actionstamps/actionstamps.rb",
|
29
|
+
"lib/dm-actionstamps/version.rb",
|
30
|
+
"spec/integration/actionstamps_spec.rb",
|
31
|
+
"spec/spec_helper.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/kematzy/dm-actionstamps}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.6}
|
37
|
+
s.summary = %q{A DataMapper plugin that automatically adds/updates the created_?, updated_? fields of your models.}
|
38
|
+
s.test_files = [
|
39
|
+
"spec/integration/actionstamps_spec.rb",
|
40
|
+
"spec/spec_helper.rb"
|
41
|
+
]
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
45
|
+
s.specification_version = 3
|
46
|
+
|
47
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
48
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
49
|
+
else
|
50
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
51
|
+
end
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
# Need to import datamapper and other gems
|
3
|
+
# require 'rubygems' # read [ http://gist.github.com/54177 ] to understand why this line is commented out
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
# Add all external dependencies for the plugin here
|
7
|
+
# gem 'dm-core', '~> 0.10.2'
|
8
|
+
require 'dm-core'
|
9
|
+
|
10
|
+
# Require plugin-files
|
11
|
+
require Pathname(__FILE__).dirname.expand_path / 'dm-actionstamps' / 'actionstamps.rb'
|
12
|
+
|
13
|
+
DataMapper::Model.append_extensions(DataMapper::Actionstamps)
|
14
|
+
# DataMapper::Model.append_inclusions(DataMapper::Actionstamps)
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
|
2
|
+
require 'dm-core'
|
3
|
+
require 'extlib/inflection'
|
4
|
+
|
5
|
+
module DataMapper
|
6
|
+
module Actionstamps
|
7
|
+
|
8
|
+
##
|
9
|
+
# Provider method, used to setup the +current_user+ information.
|
10
|
+
#
|
11
|
+
# ==== Examples
|
12
|
+
#
|
13
|
+
# class User
|
14
|
+
# <snip...>
|
15
|
+
#
|
16
|
+
# provides_actionstamps
|
17
|
+
#
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# => creates the :current_user & :current_user= methods
|
21
|
+
#
|
22
|
+
# class Client
|
23
|
+
# <snip...>
|
24
|
+
#
|
25
|
+
# provides_actionstamps
|
26
|
+
#
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# => creates the :current_client & :current_client= methods
|
30
|
+
#
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def provides_actionstamps
|
34
|
+
@actionstamps_class = self
|
35
|
+
|
36
|
+
extend DataMapper::Actionstamps::ClassMethods
|
37
|
+
|
38
|
+
class_eval(<<-END, __FILE__, __LINE__)
|
39
|
+
def self.current_#{name.downcase}=(user)
|
40
|
+
Thread.current["#{name.downcase}_#{self.object_id}_actionstamp"] = user
|
41
|
+
end
|
42
|
+
def self.current_#{name.downcase}
|
43
|
+
Thread.current["#{name.downcase}_#{self.object_id}_actionstamp"]
|
44
|
+
end
|
45
|
+
END
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
##
|
50
|
+
# The Receiver Model receives the actionstamps and defines the
|
51
|
+
#
|
52
|
+
# ==== Examples
|
53
|
+
#
|
54
|
+
# class Bill
|
55
|
+
# include DataMapper::Resource
|
56
|
+
# property :id, Serial
|
57
|
+
# property :amount, Integer
|
58
|
+
# ...<snip>
|
59
|
+
#
|
60
|
+
# actionstamps :by, Client
|
61
|
+
#
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# => creates the :created_by and :updated_by fields.
|
65
|
+
#
|
66
|
+
# actionstamps :by_id, Author
|
67
|
+
#
|
68
|
+
#
|
69
|
+
# @api public/private
|
70
|
+
def actionstamps(*args)
|
71
|
+
# set default args if none passed in
|
72
|
+
args = [:by, ::User ] if args.empty?
|
73
|
+
# if invalid args, just bail out
|
74
|
+
if ( args[0].is_a?(Hash) || nil ) || ( args[1].is_a?(Hash) || args[1].is_a?( Symbol) || args[1].is_a?(String) || nil )
|
75
|
+
raise ArgumentError, "Invalid arguments passed: syntax: actionstamps :by, ModelName"
|
76
|
+
end
|
77
|
+
|
78
|
+
configs = { :suffix => args[0], :model => args[1] }
|
79
|
+
|
80
|
+
# do we have the fields :created_? / :updated_? declared, if not we declare them
|
81
|
+
if properties.any? { |p| p.name.to_s =~ /^(created|updated)_#{Regexp.escape(configs[:suffix].to_s)}$/ }
|
82
|
+
# if they are declared then we use them
|
83
|
+
raise ArgumentError, "Full functionality NOT implemented yet. Please DO NOT declare your created_#{configs[:suffix]} / updated_#{configs[:suffix]} properties, they will be automatically declared by this plugin."
|
84
|
+
else
|
85
|
+
property "created_#{configs[:suffix]}".to_sym, Integer#, :default => 1
|
86
|
+
property "updated_#{configs[:suffix]}".to_sym, Integer#, :default => 1
|
87
|
+
end
|
88
|
+
|
89
|
+
@actionstamps_receiver_properties = ["created_#{configs[:suffix]}".to_sym, "updated_#{configs[:suffix]}".to_sym ]
|
90
|
+
@actionstamps_model_class = configs[:model].to_s.capitalize
|
91
|
+
|
92
|
+
extend DataMapper::Actionstamps::ClassMethods
|
93
|
+
include DataMapper::Actionstamps::ReceiverMethods
|
94
|
+
|
95
|
+
|
96
|
+
class_eval(<<-END, __FILE__, __LINE__)
|
97
|
+
def set_actionstamps
|
98
|
+
self.created_#{configs[:suffix].to_s} = #{configs[:model]}.current_#{configs[:model].to_s.downcase}.id if #{configs[:model]}.current_#{configs[:model].to_s.downcase} && self.new? && self.created_#{configs[:suffix].to_s}.nil?
|
99
|
+
self.updated_#{configs[:suffix].to_s} = #{configs[:model]}.current_#{configs[:model].to_s.downcase}.id if #{configs[:model]}.current_#{configs[:model].to_s.downcase}
|
100
|
+
end
|
101
|
+
END
|
102
|
+
|
103
|
+
end #/def actionstamps
|
104
|
+
|
105
|
+
module ClassMethods
|
106
|
+
attr_reader :actionstamps_class
|
107
|
+
end #/module ClassMethods
|
108
|
+
|
109
|
+
|
110
|
+
module ReceiverMethods
|
111
|
+
|
112
|
+
def self.included(model)
|
113
|
+
model.before :save, :set_actionstamps_on_save
|
114
|
+
model.extend DataMapper::Actionstamps::ClassMethods
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Saves the record with the created_? / updated_? attributes set to the current time.
|
119
|
+
#
|
120
|
+
# ==== Examples
|
121
|
+
#
|
122
|
+
# @model.touch
|
123
|
+
#
|
124
|
+
# @api public
|
125
|
+
def touch
|
126
|
+
set_actionstamps
|
127
|
+
save
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
##
|
134
|
+
# Callback method
|
135
|
+
#
|
136
|
+
# ==== Examples
|
137
|
+
#
|
138
|
+
# before :save, :set_actionstamps_on_save
|
139
|
+
#
|
140
|
+
#
|
141
|
+
# @api public
|
142
|
+
def set_actionstamps_on_save
|
143
|
+
return unless dirty?
|
144
|
+
set_actionstamps
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
end #/module ReceiverMethods
|
149
|
+
|
150
|
+
end #/module Actionstamps
|
151
|
+
|
152
|
+
end #/module DataMapper
|
@@ -0,0 +1,576 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
3
|
+
|
4
|
+
|
5
|
+
return unless HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
|
6
|
+
|
7
|
+
describe "DataMapper::Actionstamps" do
|
8
|
+
|
9
|
+
describe "Default behaviours" do
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
class User
|
13
|
+
include DataMapper::Resource
|
14
|
+
property :id, Serial
|
15
|
+
property :name, String
|
16
|
+
|
17
|
+
provides_actionstamps
|
18
|
+
end
|
19
|
+
|
20
|
+
class Article
|
21
|
+
include DataMapper::Resource
|
22
|
+
property :id, Serial
|
23
|
+
property :title, String
|
24
|
+
|
25
|
+
actionstamps #:by, User
|
26
|
+
end
|
27
|
+
|
28
|
+
DataMapper.auto_migrate!
|
29
|
+
end
|
30
|
+
|
31
|
+
before(:each) do
|
32
|
+
@user = User.create(:name => "Joe", :id => 99)
|
33
|
+
# User.current_user = @user
|
34
|
+
end
|
35
|
+
|
36
|
+
after do
|
37
|
+
User.all.destroy!
|
38
|
+
Article.all.destroy!
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "Provider Model" do
|
42
|
+
|
43
|
+
describe "#self.actionstamps_class" do
|
44
|
+
|
45
|
+
it "should return the constant of the Actionstamps provider class" do
|
46
|
+
User.actionstamps_class.should == User
|
47
|
+
|
48
|
+
class Donkey
|
49
|
+
include DataMapper::Resource
|
50
|
+
property :id, Serial
|
51
|
+
property :name, String
|
52
|
+
|
53
|
+
provides_actionstamps
|
54
|
+
end
|
55
|
+
Donkey.actionstamps_class.should == Donkey
|
56
|
+
end
|
57
|
+
|
58
|
+
end #/ #self.actionstamps_class
|
59
|
+
|
60
|
+
describe "#self.current_user=(user)" do
|
61
|
+
|
62
|
+
it "should respond to :current_user=" do
|
63
|
+
User.should respond_to(:current_user=)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should allow setting a new user" do
|
67
|
+
lambda {
|
68
|
+
User.current_user = User.create(:id => 77, :name => "Adam")
|
69
|
+
}.should_not raise_error(Exception)
|
70
|
+
end
|
71
|
+
|
72
|
+
end #/ #self.current_user=(user)
|
73
|
+
|
74
|
+
|
75
|
+
describe "#self.current_user" do
|
76
|
+
|
77
|
+
it "should respond to :current_user" do
|
78
|
+
User.should respond_to(:current_user)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return the currently assigned User" do
|
82
|
+
User.current_user.id.should == 77
|
83
|
+
end
|
84
|
+
|
85
|
+
end #/ #self.current_user
|
86
|
+
|
87
|
+
end #/ Provider Model
|
88
|
+
|
89
|
+
describe "Receiver Model" do
|
90
|
+
|
91
|
+
describe "when there is NO current_user" do
|
92
|
+
|
93
|
+
before(:each) do
|
94
|
+
User.current_user = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should not set the created_by" do
|
98
|
+
User.current_user.should == nil
|
99
|
+
a = Article.create(:title => "This also works")
|
100
|
+
a.created_by.should == nil
|
101
|
+
a.updated_by.should == nil
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should not set the updated_by" do
|
105
|
+
User.current_user.should == nil
|
106
|
+
a = Article.create(:title => "This also works")
|
107
|
+
a.updated_by.should == nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should set :updated_by and NOT set :created_by when touched" do
|
111
|
+
User.current_user.should == nil # sanity
|
112
|
+
a = Article.create(:title => "Absolutely Amazing, it all works" )
|
113
|
+
|
114
|
+
a.touch
|
115
|
+
|
116
|
+
a.updated_by.should == nil
|
117
|
+
a.created_by.should == nil
|
118
|
+
end
|
119
|
+
|
120
|
+
end #/ when there is NO current_user
|
121
|
+
|
122
|
+
describe "when there is a current_user" do
|
123
|
+
|
124
|
+
before(:each) do
|
125
|
+
User.current_user = @user
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should NOT set if :created_by is already set" do
|
129
|
+
User.current_user.id.should == 99 # sanity
|
130
|
+
a = Article.new(:title => "Hell, this works too" )
|
131
|
+
a.created_by = 5
|
132
|
+
a.save
|
133
|
+
a.created_by.should == 5
|
134
|
+
a.created_by.should be_a_kind_of(Integer)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should set :created_by on creation" do
|
138
|
+
User.current_user.id.should == 99 # sanity
|
139
|
+
a = Article.new(:title => "Hell, this works as well!" )
|
140
|
+
a.created_by.should == nil
|
141
|
+
a.save
|
142
|
+
a.created_by.should be_a_kind_of(Integer)
|
143
|
+
a.created_by.should == User.current_user.id
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should NOT alter :created_by on model updates" do
|
147
|
+
User.current_user.id.should == 99 # sanity
|
148
|
+
a = Article.new(:title => "Even this works" )
|
149
|
+
a.created_by.should == nil
|
150
|
+
a.save
|
151
|
+
a.created_by.should be_a_kind_of(Integer)
|
152
|
+
a.created_by.should == User.current_user.id
|
153
|
+
|
154
|
+
u = User.create(:name => "Eve", :id => 88)
|
155
|
+
User.current_user = u
|
156
|
+
a.title = "Updating things works as well"
|
157
|
+
a.save
|
158
|
+
a.created_by.should_not == User.current_user.id
|
159
|
+
a.updated_by.should == User.current_user.id
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should set :updated_by on creation and on update" do
|
163
|
+
User.current_user.id.should == 99 # sanity
|
164
|
+
a = Article.new(:title => "This is just great, it all works" )
|
165
|
+
a.updated_by.should == nil
|
166
|
+
a.save
|
167
|
+
a.updated_by.should be_a_kind_of(Integer)
|
168
|
+
a.updated_by.should == User.current_user.id
|
169
|
+
|
170
|
+
u = User.create(:name => "Eve", :id => 88)
|
171
|
+
User.current_user = u
|
172
|
+
a.title = "Updating things works as well"
|
173
|
+
a.save
|
174
|
+
a.updated_by.should == User.current_user.id
|
175
|
+
a.updated_by.should_not == @user.id
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should set :updated_by and NOT set :created_by when touched" do
|
179
|
+
User.current_user.id.should == 99 # sanity
|
180
|
+
a = Article.create(:title => "Absolutely Amazing, it all works" )
|
181
|
+
a.created_by.should be_a_kind_of(Integer)
|
182
|
+
a.created_by.should == User.current_user.id
|
183
|
+
a.updated_by.should be_a_kind_of(Integer)
|
184
|
+
a.updated_by.should == User.current_user.id
|
185
|
+
|
186
|
+
User.current_user = User.create(:name => "Eve", :id => 88)
|
187
|
+
User.current_user.id.should == 88
|
188
|
+
|
189
|
+
a.touch
|
190
|
+
|
191
|
+
a.updated_by.should == User.current_user.id
|
192
|
+
a.created_by.should_not == User.current_user.id
|
193
|
+
a.created_by.should == @user.id
|
194
|
+
end
|
195
|
+
|
196
|
+
end #/ when there is a current_user
|
197
|
+
|
198
|
+
end #/ Receiver Model
|
199
|
+
|
200
|
+
end #/ Default behaviours
|
201
|
+
|
202
|
+
describe "Error Handling" do
|
203
|
+
|
204
|
+
describe "Provider declarations" do
|
205
|
+
|
206
|
+
it "should raise an ArgumentError when passed an arg" do
|
207
|
+
lambda {
|
208
|
+
class Client
|
209
|
+
include DataMapper::Resource
|
210
|
+
property :id, Serial
|
211
|
+
property :name, String
|
212
|
+
|
213
|
+
provides_actionstamps :some_value
|
214
|
+
|
215
|
+
# actionstamps :by, User
|
216
|
+
end
|
217
|
+
|
218
|
+
}.should raise_error(ArgumentError)
|
219
|
+
end
|
220
|
+
|
221
|
+
end #/ Provider declarations
|
222
|
+
|
223
|
+
describe "Receiver declarations" do
|
224
|
+
|
225
|
+
it "should raise an ArgumentError when passed a Hash as the 1st arg" do
|
226
|
+
lambda {
|
227
|
+
class Post
|
228
|
+
include DataMapper::Resource
|
229
|
+
property :id, Serial
|
230
|
+
property :title, String
|
231
|
+
|
232
|
+
actionstamps :model => :user
|
233
|
+
end
|
234
|
+
|
235
|
+
}.should raise_error(ArgumentError)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should raise an ArgumentError when passed a Hash as the 2nd args" do
|
239
|
+
lambda {
|
240
|
+
class Post
|
241
|
+
include DataMapper::Resource
|
242
|
+
property :id, Serial
|
243
|
+
property :title, String
|
244
|
+
|
245
|
+
actionstamps :by, :model => :user
|
246
|
+
end
|
247
|
+
}.should raise_error(ArgumentError)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should raise an ArgumentError when passed a Symbol as the 2nd args" do
|
251
|
+
lambda {
|
252
|
+
class Post
|
253
|
+
include DataMapper::Resource
|
254
|
+
property :id, Serial
|
255
|
+
property :title, String
|
256
|
+
|
257
|
+
actionstamps :by, :user
|
258
|
+
end
|
259
|
+
}.should raise_error(ArgumentError)
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should raise an ArgumentError when passed a String as the 2nd args" do
|
263
|
+
lambda {
|
264
|
+
class Post
|
265
|
+
include DataMapper::Resource
|
266
|
+
property :id, Serial
|
267
|
+
property :title, String
|
268
|
+
|
269
|
+
actionstamps :by, "User"
|
270
|
+
end
|
271
|
+
}.should raise_error(ArgumentError)
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should raise an ArgumentError when passed a non-existant model as the 2nd args" do
|
275
|
+
lambda {
|
276
|
+
class Post
|
277
|
+
include DataMapper::Resource
|
278
|
+
property :id, Serial
|
279
|
+
property :title, String
|
280
|
+
|
281
|
+
actionstamps :by, ::DoesNotExist
|
282
|
+
end
|
283
|
+
}.should raise_error(NameError)
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should raise an ArgumentError when declaring a property by the same name" do
|
287
|
+
lambda {
|
288
|
+
class Post
|
289
|
+
include DataMapper::Resource
|
290
|
+
property :id, Serial
|
291
|
+
property :title, String
|
292
|
+
|
293
|
+
property :created_by_id, Integer
|
294
|
+
|
295
|
+
actionstamps :by_id, ::User
|
296
|
+
end
|
297
|
+
}.should raise_error(ArgumentError)
|
298
|
+
end
|
299
|
+
|
300
|
+
end #/ Receiver declarations
|
301
|
+
|
302
|
+
end #/ Error Handling
|
303
|
+
|
304
|
+
describe "Associations" do
|
305
|
+
|
306
|
+
describe "when using :created_by_id" do
|
307
|
+
|
308
|
+
before(:each) do
|
309
|
+
class Author
|
310
|
+
include DataMapper::Resource
|
311
|
+
property :id, Serial
|
312
|
+
property :name, String
|
313
|
+
|
314
|
+
provides_actionstamps
|
315
|
+
|
316
|
+
has n, :articles, 'Article', :parent_key => [:id], :child_key => [:created_by_id]
|
317
|
+
has n, :authored_articles, 'Article', :parent_key => [:id], :child_key => [:created_by_id]
|
318
|
+
has n, :updated_articles, 'Article', :parent_key => [:id], :child_key => [:updated_by_id]
|
319
|
+
end
|
320
|
+
|
321
|
+
class Article
|
322
|
+
include DataMapper::Resource
|
323
|
+
property :id, Serial
|
324
|
+
property :title, String
|
325
|
+
|
326
|
+
actionstamps :by_id, Author
|
327
|
+
|
328
|
+
belongs_to :author, 'Author', :parent_key => [:id], :child_key => [:created_by_id]
|
329
|
+
belongs_to :updater, 'Author', :parent_key => [:id], :child_key => [:updated_by_id]
|
330
|
+
end
|
331
|
+
|
332
|
+
DataMapper.auto_migrate!
|
333
|
+
|
334
|
+
@author_joe = Author.create(:id => 22, :name => "Joe")
|
335
|
+
@author_jane = Author.create(:id => 33, :name => "Jane")
|
336
|
+
|
337
|
+
Author.current_author = @author_joe
|
338
|
+
|
339
|
+
@article1 = Article.create(:title => "Article 1")
|
340
|
+
@article2 = Article.create(:title => "Article 2")
|
341
|
+
@article3 = Article.create(:title => "Article 3")
|
342
|
+
|
343
|
+
Author.current_author = @author_jane
|
344
|
+
@article4 = Article.create(:title => "Article 4")
|
345
|
+
@article5 = Article.create(:title => "Article 5")
|
346
|
+
@article6 = Article.create(:title => "Article 6")
|
347
|
+
|
348
|
+
# update
|
349
|
+
@article3.title = "Article 3 updated" # set updater to Jane
|
350
|
+
@article3.save
|
351
|
+
|
352
|
+
end
|
353
|
+
|
354
|
+
describe "Author" do
|
355
|
+
|
356
|
+
describe "has n :authored_articles" do
|
357
|
+
|
358
|
+
it "should respond to :authored_articles" do
|
359
|
+
@author_joe.should respond_to(:authored_articles)
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should return all the articles created by the author" do
|
363
|
+
@author_joe.authored_articles.map(&:id).should == [1,2,3]
|
364
|
+
@author_jane.authored_articles.map(&:id).should == [4,5,6]
|
365
|
+
end
|
366
|
+
|
367
|
+
end #/ has n :authored_articles
|
368
|
+
|
369
|
+
describe "has n :updated_articles" do
|
370
|
+
|
371
|
+
it "should respond to :updated_articles" do
|
372
|
+
@author_joe.should respond_to(:updated_articles)
|
373
|
+
end
|
374
|
+
|
375
|
+
it "should return all the articles updated by author" do
|
376
|
+
@author_joe.updated_articles.map(&:id).should == [1,2]
|
377
|
+
@author_jane.updated_articles.map(&:id).should == [3,4,5,6]
|
378
|
+
end
|
379
|
+
|
380
|
+
end #/ has n :updated_articles
|
381
|
+
|
382
|
+
describe "has n :articles" do
|
383
|
+
|
384
|
+
it "should respond to :articles" do
|
385
|
+
@author_joe.should respond_to(:articles)
|
386
|
+
end
|
387
|
+
|
388
|
+
it "should return all the articles created by the author" do
|
389
|
+
@author_joe.articles.map(&:id).should == [1,2,3]
|
390
|
+
@author_jane.articles.map(&:id).should == [4,5,6]
|
391
|
+
end
|
392
|
+
|
393
|
+
end #/ has n :articles
|
394
|
+
|
395
|
+
end #/ Author
|
396
|
+
|
397
|
+
describe "Article" do
|
398
|
+
|
399
|
+
describe "belongs_to :author" do
|
400
|
+
|
401
|
+
it "should respond to :author" do
|
402
|
+
@article1.should respond_to(:author)
|
403
|
+
end
|
404
|
+
|
405
|
+
it "should return the author" do
|
406
|
+
@article1.author.should == @author_joe
|
407
|
+
@article4.author.should == @author_jane
|
408
|
+
end
|
409
|
+
|
410
|
+
end #/ belongs_to :author
|
411
|
+
|
412
|
+
describe "belongs_to :updater" do
|
413
|
+
|
414
|
+
it "should respond to :updater" do
|
415
|
+
@article1.should respond_to(:updater)
|
416
|
+
end
|
417
|
+
|
418
|
+
it "should return the updater" do
|
419
|
+
@article1.updater.should == @author_joe
|
420
|
+
@article3.updater.should == @author_jane
|
421
|
+
end
|
422
|
+
|
423
|
+
end #/ belongs_to :author
|
424
|
+
|
425
|
+
end #/ Article
|
426
|
+
|
427
|
+
end #/ when using :created_by_id
|
428
|
+
|
429
|
+
describe "when using :created_by" do
|
430
|
+
|
431
|
+
before(:each) do
|
432
|
+
class Author
|
433
|
+
include DataMapper::Resource
|
434
|
+
property :id, Serial
|
435
|
+
property :name, String
|
436
|
+
|
437
|
+
provides_actionstamps
|
438
|
+
|
439
|
+
has n, :articles, 'Article', :parent_key => [:id], :child_key => [:created_by]
|
440
|
+
has n, :authored_articles, 'Article', :parent_key => [:id], :child_key => [:created_by]
|
441
|
+
has n, :updated_articles, 'Article', :parent_key => [:id], :child_key => [:updated_by]
|
442
|
+
end
|
443
|
+
|
444
|
+
class Article
|
445
|
+
include DataMapper::Resource
|
446
|
+
property :id, Serial
|
447
|
+
property :title, String
|
448
|
+
|
449
|
+
actionstamps :by, Author
|
450
|
+
|
451
|
+
belongs_to :author, 'Author', :parent_key => [:id], :child_key => [:created_by]
|
452
|
+
belongs_to :updater, 'Author', :parent_key => [:id], :child_key => [:updated_by]
|
453
|
+
end
|
454
|
+
|
455
|
+
DataMapper.auto_migrate!
|
456
|
+
|
457
|
+
@author_joe = Author.create(:id => 22, :name => "Joe")
|
458
|
+
@author_jane = Author.create(:id => 33, :name => "Jane")
|
459
|
+
|
460
|
+
Author.current_author = @author_joe
|
461
|
+
|
462
|
+
@article1 = Article.create(:title => "Article 1")
|
463
|
+
@article2 = Article.create(:title => "Article 2")
|
464
|
+
@article3 = Article.create(:title => "Article 3")
|
465
|
+
|
466
|
+
Author.current_author = @author_jane
|
467
|
+
@article4 = Article.create(:title => "Article 4")
|
468
|
+
@article5 = Article.create(:title => "Article 5")
|
469
|
+
@article6 = Article.create(:title => "Article 6")
|
470
|
+
|
471
|
+
# update
|
472
|
+
@article3.title = "Article 3 updated" # set updater to Jane
|
473
|
+
@article3.save
|
474
|
+
|
475
|
+
end
|
476
|
+
|
477
|
+
describe "Author" do
|
478
|
+
|
479
|
+
describe "has n :authored_articles" do
|
480
|
+
|
481
|
+
it "should respond to :authored_articles" do
|
482
|
+
@author_joe.should respond_to(:authored_articles)
|
483
|
+
end
|
484
|
+
|
485
|
+
it "should return all the articles created by the author" do
|
486
|
+
@author_joe.authored_articles.map(&:id).should == [1,2,3]
|
487
|
+
@author_jane.authored_articles.map(&:id).should == [4,5,6]
|
488
|
+
end
|
489
|
+
|
490
|
+
end #/ has n :authored_articles
|
491
|
+
|
492
|
+
describe "has n :updated_articles" do
|
493
|
+
|
494
|
+
it "should respond to :updated_articles" do
|
495
|
+
@author_joe.should respond_to(:updated_articles)
|
496
|
+
end
|
497
|
+
|
498
|
+
it "should return all the articles updated by author" do
|
499
|
+
@author_joe.updated_articles.map(&:id).should == [1,2]
|
500
|
+
@author_jane.updated_articles.map(&:id).should == [3,4,5,6]
|
501
|
+
end
|
502
|
+
|
503
|
+
end #/ has n :updated_articles
|
504
|
+
|
505
|
+
describe "has n :articles" do
|
506
|
+
|
507
|
+
it "should respond to :articles" do
|
508
|
+
@author_joe.should respond_to(:articles)
|
509
|
+
end
|
510
|
+
|
511
|
+
it "should return all the articles created by the author" do
|
512
|
+
@author_joe.articles.map(&:id).should == [1,2,3]
|
513
|
+
@author_jane.articles.map(&:id).should == [4,5,6]
|
514
|
+
end
|
515
|
+
|
516
|
+
end #/ has n :articles
|
517
|
+
|
518
|
+
end #/ Author
|
519
|
+
|
520
|
+
describe "Article" do
|
521
|
+
|
522
|
+
describe "belongs_to :author" do
|
523
|
+
|
524
|
+
it "should respond to :author" do
|
525
|
+
@article1.should respond_to(:author)
|
526
|
+
end
|
527
|
+
|
528
|
+
it "should return the author" do
|
529
|
+
@article1.author.should == @author_joe
|
530
|
+
@article4.author.should == @author_jane
|
531
|
+
end
|
532
|
+
|
533
|
+
end #/ belongs_to :author
|
534
|
+
|
535
|
+
describe "belongs_to :updater" do
|
536
|
+
|
537
|
+
it "should respond to :updater" do
|
538
|
+
@article1.should respond_to(:updater)
|
539
|
+
end
|
540
|
+
|
541
|
+
it "should return the updater" do
|
542
|
+
@article1.updater.should == @author_joe
|
543
|
+
@article3.updater.should == @author_jane
|
544
|
+
end
|
545
|
+
|
546
|
+
end #/ belongs_to :author
|
547
|
+
|
548
|
+
end #/ Article
|
549
|
+
|
550
|
+
end #/ when using :created_by
|
551
|
+
|
552
|
+
end #/ Associations
|
553
|
+
|
554
|
+
|
555
|
+
describe "Client Model" do
|
556
|
+
|
557
|
+
before(:each) do
|
558
|
+
class Client
|
559
|
+
include DataMapper::Resource
|
560
|
+
property :id, Serial
|
561
|
+
property :name, String
|
562
|
+
|
563
|
+
provides_actionstamps
|
564
|
+
end
|
565
|
+
|
566
|
+
end
|
567
|
+
%w(current_client current_client=).each do |m|
|
568
|
+
it "should respond to :#{m}" do
|
569
|
+
Client.should respond_to(m.to_sym)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
end #/ Client Model
|
574
|
+
|
575
|
+
|
576
|
+
end #/ DataMapper::Actionstamps
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'spec'
|
4
|
+
require 'pathname'
|
5
|
+
require Pathname(__FILE__).dirname.parent.expand_path + 'lib/dm-actionstamps'
|
6
|
+
require 'dm-core'
|
7
|
+
|
8
|
+
def load_driver(name, default_uri)
|
9
|
+
return false if ENV['ADAPTER'] != name.to_s
|
10
|
+
|
11
|
+
lib = "do_#{name}"
|
12
|
+
|
13
|
+
begin
|
14
|
+
gem lib, '>=0.10.1'
|
15
|
+
require lib
|
16
|
+
DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
|
17
|
+
DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
|
18
|
+
true
|
19
|
+
rescue Gem::LoadError => e
|
20
|
+
warn "Could not load #{lib}: #{e}"
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ENV['ADAPTER'] ||= 'sqlite3'
|
26
|
+
|
27
|
+
HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
|
28
|
+
HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
|
29
|
+
HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dm-actionstamps
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- kematzy
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-17 00:00:00 +08:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 9
|
31
|
+
version: 1.2.9
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
description: A DataMapper plugin that works similar to the dm-timestamps in that it 'automagically' adds/updates the created_?, updated_? fields of your models.
|
35
|
+
email: kematzy@gmail.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- LICENSE
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- .document
|
45
|
+
- .gitignore
|
46
|
+
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- VERSION
|
50
|
+
- dm-actionstamps.gemspec
|
51
|
+
- lib/dm-actionstamps.rb
|
52
|
+
- lib/dm-actionstamps/actionstamps.rb
|
53
|
+
- lib/dm-actionstamps/version.rb
|
54
|
+
- spec/integration/actionstamps_spec.rb
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/kematzy/dm-actionstamps
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options:
|
62
|
+
- --charset=UTF-8
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.6
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: A DataMapper plugin that automatically adds/updates the created_?, updated_? fields of your models.
|
86
|
+
test_files:
|
87
|
+
- spec/integration/actionstamps_spec.rb
|
88
|
+
- spec/spec_helper.rb
|