has_extra_data 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format doc
data/README CHANGED
@@ -1,48 +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.
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
2
 
3
- Uses rspec for test.
3
+ Usage
4
+ ---------
5
+ Use in Rails 3 app. Add to bundler:
6
+ gem "has_extra_data"
4
7
 
5
- This is an example of it in use...
8
+ Tests
9
+ ---------
10
+ Uses rspec for testing.
11
+ Run tests with rspec spec/*
6
12
 
7
- Usage
8
- -------
9
- Drink.all
10
- Drink.first.is_hot?
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.
11
18
 
12
- Coke.all
13
- Coke.first.is_hot?
14
- Coke.first.is_diet?
19
+ Example
20
+ ---------
15
21
 
16
- Classes
17
- --------
22
+ Usage:
18
23
 
19
- class Drink < ActiveRecord::Base
20
- validates :is_hot, :in => [true, false]
21
- end
24
+ Account.each do |account|
25
+ puts account.balance
26
+ end
22
27
 
23
- class Coffee < Product
24
- end
28
+ BankAccount.each do |bank_account|
29
+ puts bank_account.balance
30
+ puts bank_account.bank_account.name
31
+ end
25
32
 
26
- class Water < Product
27
- end
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
28
43
 
29
- class Coke < Product
30
- has_extra_data
31
- validates :is_diet, :in => [true, false]
32
- end
44
+ class BankAccount < Account
45
+ has_extra_data do
46
+ belongs_to :bank
47
+ end
48
+ end
33
49
 
34
- schema
50
+ class CreditCard < Account
51
+ has_extra_data
52
+ end
35
53
 
36
- create_table :drinks do |t|
37
- t.string type, :null => false
38
- t.boolean :is_hot, :null => false
39
- end
54
+ class Bank < ActiveRecord::Base
55
+ has_one :bank_account
56
+ end
40
57
 
41
- create_table :coke_data do |t|
42
- t.integer :coke_id, :null => false # Foreign key here...
43
- t.boolean :is_diet, :null => false
44
- end
58
+ Database Schema:
45
59
 
46
- Todo
47
- ----
48
- Automatically pass attributes through.
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
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = ["jez.walker@gmail.com"]
11
11
  s.homepage = ""
12
12
  s.summary = %q{Ruby Rails - Add 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. Use with STI to keep your database clean.}
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
14
 
15
15
  s.add_dependency "rails"
16
16
  s.add_development_dependency "rspec-rails"
@@ -1,16 +1,51 @@
1
1
  module HasExtraData
2
2
  module Hook
3
- def has_extra_data(&block)
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)
4
17
 
5
- table_name = "#{self.name.underscore.gsub("/", "_")}_data"
18
+ table_name = options[:table_name] || "#{self.name.underscore.gsub("/", "_")}_data"
6
19
  klass = Class.new(ActiveRecord::Base) do
7
20
  set_table_name(table_name)
8
21
  end
9
22
  klass.class_eval &block if block_given?
10
23
  self.const_set "Data", klass
11
-
24
+
25
+ # Add a reference to a data object that gets created when this is created
12
26
  has_one :data, :class_name => "#{self.name}::Data"
13
- before_create :build_data
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
14
49
  end
15
50
  end
16
51
  end
@@ -1,3 +1,3 @@
1
1
  module HasExtraData
2
- VERSION = "0.1"
2
+ VERSION = "0.2"
3
3
  end
@@ -1,30 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "HasExtraData" do
3
+ describe "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
4
14
 
5
- before :each do
6
- if Object.const_defined?("TestClass")
7
- Object.send(:remove_const, "TestClass")
8
- end
9
- @klass = Class.new(ActiveRecord::Base)
10
- Object.const_set "TestClass", @klass
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
11
27
  end
12
28
 
13
- it "has_extra_data can be called on an AR class" do
14
- lambda{
15
- @klass.class_eval{has_extra_data}
16
- }.should_not raise_error
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"
17
34
  end
18
35
 
19
- it "has_extra_data adds the data method" do
20
- @klass.class_eval{has_extra_data}
21
- @klass.new.should respond_to(:data)
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
22
41
  end
23
42
 
24
- it "creates data with the test class" do
25
- @klass.class_eval{has_extra_data}
26
- obj = @klass.create!
27
- obj.data.id.should_not == 0
43
+ it "can have any table name" do
44
+ SillyAccount.create!
28
45
  end
29
46
 
30
47
  end
data/spec/spec_helper.rb CHANGED
@@ -6,7 +6,7 @@ require 'active_record'
6
6
 
7
7
  $:.unshift File.dirname(__FILE__) + '/../lib'
8
8
 
9
- # This isn't working so I have to use the second line...
9
+ # Thie first line isn't working so I have added the second...
10
10
  require File.dirname(__FILE__) + '/../lib/has_extra_data'
11
11
  ActiveRecord::Base.send(:extend, HasExtraData::Hook)
12
12
 
@@ -17,10 +17,30 @@ $stdout = StringIO.new
17
17
 
18
18
  ActiveRecord::Base.logger
19
19
  ActiveRecord::Schema.define(:version => 1) do
20
- create_table :test_classes do |t|
20
+ create_table :accounts do |t|
21
+ t.float :balance
21
22
  end
22
23
 
23
- create_table :test_class_data do |t|
24
- t.integer :test_class_id, :null => false
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
25
29
  end
26
- 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 :silly_table_name do |t|
42
+ t.integer :silly_account_id, :null => false
43
+ end
44
+ end
45
+
46
+ require 'test_classes'
@@ -0,0 +1,27 @@
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 SillyAccount < Account
22
+ has_extra_data :table_name => "silly_table_name"
23
+ end
24
+
25
+ class Bank < ActiveRecord::Base
26
+ has_one :bank_account
27
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: has_extra_data
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: "0.1"
5
+ version: "0.2"
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jeremy Walker
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-16 00:00:00 +01:00
13
+ date: 2011-05-17 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -35,7 +35,7 @@ dependencies:
35
35
  version: "0"
36
36
  type: :development
37
37
  version_requirements: *id002
38
- description: Adds an add_extra_data method to ActiveRecord that invisibly includes an extra data table. Use with STI to keep your database clean.
38
+ 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.
39
39
  email:
40
40
  - jez.walker@gmail.com
41
41
  executables: []
@@ -46,6 +46,7 @@ extra_rdoc_files: []
46
46
 
47
47
  files:
48
48
  - .gitignore
49
+ - .rspec
49
50
  - Gemfile
50
51
  - README
51
52
  - Rakefile
@@ -56,6 +57,7 @@ files:
56
57
  - lib/has_extra_data/version.rb
57
58
  - spec/has_extra_data.rb
58
59
  - spec/spec_helper.rb
60
+ - spec/test_classes.rb
59
61
  has_rdoc: true
60
62
  homepage: ""
61
63
  licenses: []
@@ -87,3 +89,4 @@ summary: Ruby Rails - Add extra data to SDI models with clean database tables.
87
89
  test_files:
88
90
  - spec/has_extra_data.rb
89
91
  - spec/spec_helper.rb
92
+ - spec/test_classes.rb