classy-inheritance 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,22 @@
1
+ == 0.7.0 2009-04-11
2
+ * merge all of johnsbrn changes
3
+ == 0.6.8.2 2009-03-19
4
+ * have fixed problems with class_name ending with ss
5
+ == 0.6.8.1 2009-03-19
6
+ * Update for Rails 2.3 - johnsbrn
7
+ == 0.6.8 2009-02-03
8
+ * Make has_one fix consistent with edge Rails - johnsbrn
9
+ == 0.6.7 2009-02-01
10
+ * Forgot to remove some debugging code -johnsbrn
11
+ == 0.6.6 2009-02-01
12
+ * More comprehensive fix for has_one bug - johnsbrn
13
+ == 0.6.5 2009-02-01
14
+ * Add fix for has_one primary key bug - http://rails.lighthouseapp.com/projects/8994/tickets/1756-has_one-with-foreign_key-primary_key-bug - johnsbrn
15
+ == 0.6.4 2009-02-01
16
+ * Updated deprecated default error messages - johnsbrn
17
+ * Added has_dependency for non-polymorphic has_one - johnsbrn
18
+ == 0.6.3 2009-01-13
19
+ * Fixed validations for prefix and postfix - johnsbrn
1
20
  == 0.6.2 2008-09-25
2
21
  * Added back validates_associated override.
