Skip to content

Commit

Permalink
Initial import.
Browse files Browse the repository at this point in the history
git-svn-id: svn+ssh://svn0.sea.apvio.net/home/rwl4/inherits_from@1 bd10a536-b517-0410-99c0-c9a68740b5c0
  • Loading branch information
rwl4 committed Jul 3, 2006
0 parents commit 7e682f9
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README
@@ -0,0 +1,6 @@
InheritsFrom
============

Allows class inheritance with ActiveRecord.

It is very basic at the moment, and might even be fundamentally flawed.
22 changes: 22 additions & 0 deletions Rakefile
@@ -0,0 +1,22 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'

desc 'Default: run unit tests.'
task :default => :test

desc 'Test the inherits_from plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end

desc 'Generate documentation for the inherits_from plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'InheritsFrom'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
1 change: 1 addition & 0 deletions init.rb
@@ -0,0 +1 @@
require 'inherits_from'
81 changes: 81 additions & 0 deletions lib/inherits_from.rb
@@ -0,0 +1,81 @@
require 'active_record'

# +inherits_from+ is an +ActiveRecord+ plugin designed to allow simple multiple table (class) inheritance.
#
# Example:
# class Product < ActiveRecord::Base
# inherits_from :product
# end
#
# class Book < ActiveRecord::Base
# inherits_from :product
# end
#
# class Video < ActiveRecord::Base
# inherits_from :product
# end
#
# book = Book.find(1)
# book.name => "Agile Development with Rails"
# book.author => "Dave Thomas"
#
# video = Video.find(2)
# book.name => "Twilight Zone Season 1"
# book.actors => "Rod Serling"

class ActiveRecord::Base
attr_reader :reflection

# Creates an inheritance association and generates proxy methods in the inherited object for easy access to the parent.
# Currently, the options are ignored.
#
# Example:
# class Book < ActiveRecord::Base
# inherits_from :product
# end
def self.inherits_from(association_id, options = {})
belongs_to association_id

reflection = create_reflection(:belongs_to, association_id, options, self)

association_class = Object.const_get(reflection.class_name)

inherited_column_names = association_class.column_names.reject { |c| self.column_names.grep(c).length > 0 || c == "type"}

inherited_column_names.each { |name| alias_associated_attr(association_id, name) }

before_callback = <<-end_eval
init_inherited("#{association_id}")
instance_variable_get("@#{association_id}").save
end_eval

before_create(before_callback)
before_update(before_callback)
end

# Creates a proxy accessor method for an inherited object.
def self.alias_associated_attr(association_id, name)
define_method(name) do
init_inherited_assoc(association_id)
klass = send(association_id)

klass.send(name)
end

define_method("#{name}=") do |new_value|
init_inherited_assoc(association_id)
klass = send(association_id)

klass.send("#{name}=", new_value)
end
end

private
# Ensures that there is an association to access, if not, creates one.
def init_inherited_assoc(association_id)
if new_record? and instance_variable_get("@#{association_id}").nil?
send("build_#{association_id}")
instance_variable_get("@#{association_id}").type = self.class.to_s
end
end
end
5 changes: 5 additions & 0 deletions test/fixtures/book.rb
@@ -0,0 +1,5 @@
class Book < ActiveRecord::Base
inherits_from :product

validates_presence_of :name, :price, :pages
end
5 changes: 5 additions & 0 deletions test/fixtures/books.yml
@@ -0,0 +1,5 @@
agile_book:
author: Dave Thomas
product_id: 1
id: 1
pages: 300
3 changes: 3 additions & 0 deletions test/fixtures/product.rb
@@ -0,0 +1,3 @@
class Product < ActiveRecord::Base
validates_presence_of :name
end
10 changes: 10 additions & 0 deletions test/fixtures/products.yml
@@ -0,0 +1,10 @@
agile_book:
name: Agile Web Development with Rails
price: 2995
type: Book
id: 1
twilight_video:
name: Twilight Zone Season 1
price: 8945
type: Video
id: 2
5 changes: 5 additions & 0 deletions test/fixtures/video.rb
@@ -0,0 +1,5 @@
class Video < ActiveRecord::Base
inherits_from :product

validates_presence_of :name, :price, :minutes, :starring
end
5 changes: 5 additions & 0 deletions test/fixtures/videos.yml
@@ -0,0 +1,5 @@
twilight_video:
minutes: 490
product_id: 2
id: 1
starring: Rod Serling
7 changes: 7 additions & 0 deletions test/inherits_from_test.rb
@@ -0,0 +1,7 @@
require 'test/unit'

class InheritsFromTest < Test::Unit::TestCase
def test_code_needs_to_be_written
flunk "Anyone care to write some tests for me? ActiveRecord tests are painful."
end
end

0 comments on commit 7e682f9

Please sign in to comment.