koujou 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ module Koujou #:nodoc:
2
+ class Sequence # :nodoc:
3
+ include Singleton
4
+ def initialize
5
+ @current_value = 1
6
+ end
7
+ def next
8
+ @current_value += 1
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,143 @@
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
+ base.class_eval <<-"end_eval"
64
+ class << self
65
+ def #{validation_type}_with_reflection(*attr_names, &block)
66
+ ignoring_subvalidations(#{ignore_subvalidations}) do
67
+ #{validation_type}_without_reflection(*attr_names, &block)
68
+ remember_validation_metadata(:#{validation_type}, *attr_names)
69
+ end
70
+ end
71
+
72
+ alias_method_chain :#{validation_type}, :reflection
73
+ end
74
+ end_eval
75
+ end
76
+ end
77
+
78
+ module ClassMethods
79
+
80
+ # Returns an array of MacroReflection objects for all validations in the class
81
+ def reflect_on_all_validations
82
+ read_inheritable_attribute(:validations) || []
83
+ end
84
+
85
+ # Returns an array of MacroReflection objects for all validations defined for the field +attr_name+.
86
+ def reflect_on_validations_for(attr_name)
87
+ attr_name = attr_name.to_sym
88
+ reflect_on_all_validations.select do |reflection|
89
+ reflection.name == attr_name
90
+ end
91
+ end
92
+
93
+ # A few convenience methods added in by Mike. Why not loop and define_method these?
94
+
95
+ def unique_validations
96
+ reflect_on_all_validations.select{|v| v.macro == :validates_uniqueness_of }
97
+ end
98
+
99
+ def required_validations
100
+ reflect_on_all_validations.select{|v| v.macro == :validates_presence_of }
101
+ end
102
+
103
+ def confirmation_validations
104
+ reflect_on_all_validations.select{|v| v.macro == :validates_confirmation_of }
105
+ end
106
+
107
+ def length_validations
108
+ reflect_on_all_validations.select{|v| v.macro == :validates_length_of || v.macro == :validates_size_of }
109
+ end
110
+
111
+ def inclusion_validations
112
+ reflect_on_all_validations.select{|v| v.macro == :validates_inclusion_of }
113
+ end
114
+
115
+ def custom_validations
116
+ # We don't want to get anything like: validate_associated_records_for_posts.
117
+ reflect_on_all_validations.select{|v| v.macro == :validate && v.name.to_s.match("_associated_").nil? }
118
+ end
119
+
120
+ private
121
+
122
+ def remember_validation_metadata(validation_type, *attr_names)
123
+ configuration = attr_names.last.is_a?(Hash) ? attr_names.pop : {}
124
+ attr_names.each do |attr_name|
125
+ write_inheritable_array :validations,
126
+ [ ActiveRecord::Reflection::MacroReflection.new(validation_type, attr_name.to_sym, configuration, self) ]
127
+ end
128
+ end
129
+
130
+ def ignoring_subvalidations(ignore)
131
+ save_ignore = Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation
132
+ unless Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation
133
+ Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation = ignore
134
+ yield
135
+ end
136
+ ensure
137
+ Koujou::ActiveRecordExtensions::ValidationReflection.in_ignored_subvalidation = save_ignore
138
+ end
139
+ end
140
+
141
+ end
142
+ end
143
+ end
@@ -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"
@@ -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)
@@ -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,79 @@
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.text "about"
39
+ t.integer "age"
40
+ t.float "salary"
41
+ t.datetime "hired_on"
42
+ t.boolean "terms_of_service"
43
+ end
44
+ create_table "posts", :force => true do |t|
45
+ t.string "name"
46
+ t.text "body"
47
+ t.integer "user_id"
48
+ end
49
+ create_table "comments", :force => true do |t|
50
+ t.text "bod"
51
+ t.integer "post_id"
52
+ end
53
+ create_table "profiles", :force => true do |t|
54
+ t.integer "user_id"
55
+ t.boolean "likes_cheese"
56
+ end
57
+ create_table "photos", :force => true do |t|
58
+ t.integer "profile_id"
59
+ end
60
+ create_table "messages", :force => true do |t|
61
+ t.string "subject"
62
+ t.text "body"
63
+ t.datetime "created_at"
64
+ t.datetime "updated_at"
65
+ t.integer "sender_id"
66
+ t.integer "receiver_id"
67
+ t.boolean "read"
68
+ end
69
+ create_table "cars", :force => true do |t|
70
+ t.integer "user_id", "year"
71
+ t.string "make", "model"
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+
79
+
@@ -0,0 +1,7 @@
1
+ class Car < ActiveRecord::Base
2
+ belongs_to :owner, :class_name => 'User'
3
+ validates_presence_of :make, :model, :user_id
4
+
5
+ validates_inclusion_of :make, :in => %w(Nissan Subaru)
6
+ validates_inclusion_of :year, :in => 1900..2009
7
+ end
@@ -0,0 +1,7 @@
1
+ class Comment < ActiveRecord::Base
2
+ validates_presence_of :bod
3
+ validates_length_of :bod, :maximum => 200
4
+
5
+ belongs_to :post
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ class Message < ActiveRecord::Base
2
+ belongs_to :sender, :class_name => "Profile"
3
+ belongs_to :receiver, :class_name => "Profile"
4
+ validates_presence_of :body, :subject, :sender, :receiver
5
+ end
@@ -0,0 +1,3 @@
1
+ class Photo < ActiveRecord::Base
2
+ belongs_to :profile
3
+ end
@@ -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,9 @@
1
+ class Profile < ActiveRecord::Base
2
+ belongs_to :user
3
+ has_many :photos, :order => 'created_at DESC'
4
+
5
+ has_many :sent_messages, :class_name => 'Message', :order => 'created_at desc', :foreign_key => 'sender_id'
6
+
7
+ validates_presence_of :user_id
8
+
9
+ 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,150 @@
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
+ should 'cause a model to be invalid if you override a field that has validates_presence_of with a nil value' do
95
+ u = User.koujou_build(:email => nil)
96
+ assert !u.valid?
97
+ end
98
+ end
99
+
100
+ context 'associations' do
101
+
102
+ should 'not automatically create any assoications unless there\'s a validation for the id' do
103
+ u = User.koujou
104
+ assert_equal 0, u.posts.size
105
+ end
106
+
107
+ should 'automatically create a user for a profile when the profile has a required user_id validation' do
108
+ p = Profile.koujou
109
+ assert_not_nil p.user
110
+ end
111
+
112
+ should 'find custom validations' do
113
+ assert_equal 2, User.custom_validations.size
114
+ end
115
+
116
+ should 'car should have an owner association to user via class_name' do
117
+ c = Car.koujou
118
+ assert_not_nil c.owner
119
+ end
120
+
121
+ end
122
+
123
+ context 'custom validations' do
124
+
125
+ should 'totally override any custom validations, and thus not fail when we call koujou' do
126
+ p = Post.koujou
127
+ assert true
128
+ end
129
+
130
+ end
131
+
132
+ context 'inclusion_of_validation' do
133
+
134
+ should 'create the correct value for an attribute marked with validates_inclusion_of' do
135
+ c = Car.koujou
136
+ assert_equal 'Nissan', c.make
137
+ end
138
+
139
+ should 'create the correct values for inclusion when it\'s not also a required attribute' do
140
+ c = Car.koujou
141
+ assert_equal 1900, c.year
142
+ end
143
+
144
+ end
145
+
146
+
147
+ end
148
+
149
+
150
+