classy-inheritance 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,6 @@
1
+ == 0.5.0 2008-07-08
2
+ * Add: new options: validates_presence_if, validates_associated_if to allow for greater control over validation use.
3
+ * Add: Basic test cases of classy-inheritance depends_on functionality.
1
4
  == 0.4.4 2008-06-24
2
5
  * Fix: :class_name attribute was not being recognized
3
6
  == 0.4.3 2008-06-24
@@ -26,8 +26,22 @@ module Stonean
26
26
  def depends_on(model_sym, options = {})
27
27
  define_relationship(model_sym,options)
28
28
 
29
- validates_presence_of model_sym
30
- validates_associated model_sym
29
+ # Optional presence of handling
30
+ if options.has_key?(:validates_presence_if) && options[:validates_presence_if] != true
31
+ if [Symbol, String, Proc].include?(options[:validates_presence_if].class)
32
+ validates_presence_of model_sym, :if => options[:validates_presence_if]
33
+ end
34
+ else
35
+ validates_presence_of model_sym
36
+ end
37
+
38
+ if options.has_key?(:validates_associated_if) && options[:validates_associated_if] != true
39
+ if [Symbol, String, Proc].include?(options[:validates_assoicated_if].class)
40
+ validates_associated model_sym, :if => options[:validates_associated_if]
41
+ end
42
+ else
43
+ validates_associated model_sym
44
+ end
31
45
 
32
46
  # Before save functionality to create/update the requisite object
33
47
  define_save_method(model_sym, options[:as])
@@ -63,9 +77,19 @@ module Stonean
63
77
 
64
78
  private
65
79
 
80
+ def classy_options
81
+ [:as, :attrs, :prefix, :validates_presence_if, :validates_associated_if]
82
+ end
83
+
84
+ def delete_classy_options(options, *keepers)
85
+ options.delete_if do |key,value|
86
+ classy_options.include?(key) && !keepers.include?(key)
87
+ end
88
+ options
89
+ end
90
+
66
91
  def define_relationship(model_sym, options)
67
- opts = options.dup
68
- [:attrs, :prefix].each{|key| opts.delete(key)}
92
+ opts = delete_classy_options(options.dup, :as)
69
93
  if opts[:as]
70
94
  as_opt = opts.delete(:as)
71
95
  opts = polymorphic_constraints(as_opt).merge(opts)
@@ -77,12 +101,17 @@ module Stonean
77
101
 
78
102
  def define_save_method(model_sym, polymorphic_name = nil)
79
103
  define_method "save_requisite_#{model_sym}" do
104
+ # Return unless the association exists
105
+ eval("return unless self.#{model_sym}")
106
+
107
+ # Set the polymorphic type and id before saving
80
108
  if polymorphic_name
81
109
  eval("self.#{model_sym}.#{polymorphic_name}_type = self.class.name")
82
110
  eval("self.#{model_sym}.#{polymorphic_name}_id = self.id")
83
111
  end
84
112
 
85
113
  if polymorphic_name
114
+ # Save only if it's an update, has_one creates automatically
86
115
  eval <<-SAVEIT
87
116
  unless self.#{model_sym}.new_record?
88
117
  self.#{model_sym}.save
@@ -1,8 +1,8 @@
1
1
  module ClassyInheritance #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 4
5
- TINY = 4
4
+ MINOR = 5
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,11 +1,61 @@
1
1
  require File.dirname(__FILE__) + '/test_helper.rb'
2
2
 
3
+ User.depends_on :profile, :attrs => [:first_name, :last_name, :email]
4
+
3
5
  class TestClassyInheritance < Test::Unit::TestCase
4
6
 
5
7
  def setup
8
+ @user = User.new
9
+ end
10
+
11
+ def test_active_record_should_have_classy_inheritance_included
12
+ assert ActiveRecord::Base.included_modules.include?(Stonean::ClassyInheritance)
13
+ end
14
+
15
+ def test_active_record_should_respond_to_depends_on
16
+ assert ActiveRecord::Base.respond_to?(:depends_on)
17
+ end
18
+
19
+ def test_user_should_respond_to_find_with_profile
20
+ assert User.respond_to?(:find_with_profile)
21
+ end
22
+
23
+ def test_user_should_respond_to_first_name
24
+ assert @user.respond_to?(:first_name)
25
+ end
26
+
27
+ def test_user_should_respond_to_first_name=
28
+ assert @user.respond_to?(:first_name=)
6
29
  end
7
30
 
