super_sti 0.2.1

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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.tmproj
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format doc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in has_extra_data.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,79 @@
1
+ Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Use with STI to keep your database clean. It removes the need to have lots of nullable columns.
2
+
3
+ Usage
4
+ ---------
5
+ Use in Rails 3 app. Add to bundler:
6
+ gem "has_extra_data"
7
+
8
+ Tests
9
+ ---------
10
+ Uses rspec for testing.
11
+ Run tests with rspec spec/*
12
+
13
+ Todo
14
+ ---------
15
+ * Automatically load extra data class with main class.
16
+ * Automatically load associations in main class.
17
+ * Automatically pass attributes through to main class.
18
+
19
+ Example
20
+ ---------
21
+
22
+ Usage:
23
+
24
+ Account.each do |account|
25
+ puts account.balance
26
+ end
27
+
28
+ BankAccount.each do |bank_account|
29
+ puts bank_account.balance
30
+ puts bank_account.bank.name
31
+ end
32
+
33
+ Classes:
34
+ class Account < ActiveRecord::Base
35
+ before_create :set_initial_balance
36
+
37
+ private
38
+ def set_initial_balance
39
+ self.balance = 0
40
+ true
41
+ end
42
+ end
43
+
44
+ class BankAccount < Account
45
+ has_extra_data do
46
+ belongs_to :bank
47
+ end
48
+ end
49
+
50
+ class CreditCard < Account
51
+ has_extra_data
52
+ end
53
+
54
+ class Bank < ActiveRecord::Base
55
+ has_one :bank_account
56
+ end
57
+
58
+ Database Schema:
59
+
60
+ create_table :accounts do |t|
61
+ t.float :balance
62
+ end
63
+
64
+ create_table :bank_account_data do |t|
65
+ t.integer :bank_account_id, :null => false
66
+ t.integer :bank_id, :null => false
67
+ t.string :account_number, :null => false
68
+ t.string :sort_code, :null => false
69
+ end
70
+
71
+ create_table :credit_card_data do |t|
72
+ t.integer :credit_card_id, :null => false
73
+ t.string :credit_card_number, :null => false
74
+ t.date :expiry_date, :null => false
75
+ end
76
+
77
+ create_table :banks do |t|
78
+ t.string :name, :null => false
79
+ end
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,51 @@
1
+ module SuperSTI
2
+ module Hook
3
+
4
+ ######
5
+ # has_extra_data(options = {})
6
+ #
7
+ # In it's most raw form, this method creates an associated Data class,
8
+ # which seamlessly adds attributes and methods to the main class
9
+ #
10
+ # If passed a block, extra attributes can be set on the data table,
11
+ # methods (e.g. has_many) can be called, and other methods can be defined.
12
+ #
13
+ # Options:
14
+ # table_name: The table name of the class
15
+ #####
16
+ def has_extra_data(options = {}, &block)
17
+
18
+ table_name = options[:table_name] || "#{self.name.underscore.gsub("/", "_")}_data"
19
+ klass = Class.new(ActiveRecord::Base) do
20
+ set_table_name(table_name)
21
+ end
22
+ klass.class_eval &block if block_given?
23
+ self.const_set "Data", klass
24
+
25
+ # Add a reference to a data object that gets created when this is created
26
+ has_one :data, :class_name => "#{self.name}::Data", :foreign_key => options[:foreign_key]
27
+ before_create :get_data
28
+
29
+ # A helper method which gets the existing data or builds a new object
30
+ define_method :get_data do
31
+ data || build_data
32
+ end
33
+
34
+ # Override respond_to? to check both this object and its data object.
35
+ define_method "respond_to?" do |sym, include_private = false|
36
+ super(sym, include_private) || get_data.respond_to?(sym, include_private)
37
+ end
38
+
39
+ # Override method_missing to check both this object and it's data object for any methods or magic functionality.
40
+ # Firstly, try the original method_missing because there may well be
41
+ # some magic piping that will return a result and then try the data object.
42
+ define_method :method_missing do |sym, *args|
43
+ begin
44
+ super(sym, args)
45
+ rescue
46
+ get_data.send(sym, *args)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,12 @@
1
+ require 'rails'
2
+ require 'super_sti'
3
+
4
+ module SuperSTI
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :super_sti
7
+
8
+ config.to_prepare do
9
+ ActiveRecord::Base.send(:extend, SuperSTI::Hook)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module SuperSTI
2
+ VERSION = "0.2.1"
3
+ end
data/lib/super_sti.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'active_support/core_ext'
2
+ require File.join(File.dirname(__FILE__), "super_sti/hook")
3
+ require File.join(File.dirname(__FILE__), "super_sti/railtie")
@@ -0,0 +1,50 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ require 'rails'
4
+ require 'rspec-rails'
5
+ require 'active_record'
6
+
7
+ $:.unshift File.dirname(__FILE__) + '/../lib'
8
+
9
+ # Thie first line isn't working so I have added the second...
10
+ require File.dirname(__FILE__) + '/../lib/super_sti'
11
+ ActiveRecord::Base.send(:extend, SuperSTI::Hook)
12
+
13
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
14
+
15
+ # AR keeps printing annoying schema statements
16
+ $stdout = StringIO.new
17
+
18
+ ActiveRecord::Base.logger
19
+ ActiveRecord::Schema.define(:version => 1) do
20
+ create_table :accounts do |t|
21
+ t.float :balance
22
+ end
23
+
24
+ create_table :bank_account_data do |t|
25
+ t.integer :bank_account_id, :null => false
26
+ t.integer :bank_id, :null => false
27
+ t.string :account_number, :null => false
28
+ t.string :sort_code, :null => false
29
+ end
30
+
31
+ create_table :credit_card_data do |t|
32
+ t.integer :credit_card_id, :null => false
33
+ t.string :credit_card_number, :null => false
34
+ t.date :expiry_date, :null => false
35
+ end
36
+
37
+ create_table :banks do |t|
38
+ t.string :name, :null => false
39
+ end
40
+
41
+ create_table :unusual_table_name do |t|
42
+ t.integer :unusual_table_name_id, :null => false
43
+ end
44
+
45
+ create_table :unusual_foreign_key_data do |t|
46
+ t.integer :unusual_foreign_key, :null => false
47
+ end
48
+ end
49
+
50
+ require 'test_classes'
data/spec/super_sti.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Super STI models with has_extra_data models" do
4
+
5
+ before :each do
6
+ @bank = Bank.create!(:name => "My Bank")
7
+ @bank_account = BankAccount.new
8
+ @valid_bank_account_attributes = {:account_number => "12345678", :sort_code => "12 34 56", :bank => @bank}
9
+ end
10
+
11
+ it "have the data method" do
12
+ @bank_account.should respond_to(:data)
13
+ end
14
+
15
+ it "can have variables set" do
16
+ @bank_account.account_number = "12345678"
17
+ @bank_account.sort_code = "12 34 56"
18
+ @bank_account.bank = @bank
19
+ @bank_account.save!
20
+ @bank_account.data.id.should_not == 0
21
+ end
22
+
23
+ it "creates data with the test class" do
24
+ @bank_account.attributes = @valid_bank_account_attributes
25
+ @bank_account.save!
26
+ @bank_account.data.id.should_not == 0
27
+ end
28
+
29
+ it "can read attributes" do
30
+ @bank_account.attributes = @valid_bank_account_attributes
31
+ @bank_account.save!
32
+ @bank_account = BankAccount.find(@bank_account.id)
33
+ @bank_account.account_number.should == "12345678"
34
+ end
35
+
36
+ it "can read associations" do
37
+ @bank_account.attributes = @valid_bank_account_attributes
38
+ @bank_account.save!
39
+ @bank_account = BankAccount.find(@bank_account.id)
40
+ @bank_account.bank.should == @bank
41
+ end
42
+
43
+ it "can have a specifc foreign_key" do
44
+ obj = UnusualForeignKey.create!
45
+ obj.data.should_not be_nil
46
+ end
47
+
48
+ it "can have any table name" do
49
+ obj = UnusualTableName.create!
50
+ obj.data.should_not be_nil
51
+ end
52
+
53
+ end
@@ -0,0 +1,31 @@
1
+ class Account < ActiveRecord::Base
2
+ before_create :set_initial_balance
3
+
4
+ private
5
+ def set_initial_balance
6
+ self.balance = 0
7
+ true
8
+ end
9
+ end
10
+
11
+ class BankAccount < Account
12
+ has_extra_data do
13
+ belongs_to :bank
14
+ end
15
+ end
16
+
17
+ class CreditCard < Account
18
+ has_extra_data
19
+ end
20
+
21
+ class UnusualForeignKey < Account
22
+ has_extra_data :foreign_key => "unusual_foreign_key"
23
+ end
24
+
25
+ class UnusualTableName < Account
26
+ has_extra_data :table_name => "unusual_table_name"
27
+ end
28
+
29
+ class Bank < ActiveRecord::Base
30
+ has_one :bank_account
31
+ end
data/super_sti.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "super_sti/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "super_sti"
7
+ s.version = SuperSTI::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jeremy Walker"]
10
+ s.email = ["jez.walker@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Ruby Rails - Add has_extra_data to SDI models with clean database tables.}
13
+ s.description = %q{Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Means you can use STI but keep your database clean.}
14
+
15
+ s.add_dependency "rails"
16
+ s.add_development_dependency "rspec-rails"
17
+
18
+ s.rubyforge_project = "has_extra_data"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: super_sti
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.2.1
6
+ platform: ruby
7
+ authors:
8
+ - Jeremy Walker
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-18 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec-rails
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id002
37
+ description: Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Means you can use STI but keep your database clean.
38
+ email:
39
+ - jez.walker@gmail.com
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - .rspec
49
+ - Gemfile
50
+ - README
51
+ - Rakefile
52
+ - lib/super_sti.rb
53
+ - lib/super_sti/hook.rb
54
+ - lib/super_sti/railtie.rb
55
+ - lib/super_sti/version.rb
56
+ - spec/spec_helper.rb
57
+ - spec/super_sti.rb
58
+ - spec/test_classes.rb
59
+ - super_sti.gemspec
60
+ homepage: ""
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project: has_extra_data
83
+ rubygems_version: 1.7.2
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Ruby Rails - Add has_extra_data to SDI models with clean database tables.
87
+ test_files:
88
+ - spec/spec_helper.rb
89
+ - spec/super_sti.rb
90
+ - spec/test_classes.rb