has_extra_data 0.1 → 0.2

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/.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