3
22
  == 0.6.1 2008-07-21
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{classy-inheritance}
5
+ s.version = "0.7.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Andrew Stone"]
9
+ s.date = %q{2009-03-19}
10
+ s.description = %q{Classy Inheritance adds a depends_on class method to your ActiveRecord model so that you can define requisite objects. This functionality is provided using the existing ActiveRecord methods without monkey patching any core code. Essentially, it provides an easy interface to generate code that anyone could add to their model to receive the same result. Depending on the parameters to your depends_on call, it may add some of the following methods: validates_presence_of, validates_associated, has_one or belongs_to.}
11
+ s.email = %q{andy@stonean.com}
12
+ s.extra_rdoc_files = ["History.txt", "License.txt", "README.txt"]
13
+ s.files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/classy-inheritance.rb", "test/test_classy-inheritance.rb", "test/test_helper.rb", "test/test_polymorphic_associations.rb", "test/test_with_optional_dependency.rb", "test/test_with_prefix_postfix.rb", "test/test_with_standard_attributes.rb", "test/test_has_dependency.rb", "test/test_with_class_name_ending_with_ss.rb"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://stonean.com/wiki/classy-inheritance}
16
+ s.rdoc_options = ["--main", "README.txt"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{classyinherit}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Classy Inheritance adds a depends_on class method to your ActiveRecord model so that you can define requisite objects}
21
+ s.test_files = ["test/test_classy-inheritance.rb", "test/test_has_dependency.rb", "test/test_helper.rb", "test/test_polymorphic_associations.rb", "test/test_with_class_name_ending_with_ss.rb", "test/test_with_optional_dependency.rb", "test/test_with_prefix_postfix.rb", "test/test_with_standard_attributes.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<bones>, [">= 2.2.0"])
29
+ else
30
+ s.add_dependency(%q<bones>, [">= 2.2.0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<bones>, [">= 2.2.0"])
34
+ end
35
+ end
@@ -1,13 +1,114 @@
1
+ require 'active_record/version'
2
+ module ActiveRecord
3
+ module Associations
4
+ class HasOneAssociation
5
+
6
+ # this is fixed in 2.3, but it doesn't hurt to leave it here
7
+ def set_belongs_to_association_for(record)
8
+ if @reflection.options[:as]
9
+ record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
10
+ record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
11
+ else
12
+ unless @owner.new_record?
13
+ primary_key = @reflection.options[:primary_key] || :id
14
+ record[@reflection.primary_key_name] = @owner.send(primary_key)
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+ #this is still not fixed in 2.3
21
+ def new_record(replace_existing)
22
+ # Make sure we load the target first, if we plan on replacing the existing
23
+ # instance. Otherwise, if the target has not previously been loaded
24
+ # elsewhere, the instance we create will get orphaned.
25
+ load_target if replace_existing
26
+ record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) do
27
+ yield @reflection
28
+ end
29
+
30
+ if replace_existing
31
+ replace(record, true)
32
+ else
33
+ unless @owner.new_record?
34
+ primary_key = @reflection.options[:primary_key] || :id
35
+ record[@reflection.primary_key_name] = @owner.send(primary_key)
36
+ end
37
+ self.target = record
38
+ end
39
+
40
+ record
41
+ end
42
+ end
43
+ end
44
+
45
+ if ActiveRecord::VERSION::MAJOR == 2 && ActiveRecord::VERSION::MINOR == 3
46
+
47
+ module AutosaveAssociation
48
+
49
+ # fix active record has_one primary key bug rails 2.3 - http://rails.lighthouseapp.com/projects/8994/tickets/1756-has_one-with-foreign_key-primary_key-bug
50
+ def save_has_one_association(reflection)
51
+ if (association = association_instance_get(reflection.name)) && !association.target.nil?
52
+ primary_key = reflection.options[:primary_key] || :id
53
+ if reflection.options[:autosave] && association.marked_for_destruction?
54
+ association.destroy
55
+ elsif new_record? || association.new_record? || association[reflection.primary_key_name] != send(primary_key) || reflection.options[:autosave]
56
+ association[reflection.primary_key_name] = send(primary_key)
57
+ association.save(false)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+ end
1
65
 
2
66
  module Stonean
3
67
  module ClassyInheritance
4
- VERSION = '0.6.4'
68
+ VERSION = '0.7.0'
5
69
 
6
70
  def self.version
7
71
  VERSION
8
72
  end
9
-
73
+
10
74
  module ClassMethods
75
+
76
+
77
+ # fix active record has_one primary key bug rails 2.2.2 - http://rails.lighthouseapp.com/projects/8994/tickets/1756-has_one-with-foreign_key-primary_key-bug
78
+ if ActiveRecord::VERSION::MAJOR == 2 && ActiveRecord::VERSION::MINOR == 2
79
+
80
+ def has_one(association_id, options = {})
81
+ if options[:through]
82
+ reflection = create_has_one_through_reflection(association_id, options)
83
+ association_accessor_methods(reflection, ActiveRecord::Associations::HasOneThroughAssociation)
84
+ else
85
+ reflection = create_has_one_reflection(association_id, options)
86
+
87
+ ivar = "@#{reflection.name}"
88
+
89
+ method_name = "has_one_after_save_for_#{reflection.name}".to_sym
90
+ define_method(method_name) do
91
+ association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
92
+
93
+ primary_key = reflection.options[:primary_key] || :id
94
+ if !association.nil? && (new_record? || association.new_record? || association[reflection.primary_key_name] != send(primary_key))
95
+ association[reflection.primary_key_name] = send(primary_key)
96
+ association.save(true)
97
+ end
98
+ end
99
+ after_save method_name
100
+
101
+ add_single_associated_validation_callbacks(reflection.name) if options[:validate] == true
102
+ association_accessor_methods(reflection, ActiveRecord::Associations::HasOneAssociation)
103
+ association_constructor_method(:build, reflection, ActiveRecord::Associations::HasOneAssociation)
104
+ association_constructor_method(:create, reflection, ActiveRecord::Associations::HasOneAssociation)
105
+
106
+ configure_dependency_for_has_one(reflection)
107
+ end
108
+ end
109
+
110
+ end
111
+
11
112
  def depends_on(model_sym, options = {})
12
113
  define_relationship(model_sym,options)
13
114
 
@@ -41,7 +142,10 @@ module Stonean
41
142
  options[:attrs].each{|attr| define_accessors(model_sym, attr, options)}
42
143
  end
43
144
 
44
-
145
+ def has_dependency(model_sym, options = {})
146
+ depends_on(model_sym, options.update(:has_dependency => true))
147
+ end
148
+
45
149
  def can_be(model_sym, options = {})
46
150
  unless options[:as]
47
151
  raise ArgumentError, ":as attribute required when calling can_be"
@@ -63,7 +167,7 @@ module Stonean
63
167
  private
64
168
 
65
169
  def classy_options
66
- [:as, :attrs, :prefix, :postfix, :validates_presence_if, :validates_associated_if]
170
+ [:as, :attrs, :has_dependency, :prefix, :postfix, :validates_presence_if, :validates_associated_if]
67
171
  end
68
172
 
69
173
  def delete_classy_options(options, *keepers)
@@ -79,6 +183,8 @@ module Stonean
79
183
  as_opt = opts.delete(:as)
80
184
  opts = polymorphic_constraints(as_opt).merge(opts)
81
185
  has_one model_sym, opts
186
+ elsif options[:has_dependency]
187
+ has_one model_sym, opts
82
188
  else
83
189
  belongs_to model_sym, opts
84
190
  end
@@ -139,7 +245,7 @@ module Stonean
139
245
  if options[:postfix]
140
246
  accessor_method_name = (options[:postfix] == true) ? "#{accessor_method_name}_#{model_sym}" : "#{accessor_method_name}_#{options[:postfix]}"
141
247
  end
142
-
248
+
143
249
  define_method accessor_method_name do
144
250
  eval("self.#{model_sym} ? self.#{model_sym}.#{attr} : nil")
145
251
  end
@@ -177,7 +283,7 @@ if Object.const_defined?("ActiveRecord") && ActiveRecord.const_defined?("Base")
177
283
  module ActiveRecord::Validations::ClassMethods
178
284
 
179
285
  def validates_associated_dependent(model_sym, options, configuration = {})
180
- configuration = { :message => I18n.translate('activerecord.errors.messages.invalid'), :on => :save }.update(configuration)
286
+ configuration = { :message => I18n.translate('activerecord.errors.messages')[:invalid], :on => :save }.update(configuration)
181
287
 
182
288
  validates_each(model_sym, configuration) do |record, attr_name, value|
183
289
  associate = record.send(attr_name)
@@ -195,9 +301,9 @@ if Object.const_defined?("ActiveRecord") && ActiveRecord.const_defined?("Base")
195
301
  end
196
302
  end
197
303
  end
198
-
199
-
304
+
200
305
  ActiveRecord::Base.class_eval do
201
306
  extend Stonean::ClassyInheritance::ClassMethods
202
307
  end
308
+
203
309
  end
@@ -19,10 +19,11 @@ namespace :doc do
19
19
  end
20
20
  rd.rdoc_files.push(*files)
21
21
 
22
- title = "#{PROJ.name}-#{PROJ.version} Documentation"
23
-
22
+ name = PROJ.name
24
23
  rf_name = PROJ.rubyforge.name
25
- title = "#{rf_name}'s " + title if rf_name.valid? and rf_name != title
24
+
25
+ title = "#{name}-#{PROJ.version} Documentation"
26
+ title = "#{rf_name}'s " + title if rf_name.valid? and rf_name != name
26
27
 
27
28
  rd.options << "-t #{title}"
28
29
  rd.options.concat(rdoc.opts)
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  require 'ostruct'
7
7
  require 'find'
8
8
 
9
- class OpenStruct; undef :gem; end
9
+ class OpenStruct; undef :gem if defined? :gem; end
10
10
 
11
11
  # TODO: make my own openstruct type object that includes descriptions
12
12
  # TODO: use the descriptions to output help on the available bones options
@@ -124,9 +124,7 @@ import(*rakefiles)
124
124
  %w(lib ext).each {|dir| PROJ.libs << dir if test ?d, dir}
125
125
 
126
126
  # Setup some constants
127
- WIN32 = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WIN32
128
-
129
- DEV_NULL = WIN32 ? 'NUL:' : '/dev/null'
127
+ DEV_NULL = File.exist?('/dev/null') ? '/dev/null' : 'NUL:'
130
128
 
131
129
  def quiet( &block )
132
130
  io = [STDOUT.dup, STDERR.dup]
@@ -139,21 +137,15 @@ ensure
139
137
  $stdout, $stderr = STDOUT, STDERR
140
138
  end
141
139
 
142
- DIFF = if WIN32 then 'diff.exe'
143
- else
144
- if quiet {system "gdiff", __FILE__, __FILE__} then 'gdiff'
145
- else 'diff' end
146
- end unless defined? DIFF
147
-
148
- SUDO = if WIN32 then ''
149
- else
150
- if quiet {system 'which sudo'} then 'sudo'
151
- else '' end
152
- end
153
-
154
- RCOV = WIN32 ? 'rcov.bat' : 'rcov'
155
- RDOC = WIN32 ? 'rdoc.bat' : 'rdoc'
156
- GEM = WIN32 ? 'gem.bat' : 'gem'
140
+ DIFF = if system("gdiff '#{__FILE__}' '#{__FILE__}' > #{DEV_NULL} 2>&1") then 'gdiff'
141
+ else 'diff' end unless defined? DIFF
142
+
143
+ SUDO = if system("which sudo > #{DEV_NULL} 2>&1") then 'sudo'
144
+ else '' end unless defined? SUDO
145
+
146
+ RCOV = "#{RUBY} -S rcov"
147
+ RDOC = "#{RUBY} -S rdoc"
148
+ GEM = "#{RUBY} -S gem"
157
149
 
158
150
  %w(rcov spec/rake/spectask rubyforge bones facets/ansicode).each do |lib|
159
151
  begin
@@ -1,10 +1,9 @@
1
1
  require File.dirname(__FILE__) + '/test_helper.rb'
2
2
 
3
- User.depends_on :profile, :attrs => [:first_name, :last_name, :email]
4
-
5
3
  class TestClassyInheritance < Test::Unit::TestCase
6
4
 
7
5
  def setup
6
+ User.depends_on :profile, :attrs => [:first_name, :last_name, :email]
8
7
  @user = User.new
9
8
  end
10
9
 
@@ -0,0 +1,91 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestHasDependency < Test::Unit::TestCase
4
+
5
+ def setup
6
+ Account.has_dependency :account_login, :attrs => [:login, :password], :foreign_key => :account_email, :primary_key => :email
7
+ Database.has_dependency :database_login, :attrs => [:login]
8
+ @account = Account.new
9
+ @database = Database.new
10
+ end
11
+
12
+ def test_active_record_should_respond_to_depends_on
13
+ assert ActiveRecord::Base.respond_to?(:has_dependency)
14
+ end
15
+
16
+ def test_account_should_respond_to_find_with_account_login
17
+ assert Account.respond_to?(:find_with_account_login)
18
+ end
19
+
20
+ def test_account_should_respond_to_login
21
+ assert @account.respond_to?(:login)
22
+ end
23
+
24
+ def test_account_should_respond_to_login=
25
+ assert @account.respond_to?(:login=)
26
+ end
27
+
28
+ def test_account_should_respond_to_password
29
+ assert @account.respond_to?(:password)
30
+ end
31
+
32
+ def test_account_should_respond_to_password=
33
+ assert @account.respond_to?(:password=)
34
+ end
35
+
36
+ def test_profile_should_create_author_record
37
+ @database.name = 'page'
38
+ @database.login = 'joe'
39
+
40
+ @database.save!
41
+
42
+ @database_login = DatabaseLogin.find(:first, :conditions => {:database_id => @database.id})
43
+
44
+ assert_equal 'joe', @database_login.login
45
+ end
46
+
47
+ def test_account_should_create_account_login_record
48
+ @account.login = 'joe'
49
+ @account.password = 'password'
50
+ @account.first_name = 'joe'
51
+ @account.last_name = 'bloggs'
52
+ @account.email = 'joe@bloggs.co.uk'
53
+
54
+ @account.save
55
+
56
+ @account_login = AccountLogin.find(:first, :conditions => {:account_email => @account.email})
57
+
58
+ assert_equal @account_login, @account.account_login
59
+
60
+ assert_equal @account_login.login, @account.login
61
+ assert_equal @account_login.password, @account.password
62
+ end
63
+
64
+ def test_account_should_be_invalid_without_account_login_attributes
65
+ @account.first_name = 'joe'
66
+ @account.last_name = 'bloggs'
67
+ @account.email = 'joe@bloggs.co.uk'
68
+ assert !@account.valid?
69
+ end
70
+
71
+ def test_account_should_be_valid_with_account_login_attributes
72
+ @account.login = 'joe'
73
+ @account.password = 'password'
74
+ @account.first_name = 'joe'
75
+ @account.last_name = 'bloggs'
76
+ @account.email = 'joe@bloggs.co.uk'
77
+
78
+ assert @account.valid?
79
+ end
80
+
81
+ def test_account_should_have_nice_error_message
82
+ @account = Account.new(:login => "joe")
83
+ @account.valid?
84
+
85
+ assert @account.errors.full_messages.include?("Last name can't be blank")
86
+ assert @account.errors.full_messages.include?("Email can't be blank")
87
+ assert @account.errors.full_messages.include?("First name can't be blank")
88
+ assert @account.errors.full_messages.include?("Password can't be blank")
89
+ end
90
+
91
+ end
@@ -1,6 +1,8 @@
1
1
  require 'rubygems'
2
2
  require 'activerecord'
3
3
 
4
+ ActiveRecord.load_all!
5
+
4
6
  require 'test/unit'
5
7
  require File.dirname(__FILE__) + '/../lib/classy-inheritance'
6
8
 
@@ -19,6 +21,22 @@ class SetupTestTables < ActiveRecord::Migration
19
21
  t.timestamps
20
22
  end
21
23
 
24
+ create_table :accounts, :force => true do |t|
25
+ t.string :first_name
26
+ t.string :last_name
27
+ t.string :email
28
+
29
+ t.timestamps
30
+ end
31
+
32
+ create_table :account_logins, :force => true do |t|
33
+ t.string :login
34
+ t.string :password
35
+ t.string :account_email
36
+
37
+ t.timestamps
38
+ end
39
+
22
40
  create_table :users, :force => true do |t|
23
41
  t.string :login
24
42
  t.integer :profile_id
@@ -40,6 +58,17 @@ class SetupTestTables < ActiveRecord::Migration
40
58
  t.timestamps
41
59
  end
42
60
 
61
+ create_table :databases, :force => true do |t|
62
+ t.string :name
63
+ t.timestamps
64
+ end
65
+
66
+ create_table :database_logins, :force => true do |t|
67
+ t.string :login
68
+ t.integer :database_id
69
+ t.timestamps
70
+ end
71
+
43
72
  create_table :addresses, :force => true do |t|
44
73
  t.string :line_one
45
74
  t.string :line_two
@@ -84,6 +113,8 @@ class SetupTestTables < ActiveRecord::Migration
84
113
  end
85
114
 
86
115
  def self.down
116
+ drop_table :accounts
117
+ drop_table :account_logins
87
118
  drop_table :authors
88
119
  drop_table :artists
89
120
  drop_table :users
@@ -102,6 +133,22 @@ class Profile < ActiveRecord::Base
102
133
  validates_presence_of :first_name, :last_name, :email
103
134
  end
104
135
 
136
+ class Database < ActiveRecord::Base
137
+ validates_presence_of :name
138
+ end
139
+
140
+ class DatabaseLogin < ActiveRecord::Base
141
+ validates_presence_of :login
142
+ end
143
+
144
+ class Account < ActiveRecord::Base
145
+ validates_presence_of :first_name, :last_name, :email
146
+ end
147
+
148
+ class AccountLogin < ActiveRecord::Base
149
+ validates_presence_of :login, :password
150
+ end
151
+
105
152
  class User < ActiveRecord::Base
106
153
  validates_presence_of :login
107
154
  end
@@ -1,16 +1,17 @@
1
1
  require File.dirname(__FILE__) + '/test_helper.rb'
2
2
 
3
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
4
 
13
5
  def setup
6
+ # Turn off the validates_presence_of call
7
+ Author.depends_on :profile, :validates_presence_if => false,
8
+ :attrs => [:first_name, :last_name, :email]
9
+
10
+ # Turn off the validates_presence_of and the validates_associated calls
11
+ Artist.depends_on :profile, :validates_presence_if => false,
12
+ :validates_associated_if => false,
13
+ :attrs => [:first_name, :last_name, :email]
14
+
14
15
  @author = Author.new
15
16
  @artist = Artist.new
16
17
  end
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.6.4
4
+ version: 0.7.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: 2009-02-06 00:00:00 -05:00
12
+ date: 2009-04-11 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 2.4.0
23
+ version: 2.4.2
24
24
  version:
25
25
  description: "Classy Inheritance adds a depends_on class method to your ActiveRecord model so that you can define requisite objects. This functionality is provided using the existing ActiveRecord methods without monkey patching any core code. Essentially, it provides an easy interface to generate code that anyone could add to their model to receive the same result. Depending on the parameters to your depends_on call, it may add some of the following methods: validates_presence_of, validates_associated, has_one or belongs_to."
26
26
  email: andy@stonean.com
@@ -40,6 +40,7 @@ files:
40
40
  - Manifest.txt
41
41
  - README.txt
42
42
  - Rakefile
43
+ - classy-inheritance.gemspec
43
44
  - lib/classy-inheritance.rb
44
45
  - tasks/ann.rake
45
46
  - tasks/bones.rake
@@ -55,6 +56,7 @@ files:
55
56
  - tasks/test.rake
56
57
  - test/database.sqlite3
57
58
  - test/test_classy-inheritance.rb
59
+ - test/test_has_dependency.rb
58
60
  - test/test_helper.rb
59
61
  - test/test_polymorphic_associations.rb
60
62
  - test/test_with_class_name_ending_with_ss.rb
@@ -90,6 +92,7 @@ specification_version: 2
90
92
  summary: Classy Inheritance adds a depends_on class method to your ActiveRecord model so that you can define requisite objects
91
93
  test_files:
92
94
  - test/test_classy-inheritance.rb
95
+ - test/test_has_dependency.rb
93
96
  - test/test_helper.rb
94
97
  - test/test_polymorphic_associations.rb
95
98
  - test/test_with_class_name_ending_with_ss.rb