8
- def test_truth
9
- assert true
31
+ def test_user_should_respond_to_last_name
32
+ assert @user.respond_to?(:last_name)
10
33
  end
34
+
35
+ def test_user_should_respond_to_last_name=
36
+ assert @user.respond_to?(:last_name=)
37
+ end
38
+
39
+ def test_user_should_respond_to_email
40
+ assert @user.respond_to?(:email)
41
+ end
42
+
43
+ def test_user_should_respond_to_email=
44
+ assert @user.respond_to?(:email=)
45
+ end
46
+
47
+ def test_user_should_be_invalid_without_profile_attributes
48
+ @user.login = 'joe'
49
+ assert !@user.valid?
50
+ end
51
+
52
+ def test_user_should_valid_with_profile_attributes
53
+ @user.login = 'joe'
54
+ @user.first_name = 'joe'
55
+ @user.last_name = 'bloggs'
56
+ @user.email = 'joe@bloggs.co.uk'
57
+
58
+ assert @user.valid?
59
+ end
60
+
11
61
  end
data/test/test_helper.rb CHANGED
@@ -1,2 +1,136 @@
1
+ require 'rubygems'
2
+ require 'activerecord'
3
+
1
4
  require 'test/unit'
2
5
  require File.dirname(__FILE__) + '/../lib/classy-inheritance'
