koujou 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+