classy-inheritance 0.4.4 → 0.5.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.
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