mleung-koujou 0.0.2
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/History.txt +4 -0
- data/Manifest.txt +29 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +43 -0
- data/Rakefile +26 -0
- data/lib/koujou.rb +22 -0
- data/lib/koujou/builder.rb +209 -0
- data/lib/koujou/data_generator.rb +90 -0
- data/lib/koujou/sequence.rb +11 -0
- data/lib/koujou/validation_reflection.rb +147 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/lib/active_record_test_connector.rb +78 -0
- data/test/lib/models/comment.rb +7 -0
- data/test/lib/models/post.rb +15 -0
- data/test/lib/models/profile.rb +9 -0
- data/test/lib/models/user.rb +38 -0
- data/test/test_builder.rb +143 -0
- data/test/test_data_generator.rb +89 -0
- data/test/test_helper.rb +11 -0
- data/test/test_kojo.rb +12 -0
- data/test/test_sequence.rb +20 -0
- metadata +102 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
PostInstall.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
koujou.gemspec
|
7
|
+
lib/koujou.rb
|
8
|
+
lib/koujou/builder.rb
|
9
|
+
lib/koujou/custom_validation.rb
|
10
|
+
lib/koujou/data_generator.rb
|
11
|
+
lib/koujou/sequence.rb
|
12
|
+
lib/koujou/validation_reflection.rb
|
13
|
+
script/console
|
14
|
+
script/destroy
|
15
|
+
script/generate
|
16
|
+
test/lib/active_record_test_connector.rb
|
17
|
+
test/lib/models/car.rb
|
18
|
+
test/lib/models/comment.rb
|
19
|
+
test/lib/models/message.rb
|
20
|
+
test/lib/models/photo.rb
|
21
|
+
test/lib/models/post.rb
|
22
|
+
test/lib/models/profile.rb
|
23
|
+
test/lib/models/user.rb
|
24
|
+
test/test_builder.rb
|
25
|
+
test/test_custom_validation.rb
|
26
|
+
test/test_data_generator.rb
|
27
|
+
test/test_helper.rb
|
28
|
+
test/test_kojo.rb
|
29
|
+
test/test_sequence.rb
|
data/PostInstall.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
= koujou
|
2
|
+
|
3
|
+
* http://github.com/mleung/koujou
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Koujou is a fixture replacement that requires no effort to use. You don't have to define a single thing
|
8
|
+
in your test_helper or whatever. Just call the koujou method on your active record model, and you're
|
9
|
+
off.
|
10
|
+
|
11
|
+
Check out: http://www.michaelleung.us/koujou for all the juicy details.
|
12
|
+
|
13
|
+
Please note this is a very early release of koujou, so if you find any issues, just post
|
14
|
+
them here: http://github.com/mleung/koujou/issues
|
15
|
+
|
16
|
+
== INSTALL:
|
17
|
+
|
18
|
+
gem install mleung-koujou --source http://gems.github.com
|
19
|
+
|
20
|
+
== LICENSE:
|
21
|
+
|
22
|
+
(The MIT License)
|
23
|
+
|
24
|
+
Copyright (c) 2009 Michael Leung
|
25
|
+
|
26
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
27
|
+
a copy of this software and associated documentation files (the
|
28
|
+
'Software'), to deal in the Software without restriction, including
|
29
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
30
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
31
|
+
permit persons to whom the Software is furnished to do so, subject to
|
32
|
+
the following conditions:
|
33
|
+
|
34
|
+
The above copyright notice and this permission notice shall be
|
35
|
+
included in all copies or substantial portions of the Software.
|
36
|
+
|
37
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
38
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
39
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
40
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
41
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
42
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
43
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'hoe', '>= 2.1.0'
|
3
|
+
require 'hoe'
|
4
|
+
require 'fileutils'
|
5
|
+
require './lib/koujou'
|
6
|
+
|
7
|
+
Hoe.plugin :newgem
|
8
|
+
# Hoe.plugin :website
|
9
|
+
# Hoe.plugin :cucumberfeatures
|
10
|
+
|
11
|
+
# Generate all the Rake tasks
|
12
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
13
|
+
$hoe = Hoe.spec 'koujou' do
|
14
|
+
self.developer 'Michael Leung', 'me@michaelleung.us'
|
15
|
+
self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
16
|
+
self.rubyforge_name = self.name # TODO this is default value
|
17
|
+
# self.extra_deps = [['activesupport','>= 2.0.2']]
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'newgem/tasks'
|
22
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
23
|
+
|
24
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
25
|
+
# remove_task :default
|
26
|
+
# task :default => [:spec, :features]
|
data/lib/koujou.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'active_record'
|
6
|
+
require 'faker'
|
7
|
+
require 'koujou/sequence'
|
8
|
+
require 'koujou/builder'
|
9
|
+
require 'koujou/data_generator'
|
10
|
+
require 'koujou/validation_reflection'
|
11
|
+
require 'koujou/custom_validation'
|
12
|
+
|
13
|
+
module Koujou
|
14
|
+
VERSION = '0.0.1'
|
15
|
+
end
|
16
|
+
|
17
|
+
ActiveRecord::Base.class_eval do
|
18
|
+
include Koujou::ActiveRecordExtensions::ValidationReflection
|
19
|
+
Koujou::ActiveRecordExtensions::ValidationReflection.install(self)
|
20
|
+
include Koujou::ActiveRecordExtensions::Builder
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module Koujou #:nodoc:
|
2
|
+
module ActiveRecordExtensions # :nodoc:
|
3
|
+
module Builder # :nodoc:
|
4
|
+
|
5
|
+
def self.included(base) # :nodoc:
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods #:nodoc:
|
10
|
+
|
11
|
+
def koujou(create = true, attributes = nil)
|
12
|
+
generate_instance(create, attributes)
|
13
|
+
end
|
14
|
+
|
15
|
+
def koujou_build(attributes = nil)
|
16
|
+
koujou(false, attributes)
|
17
|
+
end
|
18
|
+
|
19
|
+
def koujou_create(attributes = nil)
|
20
|
+
koujou(true, attributes)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def generate_instance(create, attributes)
|
25
|
+
# There were a metric ton of AR warnings about instance vars
|
26
|
+
# not being initialized when running our specs. This hides those.
|
27
|
+
silence_warnings do
|
28
|
+
instance = build_model_instance(self, attributes)
|
29
|
+
instance.save! if create
|
30
|
+
instance
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_model_instance(klass, attributes = nil, recursed_from_model = nil)
|
35
|
+
# If we pass in a string here for klass instead of a constant
|
36
|
+
# we want to convert that.
|
37
|
+
klass = Kernel.const_get(klass) unless klass.respond_to?(:new)
|
38
|
+
instance = klass.new
|
39
|
+
# Set the models attributes if the user passed them in.
|
40
|
+
# This will allow attributes to be set regardless if
|
41
|
+
# they're required or not.
|
42
|
+
instance.attributes = attributes unless attributes.nil?
|
43
|
+
|
44
|
+
set_required_attributes!(instance, attributes)
|
45
|
+
set_unique_attributes!(instance, attributes)
|
46
|
+
set_confirmation_attributes!(instance, attributes)
|
47
|
+
set_length_validated_attributes!(instance, attributes)
|
48
|
+
set_inclusion_validated_attributes!(instance, attributes)
|
49
|
+
create_associations(instance, recursed_from_model)
|
50
|
+
CustomValidation.stub_custom_validations!(instance)
|
51
|
+
|
52
|
+
instance
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_required_attributes!(instance, attributes)
|
56
|
+
instance.class.required_validations.each do |v|
|
57
|
+
# We want to skip over setting any required fields if the field
|
58
|
+
# should also be unique. We handle that in the set_unique_attributes!
|
59
|
+
# method with a sequence. Also, if it's a confirmation field (e.g. password_confirmation)
|
60
|
+
# we can skip it, because that gets set below.
|
61
|
+
standard_required_attributes(instance, v) do
|
62
|
+
# We don't want to set anything if the user passed in data for this field
|
63
|
+
# or if this is a validates_presence_of :some_id. The ids will be set
|
64
|
+
# when we create the association.
|
65
|
+
next if overridden_attribute?(attributes, v.name)
|
66
|
+
# has_required_id_validation?(instance, v.name)
|
67
|
+
|
68
|
+
generate_and_set_data(instance, v, false)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_unique_attributes!(instance, attributes)
|
74
|
+
instance.class.unique_validations.each do |v|
|
75
|
+
next if overridden_attribute?(attributes, v.name)
|
76
|
+
generate_and_set_data(instance, v, true)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# This generates set_length_validated_attributes! and set_inclusion_validated_attributes! methods.
|
81
|
+
# They used to look like this:
|
82
|
+
#
|
83
|
+
# def set_length_validated_attributes!(instance, attributes)
|
84
|
+
# instance.class.length_validations.each do |v|
|
85
|
+
# non_required_attributes(instance, v, attributes) { generate_and_set_data(instance, v, false) }
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# def set_inclusion_of_validated_attributes!(instance, attributes)
|
90
|
+
# instance.class.inclusion_validations.each do |v|
|
91
|
+
# non_required_attributes(instance, v, attributes) { generate_and_set_data(instance, v, false) }
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
# I'm sure you see the similarities.
|
95
|
+
%w(length inclusion).each do |validation|
|
96
|
+
define_method("set_#{validation}_validated_attributes!") do |instance, attributes|
|
97
|
+
instance.class.send("#{validation}_validations").each do |v|
|
98
|
+
# Non required attributes are anything that doesn't have validates_presence_of,
|
99
|
+
# validates_uniqueness_of and also anything that hasn't been overriden. These
|
100
|
+
# values get set there. So there's no real point in setting them again here.
|
101
|
+
non_required_attributes(instance, v, attributes) { generate_and_set_data(instance, v, false) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def set_confirmation_attributes!(instance, attributes)
|
108
|
+
instance.class.confirmation_validations.each do |v|
|
109
|
+
# This goes in and sets the models confirmation to whatever the corresponding
|
110
|
+
# fields value is. (e.g. password_confirmation= password)
|
111
|
+
instance.send("#{v.name}_confirmation=", instance.send("#{v.name}"))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def create_associations(instance, recursed_from_model = nil)
|
117
|
+
# We loop through all the has_one or belongs_to associations on the current instance
|
118
|
+
# using introspection, and build up and assign some models to each, if the user has
|
119
|
+
# required the id (e.g. requires_presence_of :user_id). So we're only going to build
|
120
|
+
# the minimum requirements for each model.
|
121
|
+
instance.class.reflect_on_all_associations.each do |a|
|
122
|
+
# We only want to create the association if the user has required the id field.
|
123
|
+
# This will build the minimum valid requirements.
|
124
|
+
next unless has_required_id_validation?(instance, a.name)
|
125
|
+
|
126
|
+
if a.macro == :has_one || a.macro == :belongs_to
|
127
|
+
# If there's a two way association here (user has_one profile, profile belongs_to user)
|
128
|
+
# we only want to create one of those, or it'll recurse forever. That's what the
|
129
|
+
# recursed_from_model does.
|
130
|
+
unless recursed_from_model.to_s == instance.class.to_s.downcase
|
131
|
+
instance.send("#{a.name.to_s}=", build_model_instance(get_assocation_class_name(a), nil, a.name))
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_assocation_class_name(assocation)
|
139
|
+
# This condition is used if the class_name option
|
140
|
+
# is passed to has_many or has_one. We'll definitely
|
141
|
+
# want to use that key instead of the name of the association.
|
142
|
+
if assocation.options.has_key?(:class_name)
|
143
|
+
klass = assocation.options[:class_name]
|
144
|
+
else
|
145
|
+
klass = assocation.name.to_s.singularize.classify
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def generate_and_set_data(instance, validation, sequenced)
|
150
|
+
data_generator = DataGenerator.new(sequenced, validation)
|
151
|
+
data_generator.required_length = get_required_length(instance, validation)
|
152
|
+
if has_inclusion_validation?(instance, validation)
|
153
|
+
data_generator.inclusion_values = get_inclusion_values(instance, validation)
|
154
|
+
end
|
155
|
+
instance.send("#{validation.name}=", data_generator.generate_data_for_column_type)
|
156
|
+
end
|
157
|
+
|
158
|
+
def standard_required_attributes(instance, validation)
|
159
|
+
yield unless has_unique_validation?(instance, validation)
|
160
|
+
end
|
161
|
+
|
162
|
+
def non_required_attributes(instance, validation, attributes)
|
163
|
+
yield unless has_unique_validation?(instance, validation) || has_required_validation?(instance, validation) ||
|
164
|
+
overridden_attribute?(attributes, validation.name)
|
165
|
+
end
|
166
|
+
|
167
|
+
def overridden_attribute?(attributes, key)
|
168
|
+
attributes && attributes.has_key?(key.to_sym)
|
169
|
+
end
|
170
|
+
|
171
|
+
# This creates has_unique_validation?, has_length_validation? etc.
|
172
|
+
# We could probably make one method that takes a type, but I'd rather
|
173
|
+
# get separate methods for each. Cool?
|
174
|
+
%w(unique length required inclusion).each do |v|
|
175
|
+
define_method("has_#{v}_validation?") do |instance, validation|
|
176
|
+
!instance.class.send("#{v}_validations").select{|u| u.name == validation.name }.empty?
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_required_length(instance, validation)
|
181
|
+
return unless has_length_validation?(instance, validation)
|
182
|
+
|
183
|
+
options = instance.class.length_validations.select{|v| v.name == validation.name }.first.options
|
184
|
+
|
185
|
+
# If the validation is validates_length_of :name, :within => 1..20 (or in, which is an alias),
|
186
|
+
# let's just return the minimum value of the range.
|
187
|
+
%w(within in).each { |o| return options[o.to_sym].entries.first if options.has_key?(o.to_sym) }
|
188
|
+
# These other validations should just return the value set.
|
189
|
+
%w(is minimum maximum).each { |o| return options[o.to_sym] if options.has_key?(o.to_sym) }
|
190
|
+
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
|
194
|
+
def get_inclusion_values(instance, validation)
|
195
|
+
return unless has_inclusion_validation?(instance, validation)
|
196
|
+
options = instance.class.inclusion_validations.select{|v| v.name == validation.name }.first.options
|
197
|
+
return unless options.has_key?(:in)
|
198
|
+
options[:in]
|
199
|
+
end
|
200
|
+
|
201
|
+
def has_required_id_validation?(instance, name)
|
202
|
+
!instance.class.required_validations.select{|v| v.name.to_s == "#{name}_id" }.empty?
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Koujou #:nodoc:
|
2
|
+
class DataGenerator
|
3
|
+
|
4
|
+
attr_accessor :required_length, :inclusion_values
|
5
|
+
|
6
|
+
def initialize(sequenced, validation)
|
7
|
+
@sequenced = sequenced
|
8
|
+
# Validation is actually a ActiveRecord::Reflection::MacroReflection
|
9
|
+
@validation = validation
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_data_for_column_type
|
13
|
+
# So if there was an inclusion passed in for validations_inclusion_of (which is just
|
14
|
+
# an enumberable object), let's just return the first element to ensure the value
|
15
|
+
# set is the correct one. Mmmkay?
|
16
|
+
return get_first_value_for_inclusion unless @inclusion_values.nil?
|
17
|
+
# Sometimes models have a validates_presence_of set, but there's no corresponding
|
18
|
+
# db column. The only example I can think of for this is a user model where the actual
|
19
|
+
# column is hashed_password but the model requires the presence of password. So we'll
|
20
|
+
# assume string. This could bite me in the ass later, but we'll see.
|
21
|
+
if @validation.active_record.columns_hash.has_key?("#{@validation.name}")
|
22
|
+
db_type = @validation.active_record.columns_hash["#{@validation.name}"].type
|
23
|
+
else
|
24
|
+
db_type = 'string'
|
25
|
+
end
|
26
|
+
# Since the method names are all based on the db types, we'll just go ahead and
|
27
|
+
# dynamically call the appropriate one.
|
28
|
+
send("generate_#{db_type}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_string
|
32
|
+
return format_if_sequenced(Faker::Internet.email) if @validation.name.to_s.match(/email/)
|
33
|
+
return format_if_sequenced(Faker::Name.first_name) if @validation.name.to_s == 'first_name'
|
34
|
+
return format_if_sequenced(Faker::Name.last_name) if @validation.name.to_s == 'last_name'
|
35
|
+
return format_if_sequenced(Faker::Internet.user_name) if @validation.name.to_s.match(/login|user_name/)
|
36
|
+
return format_if_sequenced(Faker::Address.city) if @validation.name.to_s.match(/city/)
|
37
|
+
return format_if_sequenced(Faker::Address.us_state) if @validation.name.to_s.match(/state|province/)
|
38
|
+
return format_if_sequenced(Faker::Address.zip_code) if @validation.name.to_s.match(/zip|postal/)
|
39
|
+
|
40
|
+
# If we don't match any standard stuff, just return a regular bs lorem string comprised of 10 words.
|
41
|
+
# 10 is sort of a "magic number" I might make a constant for that.
|
42
|
+
standard_text = format_if_sequenced(Faker::Lorem.words(10).to_s)
|
43
|
+
# So if there's a length validation set, we need to return just that amount of data.
|
44
|
+
standard_text = standard_text[0..@required_length - 1].to_s if @required_length
|
45
|
+
standard_text
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_text
|
49
|
+
if @required_length
|
50
|
+
# So if there's a length validation set, we need to return just that amount of data.
|
51
|
+
Faker::Lorem.paragraph(2).to_s[0..@required_length - 1]
|
52
|
+
else
|
53
|
+
Faker::Lorem.paragraph.to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def generate_integer
|
58
|
+
generate_number
|
59
|
+
end
|
60
|
+
|
61
|
+
def generate_float
|
62
|
+
generate_number.to_f
|
63
|
+
end
|
64
|
+
|
65
|
+
def generate_datetime
|
66
|
+
DateTime.now
|
67
|
+
end
|
68
|
+
|
69
|
+
def generate_boolean
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
def generate_number
|
75
|
+
# If this is supposed to be sequenced (aka unique), we'll get the next int from the
|
76
|
+
# Sequence class, and randomize that.
|
77
|
+
random = rand(999)
|
78
|
+
@sequenced ? random + (Sequence.instance.next * rand(2)) : random
|
79
|
+
end
|
80
|
+
|
81
|
+
def format_if_sequenced(val)
|
82
|
+
@sequenced ? "#{Sequence.instance.next}#{val}" : val
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_first_value_for_inclusion
|
86
|
+
@inclusion_values.first
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006-2008, Michael Schuerig, michael@schuerig.de
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
|
25
|
+
require 'active_record/reflection'
|
26
|
+
require 'ostruct'
|
27
|
+
|
28
|
+
# Based on code by Sebastian Kanthak
|
29
|
+
# See http://dev.rubyonrails.org/ticket/861
|
30
|
+
module Koujou # :nodoc:
|
31
|
+
module ActiveRecordExtensions # :nodoc:
|
32
|
+
module ValidationReflection # :nodoc:
|
33
|
+
|
34
|
+
mattr_accessor :reflected_validations
|
35
|
+
Koujou::ActiveRecordExtensions::ValidationReflection.reflected_validations = %w(
|
36
|
+
validates_acceptance_of
|
37
|
+
validates_associated
|
38
|
+
validates_confirmation_of
|
39
|
+
validates_exclusion_of
|
40
|
+
validates_format_of
|
41
|
+
validates_inclusion_of
|
42
|
+
validates_length_of
|
43
|
+
validates_size_of
|
44
|
+
validates_numericality_of
|
45
|
+
validates_presence_of
|
46
|
+
validates_uniqueness_of
|
47
|
+
validate
|
48
|
+
)
|
49
|
+
|
50
|
+
mattr_accessor :in_ignored_subvalidation
|
51
|
+
Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation = false
|
52
|
+
|
53
|
+
def self.included(base)
|
54
|
+
return if base.kind_of?(Koujou::ActiveRecordExtensions::ValidationReflection::ClassMethods)
|
55
|
+
base.extend(ClassMethods)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.install(base)
|
59
|
+
reflected_validations.freeze
|
60
|
+
reflected_validations.each do |validation_type|
|
61
|
+
next if base.respond_to?("#{validation_type}_with_reflection")
|
62
|
+
ignore_subvalidations = false
|
63
|
+
if validation_type.kind_of?(Hash)
|
64
|
+
ignore_subvalidations = validation_type[:ignore_subvalidations]
|
65
|
+
validation_type = validation_type[:method]
|
66
|
+
end
|
67
|
+
base.class_eval <<-"end_eval"
|
68
|
+
class << self
|
69
|
+
def #{validation_type}_with_reflection(*attr_names)
|
70
|
+
ignoring_subvalidations(#{ignore_subvalidations}) do
|
71
|
+
#{validation_type}_without_reflection(*attr_names)
|
72
|
+
remember_validation_metadata(:#{validation_type}, *attr_names)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
alias_method_chain :#{validation_type}, :reflection
|
77
|
+
end
|
78
|
+
end_eval
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module ClassMethods
|
83
|
+
|
84
|
+
# Returns an array of MacroReflection objects for all validations in the class
|
85
|
+
def reflect_on_all_validations
|
86
|
+
read_inheritable_attribute(:validations) || []
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns an array of MacroReflection objects for all validations defined for the field +attr_name+.
|
90
|
+
def reflect_on_validations_for(attr_name)
|
91
|
+
attr_name = attr_name.to_sym
|
92
|
+
reflect_on_all_validations.select do |reflection|
|
93
|
+
reflection.name == attr_name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# A few convenience methods added in by Mike. Why not loop and define_method these?
|
98
|
+
|
99
|
+
def unique_validations
|
100
|
+
reflect_on_all_validations.select{|v| v.macro == :validates_uniqueness_of }
|
101
|
+
end
|
102
|
+
|
103
|
+
def required_validations
|
104
|
+
reflect_on_all_validations.select{|v| v.macro == :validates_presence_of }
|
105
|
+
end
|
106
|
+
|
107
|
+
def confirmation_validations
|
108
|
+
reflect_on_all_validations.select{|v| v.macro == :validates_confirmation_of }
|
109
|
+
end
|
110
|
+
|
111
|
+
def length_validations
|
112
|
+
reflect_on_all_validations.select{|v| v.macro == :validates_length_of || v.macro == :validates_size_of }
|
113
|
+
end
|
114
|
+
|
115
|
+
def inclusion_validations
|
116
|
+
reflect_on_all_validations.select{|v| v.macro == :validates_inclusion_of }
|
117
|
+
end
|
118
|
+
|
119
|
+
def custom_validations
|
120
|
+
# We don't want to get anything like: validate_associated_records_for_posts.
|
121
|
+
reflect_on_all_validations.select{|v| v.macro == :validate && !v.macro.to_s.match("_associated_") }
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def remember_validation_metadata(validation_type, *attr_names)
|
127
|
+
configuration = attr_names.last.is_a?(Hash) ? attr_names.pop : {}
|
128
|
+
attr_names.each do |attr_name|
|
129
|
+
write_inheritable_array :validations,
|
130
|
+
[ ActiveRecord::Reflection::MacroReflection.new(validation_type, attr_name.to_sym, configuration, self) ]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def ignoring_subvalidations(ignore)
|
135
|
+
save_ignore = Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation
|
136
|
+
unless Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation
|
137
|
+
Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation = ignore
|
138
|
+
yield
|
139
|
+
end
|
140
|
+
ensure
|
141
|
+
Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation = save_ignore
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/koujou.rb'}"
|
9
|
+
puts "Loading koujou gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# This let's us happily test AR.
|
2
|
+
require 'active_record'
|
3
|
+
# Require all our models.
|
4
|
+
Dir.glob(File.join(File.dirname(__FILE__), "..", "lib", "models", "*.rb")).each { |f| require f }
|
5
|
+
|
6
|
+
|
7
|
+
class ActiveRecordTestConnector
|
8
|
+
cattr_accessor :connected
|
9
|
+
cattr_accessor :able_to_connect
|
10
|
+
|
11
|
+
self.connected = false
|
12
|
+
self.able_to_connect = true
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
def setup
|
17
|
+
unless self.connected || !self.able_to_connect
|
18
|
+
setup_connection
|
19
|
+
load_schema
|
20
|
+
self.connected = true
|
21
|
+
end
|
22
|
+
rescue Exception => e # errors from ActiveRecord setup
|
23
|
+
$stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
|
24
|
+
self.able_to_connect = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_connection
|
28
|
+
ActiveRecord::Base.establish_connection({
|
29
|
+
:adapter => 'sqlite3',
|
30
|
+
:dbfile => 'test.sqlite3'
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_schema
|
35
|
+
ActiveRecord::Schema.define do
|
36
|
+
create_table "users", :force => true do |t|
|
37
|
+
t.string "name", "email", "first_name", "last_name", "hashed_password"
|
38
|
+
t.integer "age"
|
39
|
+
t.float "salary"
|
40
|
+
t.datetime "hired_on"
|
41
|
+
t.boolean "terms_of_service"
|
42
|
+
end
|
43
|
+
create_table "posts", :force => true do |t|
|
44
|
+
t.string "name"
|
45
|
+
t.text "body"
|
46
|
+
t.integer "user_id"
|
47
|
+
end
|
48
|
+
create_table "comments", :force => true do |t|
|
49
|
+
t.text "bod"
|
50
|
+
t.integer "post_id"
|
51
|
+
end
|
52
|
+
create_table "profiles", :force => true do |t|
|
53
|
+
t.integer "user_id"
|
54
|
+
t.boolean "likes_cheese"
|
55
|
+
end
|
56
|
+
create_table "photos", :force => true do |t|
|
57
|
+
t.integer "profile_id"
|
58
|
+
end
|
59
|
+
create_table "messages", :force => true do |t|
|
60
|
+
t.string "subject"
|
61
|
+
t.text "body"
|
62
|
+
t.datetime "created_at"
|
63
|
+
t.datetime "updated_at"
|
64
|
+
t.integer "sender_id"
|
65
|
+
t.integer "receiver_id"
|
66
|
+
t.boolean "read"
|
67
|
+
end
|
68
|
+
create_table "cars", :force => true do |t|
|
69
|
+
t.integer "user_id", "year"
|
70
|
+
t.string "make", "model"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Post < ActiveRecord::Base
|
2
|
+
validates_presence_of :name
|
3
|
+
validates_length_of :body, :is => 20
|
4
|
+
|
5
|
+
belongs_to :user
|
6
|
+
has_many :comments
|
7
|
+
|
8
|
+
validate :craziness
|
9
|
+
|
10
|
+
protected
|
11
|
+
def craziness
|
12
|
+
raise 'No way Jose' if "Matz" != "Guido van Rossum"
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
validates_presence_of :name, :age, :salary, :hired_on, :email, :first_name, :last_name
|
3
|
+
validates_uniqueness_of :name
|
4
|
+
validates_acceptance_of :terms_of_service
|
5
|
+
|
6
|
+
attr_accessor :password
|
7
|
+
|
8
|
+
|
9
|
+
# This is basically the main validation from restful_auth's user model.
|
10
|
+
validates_presence_of :password, :if => :password_required?
|
11
|
+
validates_presence_of :password_confirmation, :if => :password_required?
|
12
|
+
validates_length_of :password, :within => 4..40, :if => :password_required?
|
13
|
+
validates_confirmation_of :password, :if => :password_required?
|
14
|
+
validates_length_of :email, :within => 3..100
|
15
|
+
|
16
|
+
has_many :posts
|
17
|
+
has_one :profile
|
18
|
+
|
19
|
+
attr_accessible :email, :password, :password_confirmation
|
20
|
+
|
21
|
+
validate :custom_validation_method
|
22
|
+
validate :custom_private_method
|
23
|
+
|
24
|
+
def password_required?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def custom_validation_method
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def custom_private_method
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestBuilder < Test::Unit::TestCase
|
4
|
+
|
5
|
+
# Gives us DB access.
|
6
|
+
ActiveRecordTestConnector.setup
|
7
|
+
|
8
|
+
context 'ActiveRecord' do
|
9
|
+
|
10
|
+
should 'have the koujou method' do
|
11
|
+
assert User.respond_to?(:koujou)
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'return an instance of User, with ActiveRecord::Base as an ancestor' do
|
15
|
+
u = User.koujou
|
16
|
+
assert_equal User, u.class
|
17
|
+
assert u.class.ancestors.include?(ActiveRecord::Base)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'on sending the koujou message' do
|
22
|
+
|
23
|
+
should 'persist the record to the db without any arguments' do
|
24
|
+
u = User.koujou
|
25
|
+
assert !u.new_record?
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'return a new record when passing in false' do
|
29
|
+
u = User.koujou(false)
|
30
|
+
assert u.new_record?
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'have unique values for multiple instances where validates_uniqueness_of is defined for a column' do
|
34
|
+
u1 = User.koujou
|
35
|
+
u2 = User.koujou
|
36
|
+
assert_not_equal u1.name, u2.name
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'have a password confirmation automatically set' do
|
40
|
+
u = User.koujou
|
41
|
+
assert_not_nil u.password_confirmation
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'allow me to override the model attributes' do
|
45
|
+
namae = 'One Factory to Rule them all'
|
46
|
+
p = Post.koujou(true, :name => namae)
|
47
|
+
assert_equal namae, p.name
|
48
|
+
end
|
49
|
+
|
50
|
+
should 'allow me to override select attributes, yet still generate data for the rest' do
|
51
|
+
# We have a validates_length_of :bod, :is => 20 set.
|
52
|
+
bod = "T" * 20
|
53
|
+
p = Post.koujou_create(:body => bod)
|
54
|
+
assert_not_nil p.name
|
55
|
+
assert_equal bod, p.body
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'on sending the koujou_create message' do
|
61
|
+
|
62
|
+
should 'persist the record to the db' do
|
63
|
+
u = User.koujou_create
|
64
|
+
assert !u.new_record?
|
65
|
+
end
|
66
|
+
|
67
|
+
should 'allow me to override the model attributes' do
|
68
|
+
comment = 'your post is epic fail'
|
69
|
+
c = Comment.koujou_create(:bod => comment)
|
70
|
+
assert_equal comment, c.bod
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'not be sequenced unless I say so' do
|
74
|
+
u = User.koujou
|
75
|
+
# The first digit should not be an integer.
|
76
|
+
assert_equal 0, u.first_name[0,1].to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'on sending the koujou_build message' do
|
82
|
+
|
83
|
+
should 'return a new record' do
|
84
|
+
u = User.koujou_build
|
85
|
+
assert u.new_record?
|
86
|
+
end
|
87
|
+
|
88
|
+
should 'allow me to override the model attributes' do
|
89
|
+
clever = 'Whatever\'s clever'
|
90
|
+
p = Post.koujou_build(:name => clever)
|
91
|
+
assert_equal clever, p.name
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'associations' do
|
97
|
+
|
98
|
+
should 'not automatically create any assoications unless there\'s a validation for the id' do
|
99
|
+
u = User.koujou
|
100
|
+
assert_equal 0, u.posts.size
|
101
|
+
end
|
102
|
+
|
103
|
+
should 'automatically create a user for a profile when the profile has a required user_id validation' do
|
104
|
+
p = Profile.koujou
|
105
|
+
assert_not_nil p.user
|
106
|
+
end
|
107
|
+
|
108
|
+
should 'find custom validations' do
|
109
|
+
User.reflect_on_all_validations.each do |v|
|
110
|
+
puts v.inspect if v.macro == :validate
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'custom validations' do
|
117
|
+
|
118
|
+
should 'totally override any custom validations, and thus not fail when we call koujou' do
|
119
|
+
p = Post.koujou
|
120
|
+
assert true
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'inclusion_of_validation' do
|
126
|
+
|
127
|
+
should 'create the correct value for an attribute marked with validates_inclusion_of' do
|
128
|
+
c = Car.koujou
|
129
|
+
assert_equal 'Nissan', c.make
|
130
|
+
end
|
131
|
+
|
132
|
+
should 'create the correct values for inclusion when it\'s not also a required attribute' do
|
133
|
+
c = Car.koujou
|
134
|
+
assert_equal 1900, c.year
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestDataGenerator < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context 'on generate' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@validation = mock("ActiveRecord::Reflection::MacroReflection")
|
9
|
+
@validation.expects(:active_record).twice.returns(User)
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'generate a valid int' do
|
13
|
+
@validation.expects(:name).twice.returns('age')
|
14
|
+
int = Koujou::DataGenerator.new(false, @validation).generate_data_for_column_type
|
15
|
+
assert_kind_of Fixnum, int
|
16
|
+
assert int > 0
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'generate a valid float' do
|
20
|
+
@validation.expects(:name).twice.returns('salary')
|
21
|
+
float = Koujou::DataGenerator.new(false, @validation).generate_data_for_column_type
|
22
|
+
assert_kind_of Float, float
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'generate a valid string' do
|
26
|
+
@validation.expects(:name).times(1..10).returns('name')
|
27
|
+
string = Koujou::DataGenerator.new(false, @validation).generate_data_for_column_type
|
28
|
+
assert_kind_of String, string
|
29
|
+
assert string.size > 0
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'generate a valid email' do
|
33
|
+
@validation.expects(:name).times(1..10).returns('email')
|
34
|
+
email = Koujou::DataGenerator.new(false, @validation).generate_data_for_column_type
|
35
|
+
assert_match(/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, email)
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'generate a valid datetime' do
|
39
|
+
@validation.expects(:name).twice.returns('hired_on')
|
40
|
+
dt = Koujou::DataGenerator.new(false, @validation).generate_data_for_column_type
|
41
|
+
assert_kind_of DateTime, dt
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'always generate true for booleans' do
|
45
|
+
@validation.expects(:name).twice.returns('terms_of_service')
|
46
|
+
assert Koujou::DataGenerator.new(false, @validation).generate_data_for_column_type
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'on generate with a required length' do
|
52
|
+
setup do
|
53
|
+
@validation = mock("ActiveRecord::Reflection::MacroReflection")
|
54
|
+
@validation.expects(:active_record).twice.returns(Post)
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'generate the correct size string with a length passed in' do
|
58
|
+
@validation.expects(:name).twice.returns('body')
|
59
|
+
data_generator = Koujou::DataGenerator.new(false, @validation)
|
60
|
+
data_generator.required_length = 20
|
61
|
+
body = data_generator.generate_data_for_column_type
|
62
|
+
assert_equal 20, body.size
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'on generate with an inclusion' do
|
68
|
+
|
69
|
+
setup do
|
70
|
+
@validation = mock("ActiveRecord::Reflection::MacroReflection")
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'generate the correct string with an inclusion_value passed in' do
|
74
|
+
data_generator = Koujou::DataGenerator.new(false, @validation)
|
75
|
+
data_generator.inclusion_values = %w(Nissan Subaru)
|
76
|
+
make = data_generator.generate_data_for_column_type
|
77
|
+
assert_equal 'Nissan', make
|
78
|
+
end
|
79
|
+
|
80
|
+
should 'generate the correct int with an inclusion_value passed in' do
|
81
|
+
data_generator = Koujou::DataGenerator.new(false, @validation)
|
82
|
+
data_generator.inclusion_values = (1..3)
|
83
|
+
num = data_generator.generate_data_for_column_type
|
84
|
+
assert_equal 1, num
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'thoughtbot-shoulda'
|
5
|
+
require 'shoulda'
|
6
|
+
gem 'mocha'
|
7
|
+
require 'mocha'
|
8
|
+
require File.dirname(__FILE__) + '/../lib/koujou'
|
9
|
+
require File.join(File.dirname(__FILE__), 'lib', 'active_record_test_connector')
|
10
|
+
|
11
|
+
|
data/test/test_kojo.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestSequence < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "sequence" do
|
6
|
+
|
7
|
+
should "implement the singleton pattern" do
|
8
|
+
assert !Koujou::Sequence.respond_to?(:new)
|
9
|
+
assert Koujou::Sequence.include?(Singleton)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "generate successive numbers when calling next" do
|
13
|
+
first = Koujou::Sequence.instance.next
|
14
|
+
second = Koujou::Sequence.instance.next
|
15
|
+
assert_not_equal first, second
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mleung-koujou
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Leung
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-19 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: faker
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.3.1
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.3.2
|
34
|
+
version:
|
35
|
+
description: "Koujou is a fixture replacement that requires no effort to use. You don't have to define a single thing in your test_helper or whatever. Just call the koujou method on your active record model, and you're off. check out: http://www.michaelleung.us/koujou for all the juicy details."
|
36
|
+
email:
|
37
|
+
- me@michaelleung.us
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- History.txt
|
44
|
+
- Manifest.txt
|
45
|
+
- PostInstall.txt
|
46
|
+
files:
|
47
|
+
- History.txt
|
48
|
+
- Manifest.txt
|
49
|
+
- PostInstall.txt
|
50
|
+
- README.rdoc
|
51
|
+
- Rakefile
|
52
|
+
- lib/koujou.rb
|
53
|
+
- lib/koujou/builder.rb
|
54
|
+
- lib/koujou/data_generator.rb
|
55
|
+
- lib/koujou/sequence.rb
|
56
|
+
- lib/koujou/validation_reflection.rb
|
57
|
+
- script/console
|
58
|
+
- script/destroy
|
59
|
+
- script/generate
|
60
|
+
- test/lib/active_record_test_connector.rb
|
61
|
+
- test/lib/models/comment.rb
|
62
|
+
- test/lib/models/post.rb
|
63
|
+
- test/lib/models/profile.rb
|
64
|
+
- test/lib/models/user.rb
|
65
|
+
- test/test_builder.rb
|
66
|
+
- test/test_data_generator.rb
|
67
|
+
- test/test_helper.rb
|
68
|
+
- test/test_kojo.rb
|
69
|
+
- test/test_sequence.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://github.com/mleung/koujou
|
72
|
+
post_install_message: PostInstall.txt
|
73
|
+
rdoc_options:
|
74
|
+
- --main
|
75
|
+
- README.rdoc
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
version:
|
90
|
+
requirements: []
|
91
|
+
|
92
|
+
rubyforge_project: koujou
|
93
|
+
rubygems_version: 1.2.0
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: Koujou is a fixture replacement that requires no effort to use
|
97
|
+
test_files:
|
98
|
+
- test/test_builder.rb
|
99
|
+
- test/test_data_generator.rb
|
100
|
+
- test/test_helper.rb
|
101
|
+
- test/test_kojo.rb
|
102
|
+
- test/test_sequence.rb
|