6
+
7
+ ActiveRecord::Base.establish_connection({
8
+ :adapter => "sqlite3",
9
+ :dbfile => "test/database.sqlite3"
10
+ })
11
+
12
+ class SetupTestTables < ActiveRecord::Migration
13
+ def self.up
14
+ create_table :profiles, :force => true do |t|
15
+ t.string :first_name
16
+ t.string :last_name
17
+ t.string :email
18
+
19
+ t.timestamps
20
+ end
21
+
22
+ create_table :users, :force => true do |t|
23
+ t.string :login
24
+ t.integer :profile_id
25
+
26
+ t.timestamps
27
+ end
28
+
29
+ create_table :authors, :force => true do |t|
30
+ t.string :login
31
+ t.integer :profile_id
32
+
33
+ t.timestamps
34
+ end
35
+
36
+ create_table :artists, :force => true do |t|
37
+ t.string :login
38
+ t.integer :profile_id
39
+
40
+ t.timestamps
41
+ end
42
+
43
+ create_table :addresses, :force => true do |t|
44
+ t.string :line_one
45
+ t.string :line_two
46
+ t.string :city
47
+ t.string :state_code
48
+ t.string :postal_code
49
+
50
+ t.timestamps
51
+ end
52
+
53
+ create_table :offices, :force => true do |t|
54
+ t.string :name
55
+ t.integer :billing_address_id
56
+ t.integer :shipping_address_id
57
+
58
+ t.timestamps
59
+ end
60
+
61
+ create_table :contents, :force => true do |t|
62
+ t.string :name
63
+ t.string :presentable_type
64
+ t.integer :presentable_id
65
+
66
+ t.timestamps
67
+ end
68
+
69
+ create_table :pages, :force => true do |t|
70
+ t.text :body
71
+
72
+ t.timestamps
73
+ end
74
+
75
+ create_table :documents, :force => true do |t|
76
+ t.string :version_file_name
77
+ t.string :version_content_type
78
+ t.integer :version_file_size
79
+
80
+ t.timestamps
81
+ end
82
+ end
83
+
84
+ def self.down
85
+ drop_table :authors
86
+ drop_table :artists
87
+ drop_table :users
88
+ drop_table :profiles
89
+ drop_table :offices
90
+ drop_table :addresses
91
+ drop_table :pages
92
+ drop_table :documents
93
+ drop_table :contents
94
+ end
95
+ end
96
+
97
+ SetupTestTables.migrate(:up)
98
+
99
+ class Profile < ActiveRecord::Base
100
+ validates_presence_of :first_name, :last_name, :email
101
+ end
102
+
103
+ class User < ActiveRecord::Base
104
+ validates_presence_of :login
105
+ end
106
+
107
+ class Author < ActiveRecord::Base
108
+ validates_presence_of :login
109
+ end
110
+
111
+ # to test optional dependency
112
+ class Artist < ActiveRecord::Base
113
+ validates_presence_of :login
114
+ end
115
+
116
+ # to test using standard relationship options (class_name, etc..)
117
+ class Address < ActiveRecord::Base
118
+ validates_presence_of :line_one, :city, :postal_code
119
+ end
120
+
121
+ class Office < ActiveRecord::Base
122
+ validates_presence_of :name
123
+ end
124
+
125
+ # Polymorphic classes
126
+ class Content < ActiveRecord::Base
127
+ validates_presence_of :name
128
+ end
129
+
130
+ class Page < ActiveRecord::Base
131
+ validates_presence_of :body
132
+ end
133
+
134
+ # Would typically use PaperClip for this...
135
+ class Document < ActiveRecord::Base
136
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ Content.can_be :document, :as => :presentable
4
+
5
+ Page.depends_on :content, :attrs => [:name], :as => :presentable
6
+
7
+ class TestPolymorphicAssociations < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @page = Page.new
11
+
12
+ @test_page = Page.create(:name => 'My Page', :body => 'Something interesting')
13
+ @test_content = @test_page.content
14
+ end
15
+
16
+ # from Content.can_be declaration
17
+ def test_document_should_respond_to_find_with_content
18
+ assert Document.respond_to?(:find_with_content)
19
+ end
20
+
21
+ def test_page_should_respond_to_name
22
+ assert @page.respond_to?(:name)
23
+ end
24
+
25
+ def test_page_should_fail_validation_without_content_name
26
+ @page.body = 'Some really informative stuff that would be a lot longer'
27
+ assert !@page.valid?
28
+ end
29
+
30
+ def test_page_should_pass_validation_with_content_name
31
+ @page.name = 'First Page'
32
+ @page.body = 'Some really informative stuff that would be a lot longer'
33
+ assert @page.valid?
34
+ end
35
+
36
+ def test_page_should_create_content
37
+ @page.name = 'First Page'
38
+ @page.body = 'Some really informative stuff that would be a lot longer'
39
+ @page.save
40
+
41
+ assert @page.content.id != nil
42
+ end
43
+
44
+ def test_content_should_respond_to_is_a_document
45
+ assert @test_content.respond_to?(:is_a_document?)
46
+ end
47
+
48
+ def test_content_should_respond_to_as_a_document
49
+ assert @test_content.respond_to?(:as_a_document)
50
+ end
51
+
52
+ def test_content_should_respond_to_is_a_page
53
+ assert @test_content.respond_to?(:is_a_page?)
54
+ end
55
+
56
+ def test_content_should_respond_to_as_a_page
57
+ assert @test_content.respond_to?(:as_a_page)
58
+ end
59
+
60
+ def test_content_should_return_page_object
61
+ assert @test_content.as_a_page.is_a?(Page)
62
+ end
63
+
64
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestWithOptionalDependency < Test::Unit::TestCase
4
+ # Turn off the validates_presence_of call
5
+ Author.depends_on :profile, :validates_presence_if => false,
6
+ :attrs => [:first_name, :last_name, :email]
7
+
8
+ # Turn off the validates_presence_of and the validates_associated calls
9
+ Artist.depends_on :profile, :validates_presence_if => false,
10
+ :validates_associated_if => false,
11
+ :attrs => [:first_name, :last_name, :email]
12
+
13
+ def setup
14
+ @author = Author.new
15
+ @artist = Artist.new
16
+ end
17
+
18
+ def test_author_should_be_valid_without_profile
19
+ @author.login = 'joe'
20
+
21
+ @author.valid?
22
+ puts @author.errors.full_messages.to_sentence
23
+
24
+ assert @author.valid?
25
+ end
26
+
27
+ def test_author_should_be_invalid_with_invalid_profile
28
+ @author.login = 'joe'
29
+ @author.first_name = 'joe'
30
+
31
+ assert !@author.valid?
32
+ end
33
+
34
+ def test_author_should_be_valid_with_profile_attributes
35
+ @author.login = 'joe'
36
+ @author.first_name = 'joe'
37
+ @author.last_name = 'bloggs'
38
+ @author.email = 'joe@bloggs.co.uk'
39
+
40
+ assert @author.valid?
41
+ end
42
+
43
+ def test_artist_should_not_save_with_invalid_profile
44
+ @artist.login = 'joe'
45
+ @artist.first_name = 'joe'
46
+
47
+ assert !@artist.save
48
+ end
49
+
50
+ def test_artist_should_save_with_valid_profile
51
+ @artist.login = 'joe'
52
+ @artist.first_name = 'joe'
53
+ @artist.last_name = 'bloggs'
54
+ @artist.email = 'joe@bloggs.co.uk'
55
+
56
+ assert @artist.save
57
+ end
58
+
59
+ end
@@ -0,0 +1,82 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ Office.depends_on :billing_address,
4
+ :attrs => [:line_one, :line_two, :city, :state_code, :postal_code],
5
+ :class_name => "Address",
6
+ :foreign_key => "billing_address_id",
7
+ :prefix => true
8
+
9
+ Office.depends_on :shipping_address,
10
+ :attrs => [:line_one, :line_two, :city, :state_code, :postal_code],
11
+ :class_name => "Address",
12
+ :foreign_key => "shipping_address_id",
13
+ :prefix => true
14
+
15
+ class TestWithStandardAttributes < Test::Unit::TestCase
16
+ def setup
17
+ @office = Office.new
18
+ end
19
+
20
+ def test_office_should_respond_to_billing_address_line_one
21
+ assert_respond_to(@office, :billing_address_line_one)
22
+ end
23
+
24
+ def test_office_should_respond_to_billing_address_line_two
25
+ assert_respond_to(@office, :billing_address_line_two)
26
+ end
27
+
28
+ def test_office_should_respond_to_billing_address_city
29
+ assert_respond_to(@office, :billing_address_city)
30
+ end
31
+
32
+ def test_office_should_respond_to_billing_address_state_code
33
+ assert_respond_to(@office, :billing_address_state_code)
34
+ end
35
+
36
+ def test_office_should_respond_to_billing_address_postal_code
37
+ assert_respond_to(@office, :billing_address_postal_code)
38
+ end
39
+
40
+ def test_office_should_respond_to_shipping_address_line_one
41
+ assert_respond_to(@office, :shipping_address_line_one)
42
+ end
43
+
44
+ def test_office_should_respond_to_shipping_address_line_two
45
+ assert_respond_to(@office, :shipping_address_line_two)
46
+ end
47
+
48
+ def test_office_should_respond_to_shipping_address_city
49
+ assert_respond_to(@office, :shipping_address_city)
50
+ end
51
+
52
+ def test_office_should_respond_to_shipping_address_state_code
53
+ assert_respond_to(@office, :shipping_address_state_code)
54
+ end
55
+
56
+ def test_office_should_respond_to_shipping_address_postal_code
57
+ assert_respond_to(@office, :shipping_address_postal_code)
58
+ end
59
+
60
+ def test_office_should_create_billing_and_shipping_address_records
61
+ @office.name = 'Initest'
62
+
63
+ @office.billing_address_line_one = '123 Somewhere'
64
+ @office.billing_address_city = 'Somecity'
65
+ @office.billing_address_postal_code = '12345'
66
+
67
+ @office.shipping_address_line_one = '999 MyHouse'
68
+ @office.shipping_address_city = 'Mycity'
69
+ @office.shipping_address_postal_code = '98765'
70
+
71
+ @office.save
72
+
73
+ @billing_address = Address.find(@office.billing_address_id)
74
+ @shipping_address = Address.find(@office.shipping_address_id)
75
+
76
+ assert_equal @billing_address, @office.billing_address
77
+
78
+ assert_equal @shipping_address, @office.shipping_address
79
+ end
80
+
81
+
82
+ end
data/website/index.html CHANGED
@@ -33,7 +33,7 @@
33
33
  <h1>Classy Inheritance</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/classyinherit"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/classyinherit" class="numbers">0.4.4</a>
36
+ <a href="http://rubyforge.org/projects/classyinherit" class="numbers">0.5.0</a>
37
37
  </div>
38
38
  <p><i>&#8220;You stay classy, inheritance&#8221; &#8211; Gibson</i></p>
39
39
 
@@ -56,7 +56,7 @@
56
56
  <p>Thanks for your interest in Classy Inheritance,<br/>
57
57
  -andy</p>
58
58
  <p class="coda">
59
- <a href="http://blog.stonean.com">Andrew Stone</a>, 24th June 2008<br>
59
+ <a href="http://blog.stonean.com">Andrew Stone</a>, 8th July 2008<br>
60
60
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
61
61
  </p>
62
62
  </div>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: classy-inheritance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Stone
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-24 00:00:00 -04:00
12
+ date: 2008-07-08 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -84,3 +84,6 @@ summary: Adds a depends_on class method to your ActiveRecord model so that you c
84
84
  test_files:
85
85
  - test/test_classy-inheritance.rb
86
86
  - test/test_helper.rb
87
+ - test/test_polymorphic_associations.rb
88
+ - test/test_with_optional_dependency.rb
89
+ - test/test_with_standard_attributes.rb