dr_nic_magic_models 0.2.5 → 0.7.0

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/Rakefile CHANGED
@@ -5,11 +5,11 @@ require 'rake/rdoctask'
5
5
  require 'rake/packagetask'
6
6
  require 'rake/gempackagetask'
7
7
  require 'rake/contrib/rubyforgepublisher'
8
- require File.join(File.dirname(__FILE__), 'lib', 'dr_nic', 'magic_models', 'version')
8
+ require File.join(File.dirname(__FILE__), 'lib', 'dr_nic_magic_models', 'version')
9
9
 
10
10
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
11
11
  PKG_NAME = 'dr_nic_magic_models'
12
- PKG_VERSION = DrNic::MagicModels::VERSION::STRING + PKG_BUILD
12
+ PKG_VERSION = DrNicMagicModels::VERSION::STRING + PKG_BUILD
13
13
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
14
 
15
15
  RELEASE_NAME = "REL #{PKG_VERSION}"
@@ -102,7 +102,7 @@ spec = Gem::Specification.new do |s|
102
102
  s.add_dependency('activerecord', '= 1.14.3' + PKG_BUILD)
103
103
 
104
104
  s.require_path = 'lib'
105
- s.autorequire = 'dr_nic'
105
+ s.autorequire = 'dr_nic_magic_models'
106
106
 
107
107
  s.has_rdoc = true
108
108
  s.extra_rdoc_files = %w( README )
data/install.rb CHANGED
@@ -21,7 +21,7 @@ end
21
21
  # the acual gruntwork
22
22
  Dir.chdir("lib")
23
23
 
24
- Find.find("dr_nic", "dr_nic.rb") { |f|
24
+ Find.find("dr_nic_magic_models", "dr_nic_magic_models.rb") { |f|
25
25
  if f[-3..-1] == ".rb"
26
26
  File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
27
27
  else
data/lib/base.rb CHANGED
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  def new(*args)
7
7
  obj = old_new(*args)
8
8
  unless self.methods.include? 'generate_validations'
9
- self.send(:include, DrNic::MagicModels::Validations)
9
+ self.send(:include, DrNicMagicModels::Validations)
10
10
  self.generate_validations
11
11
  end
12
12
  obj
@@ -15,26 +15,38 @@ module ActiveRecord
15
15
  def allocate
16
16
  obj = old_allocate
17
17
  unless self.methods.include? 'generate_validations'
18
- self.send(:include, DrNic::MagicModels::Validations)
18
+ self.send(:include, DrNicMagicModels::Validations)
19
19
  self.generate_validations
20
20
  end
21
21
  obj
22
22
  end
23
+
24
+ # Returns the AssociationReflection object for the named +aggregation+ (use the symbol). Example:
25
+ # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
26
+ # Invoice.reflect_on_association(:line_items).macro # returns :has_many
27
+ def reflect_on_association(association)
28
+ unless reflections[association]
29
+ # See if an assocation can be generated
30
+ self.new.send(association) rescue nil
31
+ end
32
+ reflections[association].is_a?(ActiveRecord::Reflection::AssociationReflection) ? reflections[association] : nil
33
+ end
23
34
  end
24
35
 
25
- alias :normal_method_missing :method_missing
26
36
  class_eval do
37
+ alias :normal_method_missing :method_missing
27
38
  def method_missing(method, *args, &block)
28
39
  if unknown_method? method
29
- result = find_has_some method, *args, &block
30
- result = find_belongs_to method, *args, &block if not result
40
+ result = find_belongs_to method, *args, &block
41
+ result = find_has_some method, *args, &block if not result
42
+ result = find_has_some_indirect method, *args, &block if not result
31
43
  return result if result
32
44
  end
33
- known_unknown method
45
+ add_known_unknown method
34
46
  normal_method_missing(method, *args, &block)
35
47
  end
36
48
 
37
- def known_unknown(method)
49
+ def add_known_unknown(method)
38
50
  @known_unknowns ||= {}
39
51
  @known_unknowns[method] = true
40
52
  end
@@ -43,6 +55,16 @@ module ActiveRecord
43
55
  @known_unknowns.nil? or @known_unknowns.include? method
44
56
  end
45
57
 
58
+ def find_belongs_to(method, *args, &block)
59
+ foreign_key = self.class.columns.select {|column| column.name == method.to_s.foreign_key}.first
60
+ return add_belongs_to(method, *args, &block) if foreign_key
61
+ end
62
+
63
+ def add_belongs_to(method, *args, &block)
64
+ self.class.send 'belongs_to', method
65
+ self.send(method, *args, &block)
66
+ end
67
+
46
68
  def find_has_some(method, *args, &block)
47
69
  klass = Module.const_get method.to_s.downcase.singularize.camelize rescue nil
48
70
  foreign_key = klass.columns.select {|column| column.name == self.class.name.foreign_key}.first if klass
@@ -54,17 +76,26 @@ module ActiveRecord
54
76
  association = _method.singularize == _method ? 'has_one' : 'has_many'
55
77
  self.class.send association, method
56
78
  self.send(method, *args, &block)
57
- end
79
+ end
58
80
 
59
- def find_belongs_to(method, *args, &block)
60
- foreign_key = self.class.columns.select {|column| column.name == method.to_s.foreign_key}.first
61
- return add_belongs_to(method, *args, &block) if foreign_key
81
+ def find_has_some_indirect(method, *args, &block)
82
+ klass = Module.const_get method.to_s.downcase.singularize.camelize rescue return
83
+ join_table = nil
84
+ self.connection.tables.each do |table|
85
+ unless [self.class.table_name, klass.table_name].include? table
86
+ columns = self.connection.columns(table).map(&:name)
87
+ join_table = table if columns.include?(self.class.to_s.foreign_key) and columns.include?(klass.to_s.foreign_key)
88
+ end
89
+ break if join_table
90
+ end
91
+ return add_has_some_through(join_table, method, *args, &block) if join_table
62
92
  end
63
-
64
- def add_belongs_to(method, *args, &block)
65
- self.class.send 'belongs_to', method
93
+
94
+ def add_has_some_through(join_table, method, *args, &block)
95
+ self.class.send 'has_many', method, :through => join_table.to_sym
66
96
  self.send(method, *args, &block)
67
97
  end
98
+
68
99
  end
69
100
  end
70
101
  end
@@ -11,7 +11,7 @@ unless defined?(ActiveRecord)
11
11
  end
12
12
  end
13
13
 
14
- require 'dr_nic/magic_models/schema'
15
- require 'dr_nic/magic_models/validations'
14
+ require 'dr_nic_magic_models/schema'
15
+ require 'dr_nic_magic_models/validations'
16
16
  require 'module'
17
17
  require 'base'
@@ -0,0 +1,12 @@
1
+ module DrNicMagicModels
2
+ module Associations
3
+ def self.append_features(base)
4
+ super
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ # Composite key versions of Association functions
9
+ module ClassMethods
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,40 @@
1
+ module DrNicMagicModels
2
+ class Schema
3
+ class << self
4
+ def models
5
+ @@models ||= nil
6
+ load_schema if @@models.blank?
7
+ @@models
8
+ end
9
+
10
+ def reset
11
+ @@models = nil
12
+ end
13
+
14
+ def load_schema
15
+ if conn = ActiveRecord::Base.connection
16
+ @@models = DrNicMagicModels::ModelHash.new
17
+ @@models.merge! conn.tables.inject({}) {|model_list,table_name| model_list[ActiveRecord::Base.class_name(table_name)] = table_name; model_list}
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class ModelHash < Hash
24
+ def unenquire(class_id)
25
+ @enquired ||= {}
26
+ @enquired[class_id = class_id.to_s] = false
27
+ end
28
+
29
+ def enquired?(class_id)
30
+ @enquired ||= {}
31
+ @enquired[class_id.to_s]
32
+ end
33
+
34
+ def [](class_id)
35
+ enquired?(class_id = class_id.to_s)
36
+ @enquired[class_id] = true
37
+ super(class_id)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ module DrNicMagicModels
2
+ module Validations
3
+ def self.append_features(base)
4
+ super
5
+ base.extend(ClassMethods)
6
+ base.generate_validations
7
+
8
+ # Currently only invoked on generated classes
9
+ # How to include and invoke on all ARs? - hook into class loading??
10
+ end
11
+
12
+ module ClassMethods
13
+ def generate_validations
14
+ unless @@generated_validations ||= false
15
+ @@generated_validations = true
16
+ column_names = self.columns.select {|column| !column.null and !column.primary}.map {|column| column.name.to_sym}
17
+ add_validation :validates_presence_of, column_names
18
+ end
19
+ end
20
+
21
+ def add_validation(validation, column_names)
22
+ self.send validation, *column_names
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module DrNicMagicModels #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 7
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/module.rb CHANGED
@@ -6,11 +6,13 @@ class Module
6
6
  return normal_const_missing(class_id)
7
7
  rescue
8
8
  end
9
- unless table_name = DrNic::MagicModels::Schema.models[class_id]
10
- raise NameError.new("uninitialized constant #{class_id}") if DrNic::MagicModels::Schema.models.enquired? class_id
9
+ unless table_name = DrNicMagicModels::Schema.models[class_id]
10
+ raise NameError.new("uninitialized constant #{class_id}") if DrNicMagicModels::Schema.models.enquired? class_id
11
11
  end
12
12
  klass_code = lambda {klass_code}
13
13
  klass = Class.new ActiveRecord::Base, &klass_code
14
14
  const_set class_id, klass
15
+ klass.set_table_name table_name
16
+ klass
15
17
  end
16
18
  end
data/lib/new_base.rb ADDED
@@ -0,0 +1,105 @@
1
+ # Only needs to be an Include module for the generated classes, not for all ARs
2
+ module ActiveRecord
3
+ class Base
4
+ class << self
5
+ alias old_new new
6
+ def new(*args)
7
+ obj = old_new(*args)
8
+ unless self.methods.include? 'generate_validations'
9
+ self.send(:include, DrNicMagicModels::Validations)
10
+ self.generate_validations
11
+ end
12
+ obj
13
+ end
14
+ alias old_allocate allocate
15
+ def allocate
16
+ obj = old_allocate
17
+ unless self.methods.include? 'generate_validations'
18
+ self.send(:include, DrNicMagicModels::Validations)
19
+ self.generate_validations
20
+ end
21
+ obj
22
+ end
23
+
24
+ cattr_accessor :known_unknowns
25
+
26
+ # Returns the AssociationReflection object for the named +aggregation+ (use the symbol). Example:
27
+ # Account.reflect_on_association(:owner) # returns the owner AssociationReflection
28
+ # Invoice.reflect_on_association(:line_items).macro # returns :has_many
29
+ def reflect_on_association(association)
30
+ puts "Known association? #{association.to_sym.inspect} -> #{reflections[association]}"
31
+ reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
32
+ end
33
+
34
+ def assess_unknown_method(instance, method, *args, &block)
35
+ result = find_belongs_to instance, method, *args, &block
36
+ result = find_has_some instance, method, *args, &block if not result
37
+ result = find_has_some_indirect instance, method, *args, &block if not result
38
+ result
39
+ end
40
+
41
+ def add_known_unknown(method)
42
+ known_unknowns ||= {}
43
+ known_unknowns[method] = true
44
+ end
45
+
46
+ def unknown_method?(method)
47
+ known_unknowns.nil? or known_unknowns.include? method
48
+ end
49
+
50
+ def find_belongs_to(instance, method, *args, &block)
51
+ foreign_key = self.columns.select {|column| column.name == method.to_s.foreign_key}.first
52
+ return add_belongs_to(instance, method, *args, &block) if foreign_key
53
+ end
54
+
55
+ def add_belongs_to(instance, method, *args, &block)
56
+ self.send 'belongs_to', method
57
+ instance.send(method, *args, &block)
58
+ end
59
+
60
+ def find_has_some(instance, method, *args, &block)
61
+ klass = Module.const_get method.to_s.downcase.singularize.camelize rescue nil
62
+ foreign_key = klass.columns.select {|column| column.name == self.name.foreign_key}.first if klass
63
+ return add_has_some(instance, method, *args, &block) if foreign_key
64
+ end
65
+
66
+ def add_has_some(instance, method, *args, &block)
67
+ _method = method.to_s
68
+ association = _method.singularize == _method ? 'has_one' : 'has_many'
69
+ self.send association, method
70
+ instance.send(instance, method, *args, &block)
71
+ end
72
+
73
+ def find_has_some_indirect(instance, method, *args, &block)
74
+ klass = Module.const_get method.to_s.downcase.singularize.camelize rescue return
75
+ join_table = nil
76
+ self.connection.tables.each do |table|
77
+ unless [self.table_name, klass.table_name].include? table
78
+ columns = self.connection.columns(table).map(&:name)
79
+ join_table = table if columns.include?(self.to_s.foreign_key) and columns.include?(klass.to_s.foreign_key)
80
+ end
81
+ break if join_table
82
+ end
83
+ return add_has_some_through(instance, join_table, method, *args, &block) if join_table
84
+ end
85
+
86
+ def add_has_some_through(instance, join_table, method, *args, &block)
87
+ puts "self.class.send 'has_many', #{method}, :through => #{join_table.inspect}"
88
+ self.send 'has_many', method, :through => join_table.to_sym
89
+ instance.send(method, *args, &block)
90
+ end
91
+ end
92
+
93
+ class_eval do
94
+ alias :normal_method_missing :method_missing
95
+ def method_missing(method, *args, &block)
96
+ if unknown_method? method
97
+ self.class.assess_unknown_method(self, method, *args, &block)
98
+ end
99
+ add_known_unknown method
100
+ normal_method_missing(method, *args, &block)
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -6,7 +6,7 @@ require 'active_record/fixtures'
6
6
  require 'active_support/binding_of_caller'
7
7
  require 'active_support/breakpoint'
8
8
  require 'connection'
9
- require 'dr_nic'
9
+ require 'dr_nic_magic_models'
10
10
 
11
11
  QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') unless Object.const_defined?(:QUOTED_TYPE)
12
12
 
data/test/dummy_test.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'abstract_unit'
2
- #require 'fixtures/users'
3
- #require 'fixtures/groups'
4
- #require 'fixtures/memberships'
2
+ #require 'fixtures/user'
3
+ #require 'fixtures/group'
4
+ #require 'fixtures/membership'
5
5
 
6
6
  class DummyTest < Test::Unit::TestCase
7
7
  def setup
data/test/env_test.rb CHANGED
@@ -3,9 +3,8 @@ require 'abstract_unit'
3
3
  class EnvTest < Test::Unit::TestCase
4
4
 
5
5
  def test_modules
6
- assert_not_nil DrNic
7
- assert_not_nil DrNic::MagicModels
8
- assert_not_nil DrNic::MagicModels::Validations
9
- assert_not_nil DrNic::MagicModels::Schema
6
+ assert_not_nil DrNicMagicModels
7
+ assert_not_nil DrNicMagicModels::Validations
8
+ assert_not_nil DrNicMagicModels::Schema
10
9
  end
11
10
  end
@@ -1,4 +1,4 @@
1
- CREATE TABLE `users` (
1
+ CREATE TABLE `fun_users` (
2
2
  `id` int(11) NOT NULL auto_increment,
3
3
  `firstname` varchar(50) NOT NULL,
4
4
  `lastname` varchar(50) NOT NULL,
@@ -9,24 +9,22 @@ CREATE TABLE `users` (
9
9
 
10
10
  CREATE TABLE `groups` (
11
11
  `id` int(11) NOT NULL auto_increment,
12
- `name` int(11) NOT NULL,
12
+ `name` varchar(50) NOT NULL,
13
13
  `description` varchar(50) default NULL,
14
14
  PRIMARY KEY (`id`)
15
15
  ) TYPE=InnoDB;
16
16
 
17
- CREATE TABLE `memberships` (
17
+ CREATE TABLE `group_memberships` (
18
18
  `id` int(11) NOT NULL auto_increment,
19
- `user_id` int(11) NOT NULL,
19
+ `fun_user_id` int(11) NOT NULL,
20
20
  `group_id` int(11) NOT NULL,
21
21
  PRIMARY KEY (`id`)
22
22
  ) TYPE=InnoDB;
23
23
 
24
- CREATE TABLE `person` (
24
+ CREATE TABLE `group_tag` (
25
25
  `id` int(11) NOT NULL auto_increment,
26
- `firstname` varchar(50) NOT NULL,
27
- `lastname` varchar(50) NOT NULL,
28
- `login` varchar(50) NOT NULL,
29
- `email` varchar(50) NULL,
26
+ `name` varchar(50) NOT NULL,
27
+ `group_id` int(11) NOT NULL,
30
28
  PRIMARY KEY (`id`)
31
29
  ) TYPE=InnoDB;
32
30
 
@@ -0,0 +1,7 @@
1
+ first:
2
+ id: 1
3
+ firstname: First
4
+ lastname: Person
5
+ login: first
6
+ email: first@person.com
7
+
@@ -0,0 +1,4 @@
1
+ first_first:
2
+ id: 1
3
+ group_id: 1
4
+ fun_user_id: 1
@@ -0,0 +1,9 @@
1
+ first:
2
+ id: 1
3
+ name: Test
4
+ group_id: 1
5
+ second:
6
+ id: 2
7
+ name: Also Test
8
+ group_id: 1
9
+
@@ -0,0 +1,4 @@
1
+ first:
2
+ id: 1
3
+ name: Group One
4
+ description: First group
@@ -0,0 +1,37 @@
1
+ require 'abstract_unit'
2
+
3
+ class InvisibleModelAccessTest < Test::Unit::TestCase
4
+ fixtures :fun_users, :groups, :group_memberships, :group_tag
5
+
6
+ def setup
7
+ @classes = [FunUser, Group, GroupMembership, GroupTag]
8
+ @group = groups(:first)
9
+ end
10
+
11
+ def test_find
12
+ @classes.each do |klass|
13
+ assert_not_nil obj = klass.find(1)
14
+ assert_equal klass, obj.class
15
+ end
16
+ end
17
+
18
+ def test_create
19
+ assert group = Group.create(:name => 'New Group')
20
+ assert_equal Group, group.class
21
+ end
22
+
23
+ def test_update
24
+ assert @group.update_attributes(:name => 'Group 1')
25
+ assert_equal Group, @group.class
26
+ end
27
+
28
+ def test_delete
29
+ assert @group.destroy
30
+ end
31
+
32
+ def test_validations
33
+ group = Group.new
34
+ assert !group.valid?
35
+ assert_not_nil group.errors[:name]
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ require 'abstract_unit'
2
+
3
+ class InvisibleModelAssocTest < Test::Unit::TestCase
4
+ fixtures :fun_users, :groups, :group_memberships
5
+
6
+ def setup
7
+ @group = groups(:first)
8
+ @user = fun_users(:first)
9
+ @membership = group_memberships(:first_first)
10
+ end
11
+
12
+ def test_has_some
13
+ assert_equal @membership, @user.group_membership
14
+ assert_equal [@membership], @user.group_memberships
15
+ assert_equal @membership, @group.group_membership
16
+ assert_equal [@membership], @group.group_memberships
17
+ end
18
+
19
+ def test_belongs_to
20
+ assert_equal @user, @membership.fun_user
21
+ assert_equal @group, @membership.group
22
+ GroupTag.find(:all, :conditions => ['group_id = ?', @group.id]).each do |group_tag|
23
+ assert_equal @group, group_tag.group
24
+ end
25
+ end
26
+
27
+ def test_indirect
28
+ assert_equal [@user], @group.fun_users
29
+ assert_equal [@group], @user.groups
30
+ end
31
+
32
+ # TODO - Support these
33
+ #def test_more_indirect
34
+ # group_tags = GroupTag.find(:all, :conditions => ['group_id = ?', @group.id])
35
+ # assert_equal group_tags, @user.group_tags
36
+ #end
37
+
38
+ #def test_more_indirect_via_belongs_to
39
+ # @group_tag = group_tag(:first)
40
+ # assert_equal [@user], @group_tag.fun_users
41
+ #end
42
+ end
@@ -4,17 +4,16 @@ class InvisibleModelClassesTest < Test::Unit::TestCase
4
4
 
5
5
  def test_available
6
6
  assert_not_nil Group
7
- assert_not_nil User
8
- assert_not_nil Membership
9
- assert_not_nil Person, "Could not find Person with singularized table name 'person'"
7
+ assert_not_nil FunUser
8
+ assert_not_nil GroupMembership
9
+ assert_not_nil GroupTag, "Could not find GroupTag with singularized table name 'GroupTag'"
10
10
  end
11
11
 
12
12
  def test_table_names
13
13
  assert_equal 'groups', Group.table_name
14
- assert_equal 'users', User.table_name
15
- assert_equal 'memberships', Membership.table_name
16
- assert_equal 'person', Person.table_name
14
+ assert_equal 'fun_users', FunUser.table_name
15
+ assert_equal 'group_memberships', GroupMembership.table_name
16
+ assert_equal 'group_tag', GroupTag.table_name
17
17
  end
18
18
 
19
-
20
19
  end
data/website/index.html CHANGED
@@ -33,11 +33,246 @@
33
33
  <h1>Dr Nic&#8217;s Magic Models</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/magicmodels"; return false'>
35
35
  Get Version
36
- <a href="http://rubyforge.org/projects/magicmodels" class="numbers">0.2.5</a>
36
+ <a href="http://rubyforge.org/projects/magicmodels" class="numbers">0.7.0</a>
37
37
  </div>
38
- <h2>Instant look-see</h2>
38
+ <blockquote>
39
+ <strong>conjure</strong> 1. To create events that appear to be magical<br />
40
+ - <a href="http://www.dcopperfield.com/">David Copperfield</a> website
41
+ </blockquote>
42
+ If you&#8217;ve used Ruby on Rails you&#8217;ll have written at least one model class like this:
43
+
44
+ <p><pre class="syntax">
45
+ <span class="keyword">class </span><span class="class">Person</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
46
+ <span class="ident">has_many</span> <span class="symbol">:memberships</span>
47
+ <span class="ident">has_many</span> <span class="symbol">:groups</span><span class="punct">,</span> <span class="symbol">:through</span> <span class="punct">=&gt;</span> <span class="symbol">:memberships</span>
48
+ <span class="ident">belongs_to</span> <span class="symbol">:family</span>
49
+ <span class="ident">validates_presence_of</span> <span class="symbol">:firstname</span><span class="punct">,</span> <span class="symbol">:lastname</span><span class="punct">,</span> <span class="symbol">:email</span>
50
+ <span class="keyword">end</span>
51
+ </pre></p>
52
+
53
+
54
+ <p>A few minutes later you&#8217;ll have wondered to yourself,</p>
55
+
56
+
57
+ <blockquote>
58
+ Why do I have write my own <code>has_many</code>, <code>belongs_to</code>, and <code>validates_presence_of</code>
59
+ commands if all the data is in the database schema?
60
+ </blockquote>
61
+
62
+ <p>Now, for the very first time, your classes can look like this:</p>
63
+
64
+
65
+ <p><pre class="syntax">
66
+ <span class="keyword">class </span><span class="class">Person</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
67
+ <span class="keyword">end</span>
68
+ </pre></p>
69
+
70
+
71
+ <p>or, if you are lazy&#8230;</p>
72
+
73
+
74
+ <p><pre class="syntax">
75
+ <span class="keyword">class </span><span class="class">Person</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">;</span> <span class="keyword">end</span>
76
+ </pre></p>
77
+
78
+
79
+ <p>or, if you read right to the end of this page, this&#8230;</p>
80
+
81
+
82
+ <p><pre class="syntax">
83
+
84
+ </pre></p>
85
+
86
+
87
+ <p>Magic and mystery abound. All for you. Impress your friends, amaze your mother.</p>
88
+
89
+
90
+ <p><span class="caps">NOTE</span>: The gratuitous use of <strong>Dr Nic&#8217;s</strong> in the name should only enhance the mystical magicery,
91
+ for magic needs a magician; and I love magic. I always wanted to create my own magic trick.
92
+ So I shall be the magician for the sake of magic itself. I look a bit like Harry Potter
93
+ if Harry were 31 and better dressed.</p>
94
+
95
+
96
+ <h2>Installation</h2>
97
+
98
+
99
+ To install the Dr Nic&#8217;s Magic Models gem you can run the following command to
100
+ fetch the gem remotely from RubyForge:
101
+ <pre>
102
+ gem install dr_nic_magic_models
103
+ </pre>
104
+
105
+ <p>or <a href="http://rubyforge.org/projects/magicmodels">download the gem manually</a> and
106
+ run the above command in the download directory.</p>
107
+
108
+
109
+ <p>Now you need to <code>require</code> the gem into your Ruby/Rails app. Insert the following
110
+ line into your script (use <code>config/environment.rb</code> for your Rails apps):</p>
111
+
112
+
113
+ <pre>
114
+ require 'dr_nic_magic_models'
115
+ </pre>
116
+
117
+ <p>Your application is now blessed with magical mystery.</p>
118
+
119
+
120
+ <h2>David Copperfield eat your Ruby-crusted heart out</h2>
121
+
122
+
123
+ <p>Let&#8217;s demonstrate the magical mystery in all its full-stage glory. Create a Ruby on Rails app:</p>
124
+
125
+
126
+ <p><pre class="syntax">
127
+ <span class="ident">rails</span> <span class="ident">magic_show</span>
128
+ <span class="ident">cd</span> <span class="ident">magic_show</span>
129
+ <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">generate</span> <span class="ident">model</span> <span class="constant">Person</span>
130
+ <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">generate</span> <span class="ident">model</span> <span class="constant">Group</span>
131
+ <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">generate</span> <span class="ident">model</span> <span class="constant">Membership</span>
132
+ </pre></p>
133
+
134
+
135
+ <p>Update the migration <code>001_create_people.rb</code> with:
136
+ <pre class="syntax">
137
+ <span class="keyword">class </span><span class="class">CreatePeople</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Migration</span>
138
+ <span class="keyword">def </span><span class="method">self.up</span>
139
+ <span class="ident">create_table</span> <span class="symbol">:people</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
140
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:firstname</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=&gt;</span> <span class="constant">false</span>
141
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:lastname</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=&gt;</span> <span class="constant">false</span>
142
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:email</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=&gt;</span> <span class="constant">false</span>
143
+ <span class="keyword">end</span>
144
+ <span class="keyword">end</span>
145
+
146
+ <span class="keyword">def </span><span class="method">self.down</span>
147
+ <span class="ident">drop_table</span> <span class="symbol">:people</span>
148
+ <span class="keyword">end</span>
149
+ <span class="keyword">end</span>
150
+ </pre></p>
151
+
152
+
153
+ <p>Similarly, update the <code>def self.up</code> method of <code>002_create_groups.rb</code>
154
+ with:
155
+ <pre class="syntax">
156
+ <span class="ident">create_table</span> <span class="symbol">:groups</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
157
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:name</span><span class="punct">,</span> <span class="symbol">:string</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=&gt;</span> <span class="constant">false</span>
158
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:description</span><span class="punct">,</span> <span class="symbol">:datetime</span>
159
+ <span class="keyword">end</span>
160
+ </pre></p>
161
+
162
+
163
+ <p>and <code>003_create_memberships.rb</code> with:
164
+ <pre class="syntax">
165
+ <span class="ident">create_table</span> <span class="symbol">:memberships</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
166
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:person_id</span><span class="punct">,</span> <span class="symbol">:integer</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=&gt;</span> <span class="constant">false</span>
167
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:group_id</span><span class="punct">,</span> <span class="symbol">:integer</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=&gt;</span> <span class="constant">false</span>
168
+ <span class="keyword">end</span>
169
+ </pre></p>
170
+
171
+
172
+ Now create your database. For MySql:
173
+ <pre>
174
+ mysqladmin -u root create magic_show_development
175
+ mysqladmin -u root create magic_show_test
176
+ </pre>
177
+
178
+ And run your migrations to create the three tables:
179
+ <pre>
180
+ rake migrate
181
+ </pre>
182
+
183
+ <h2>And now for some <a href="http://en.wikipedia.org/wiki/List_of_conjuring_terms">woofle dust</a> ...</h2>
184
+
185
+
186
+ <p>At the end of <code>config/environment.rb</code> add the following line:</p>
187
+
188
+
189
+ <pre>
190
+ require 'dr_nic_magic_models'
191
+ </pre>
192
+
193
+ <p>Now, let&#8217;s do a magic trick. First, let&#8217;s check our model classes (<code>app/models/person.rb</code> etc):</p>
194
+
195
+
196
+ <p><pre class="syntax">
197
+ <span class="keyword">class </span><span class="class">Person</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
198
+ <span class="keyword">end</span>
199
+ <span class="keyword">class </span><span class="class">Group</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
200
+ <span class="keyword">end</span>
201
+ <span class="keyword">class </span><span class="class">Membership</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
202
+ <span class="keyword">end</span>
203
+ </pre></p>
204
+
205
+
206
+ <p>Nothing suspicious here. We have no validations and no associations. Just some plain old model classes.</p>
207
+
208
+
209
+ <p>For this trick, we&#8217;ll need an ordinary console session. Any old one lying around the house will do.</p>
210
+
211
+
212
+ <pre>
213
+ ruby script/console
214
+ </pre>
215
+
216
+ <p>Now a normal model class is valid until you explicitly add <code>validates_xxx</code> commands.
217
+ With Dr Nic&#8217;s Magic Models:</p>
218
+
219
+
220
+ <p><pre class="syntax">
221
+ <span class="punct">&gt;&gt;</span> <span class="ident">person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">new</span>
222
+ <span class="punct">=&gt;</span> <span class="comment">#&lt;Person:0x393e0f8 @attributes={&quot;lastname&quot;=&gt;&quot;&quot;, &quot;firstname&quot;=&gt;&quot;&quot;, &quot;email&quot;=&gt;&quot;&quot;}, @new_record=true&gt;</span>
223
+ <span class="punct">&gt;&gt;</span> <span class="ident">person</span><span class="punct">.</span><span class="ident">valid?</span>
224
+ <span class="punct">=&gt;</span> <span class="constant">false</span>
225
+ <span class="punct">&gt;&gt;</span> <span class="ident">person</span><span class="punct">.</span><span class="ident">errors</span>
226
+ <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Errors</span><span class="punct">:</span><span class="number">0x3938b18</span> <span class="attribute">@errors</span><span class="punct">={&quot;</span><span class="string">firstname</span><span class="punct">&quot;=&gt;[&quot;</span><span class="string">can't be blank</span><span class="punct">&quot;],</span>
227
+ <span class="punct">&quot;</span><span class="string">lastname</span><span class="punct">&quot;=&gt;[&quot;</span><span class="string">can't be blank</span><span class="punct">&quot;],</span> <span class="punct">&quot;</span><span class="string">email</span><span class="punct">&quot;=&gt;[&quot;</span><span class="string">can't be blank</span><span class="punct">&quot;]},</span>
228
+ <span class="attribute">@base</span><span class="punct">=&lt;</span><span class="constant">Person</span><span class="punct">:</span><span class="number">0x393e0f8</span> <span class="attribute">@errors</span><span class="punct">=&lt;</span><span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Errors</span><span class="punct">:</span><span class="number">0x3938b18</span> <span class="punct">...&gt;,</span>
229
+ <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">lastname</span><span class="punct">&quot;=&gt;&quot;</span><span class="string"></span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">firstname</span><span class="punct">&quot;=&gt;&quot;</span><span class="string"></span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">email</span><span class="punct">&quot;=&gt;&quot;</span><span class="string"></span><span class="punct">&quot;},</span> <span class="attribute">@new_record</span><span class="punct">=</span><span class="constant">true</span><span class="punct">&gt;&gt;</span>
230
+ </pre></p>
231
+
232
+
233
+ <p><strong>Kapoow!</strong> Instant validation!</p>
234
+
235
+
236
+ <p>Because you specified the three columns as <code>:null =&gt; false</code>,
237
+ your ActiveRecord models will now automatically generated <code>validates_presence_of</code>
238
+ for each non-null field.</p>
239
+
240
+
241
+ <p>Ok, we&#8217;re just warming up.</p>
242
+
243
+
244
+ <p>Your models normally require association commands (<code>has_many</code>, <code>belongs_to</code>, etc, as
245
+ demonstrated above) to have the brilliantly simple support that Rails/ActiveRecords are known for.</p>
246
+
247
+
248
+ <p>Let&#8217;s just watch what Dr Nic&#8217;s Magic Models can do without any effort at all&#8230;</p>
249
+
250
+
251
+ <p><pre class="syntax">
252
+ <span class="punct">&gt;&gt;</span> <span class="ident">person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:firstname</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">Nic</span><span class="punct">&quot;,</span> <span class="symbol">:lastname</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">Williams</span><span class="punct">&quot;,</span> <span class="symbol">:email</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">drnicwilliams@gmail.com</span><span class="punct">&quot;)</span>
253
+ <span class="punct">&gt;&gt;</span> <span class="ident">group</span> <span class="punct">=</span> <span class="constant">Group</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">Magic Models Forum</span><span class="punct">&quot;,</span> <span class="symbol">:description</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">http://groups.google.com/magicmodels</span><span class="punct">&quot;)</span>
254
+ <span class="punct">&gt;&gt;</span> <span class="ident">membership</span> <span class="punct">=</span> <span class="constant">Membership</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:person_id</span> <span class="punct">=&gt;</span> <span class="ident">person</span><span class="punct">,</span> <span class="symbol">:group_id</span> <span class="punct">=&gt;</span> <span class="ident">group</span><span class="punct">)</span>
255
+ <span class="punct">&gt;&gt;</span> <span class="ident">person</span><span class="punct">.</span><span class="ident">memberships</span><span class="punct">.</span><span class="ident">length</span>
256
+ <span class="punct">=&gt;</span> <span class="number">1</span>
257
+ <span class="punct">&gt;&gt;</span> <span class="ident">membership</span><span class="punct">.</span><span class="ident">person</span>
258
+ <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">Person</span><span class="punct">:</span><span class="number">0x38898e8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">lastname</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Williams</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">firstname</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Nic</span><span class="punct">&quot;,</span>
259
+ <span class="punct">&quot;</span><span class="string">id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">email</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">drnicwilliams@gmail.com</span><span class="punct">&quot;}&gt;</span>
260
+ <span class="punct">&gt;&gt;</span> <span class="ident">group</span><span class="punct">.</span><span class="ident">memberships</span>
261
+ <span class="punct">=&gt;</span> <span class="punct">[&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x3c8cd70</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">person_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;]</span>
262
+ </pre></p>
263
+
264
+
265
+ <p>The final association trick is a ripper. Automatic generation of <code>has_many :through</code> associations&#8230;</p>
266
+
267
+
268
+ <p><pre class="syntax">
269
+ <span class="punct">&gt;&gt;</span> <span class="ident">person</span><span class="punct">.</span><span class="ident">groups</span>
270
+ <span class="punct">=&gt;</span> <span class="punct">[&lt;</span><span class="constant">Group</span><span class="punct">:</span><span class="number">0x39047e0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">name</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Magic Models Forum</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">description</span><span class="punct">&quot;=&gt;</span><span class="constant">nil</span><span class="punct">}&gt;]</span>
271
+ <span class="punct">&gt;&gt;</span> <span class="ident">group</span><span class="punct">.</span><span class="ident">people</span>
272
+ <span class="punct">=&gt;</span>
273
+ </pre></p>
39
274
  <p class="coda">
40
- <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 28th July 2006<br>
275
+ <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 7th August 2006<br>
41
276
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
42
277
  </p>
43
278
  </div>
data/website/index.txt CHANGED
@@ -1,4 +1,204 @@
1
1
  h1. Dr Nic's Magic Models
2
2
 
3
- h2. Instant look-see
3
+ <blockquote>
4
+ *conjure* 1. To create events that appear to be magical<br />
5
+ - "David Copperfield":http://www.dcopperfield.com/ website
6
+ </blockquote>
7
+ If you've used Ruby on Rails you'll have written at least one model class like this:
4
8
 
9
+ <pre syntax='ruby'>
10
+ class Person < ActiveRecord::Base
11
+ has_many :memberships
12
+ has_many :groups, :through => :memberships
13
+ belongs_to :family
14
+ validates_presence_of :firstname, :lastname, :email
15
+ end
16
+ </pre>
17
+
18
+ A few minutes later you'll have wondered to yourself,
19
+
20
+ <blockquote>
21
+ Why do I have write my own <code>has_many</code>, <code>belongs_to</code>, and <code>validates_presence_of</code>
22
+ commands if all the data is in the database schema?
23
+ </blockquote>
24
+
25
+ Now, for the very first time, your classes can look like this:
26
+
27
+ <pre syntax='ruby'>
28
+ class Person < ActiveRecord::Base
29
+ end
30
+ </pre>
31
+
32
+ or, if you are lazy...
33
+
34
+ <pre syntax='ruby'>
35
+ class Person < ActiveRecord::Base; end
36
+ </pre>
37
+
38
+ or, if you read right to the end of this page, this...
39
+
40
+ <pre syntax='ruby'>
41
+
42
+ </pre>
43
+
44
+ Magic and mystery abound. All for you. Impress your friends, amaze your mother.
45
+
46
+ NOTE: The gratuitous use of *Dr Nic's* in the name should only enhance the mystical magicery,
47
+ for magic needs a magician; and I love magic. I always wanted to create my own magic trick.
48
+ So I shall be the magician for the sake of magic itself. I look a bit like Harry Potter
49
+ if Harry were 31 and better dressed.
50
+
51
+ h2. Installation
52
+
53
+ To install the Dr Nic's Magic Models gem you can run the following command to
54
+ fetch the gem remotely from RubyForge:
55
+ <pre>
56
+ gem install dr_nic_magic_models
57
+ </pre>
58
+
59
+ or "download the gem manually":http://rubyforge.org/projects/magicmodels and
60
+ run the above command in the download directory.
61
+
62
+ Now you need to <code>require</code> the gem into your Ruby/Rails app. Insert the following
63
+ line into your script (use <code>config/environment.rb</code> for your Rails apps):
64
+
65
+ <pre>
66
+ require 'dr_nic_magic_models'
67
+ </pre>
68
+
69
+ Your application is now blessed with magical mystery.
70
+
71
+ h2. David Copperfield eat your Ruby-crusted heart out
72
+
73
+ Let's demonstrate the magical mystery in all its full-stage glory. Create a Ruby on Rails app:
74
+
75
+ <pre syntax="ruby">
76
+ rails magic_show
77
+ cd magic_show
78
+ ruby script/generate model Person
79
+ ruby script/generate model Group
80
+ ruby script/generate model Membership
81
+ </pre>
82
+
83
+ Update the migration <code>001_create_people.rb</code> with:
84
+ <pre syntax="ruby">
85
+ class CreatePeople < ActiveRecord::Migration
86
+ def self.up
87
+ create_table :people do |t|
88
+ t.column :firstname, :string, :null => false
89
+ t.column :lastname, :string, :null => false
90
+ t.column :email, :string, :null => false
91
+ end
92
+ end
93
+
94
+ def self.down
95
+ drop_table :people
96
+ end
97
+ end
98
+ </pre>
99
+
100
+ Similarly, update the <code>def self.up</code> method of <code>002_create_groups.rb</code>
101
+ with:
102
+ <pre syntax="ruby">
103
+ create_table :groups do |t|
104
+ t.column :name, :string, :null => false
105
+ t.column :description, :datetime
106
+ end
107
+ </pre>
108
+
109
+ and <code>003_create_memberships.rb</code> with:
110
+ <pre syntax="ruby">
111
+ create_table :memberships do |t|
112
+ t.column :person_id, :integer, :null => false
113
+ t.column :group_id, :integer, :null => false
114
+ end
115
+ </pre>
116
+
117
+ Now create your database. For MySql:
118
+ <pre>
119
+ mysqladmin -u root create magic_show_development
120
+ mysqladmin -u root create magic_show_test
121
+ </pre>
122
+
123
+ And run your migrations to create the three tables:
124
+ <pre>
125
+ rake migrate
126
+ </pre>
127
+
128
+ h2. And now for some "woofle dust":http://en.wikipedia.org/wiki/List_of_conjuring_terms ...
129
+
130
+ At the end of <code>config/environment.rb</code> add the following line:
131
+
132
+ <pre>
133
+ require 'dr_nic_magic_models'
134
+ </pre>
135
+
136
+ Now, let's do a magic trick. First, let's check our model classes (<code>app/models/person.rb</code> etc):
137
+
138
+ <pre syntax="ruby">
139
+ class Person < ActiveRecord::Base
140
+ end
141
+ class Group < ActiveRecord::Base
142
+ end
143
+ class Membership < ActiveRecord::Base
144
+ end
145
+ </pre>
146
+
147
+ Nothing suspicious here. We have no validations and no associations. Just some plain old model classes.
148
+
149
+ For this trick, we'll need an ordinary console session. Any old one lying around the house will do.
150
+
151
+ <pre>
152
+ ruby script/console
153
+ </pre>
154
+
155
+ Now a normal model class is valid until you explicitly add <code>validates_xxx</code> commands.
156
+ With Dr Nic's Magic Models:
157
+
158
+ <pre syntax="ruby">
159
+ >> person = Person.new
160
+ => #<Person:0x393e0f8 @attributes={"lastname"=>"", "firstname"=>"", "email"=>""}, @new_record=true>
161
+ >> person.valid?
162
+ => false
163
+ >> person.errors
164
+ => <ActiveRecord::Errors:0x3938b18 @errors={"firstname"=>["can't be blank"],
165
+ "lastname"=>["can't be blank"], "email"=>["can't be blank"]},
166
+ @base=<Person:0x393e0f8 @errors=<ActiveRecord::Errors:0x3938b18 ...>,
167
+ @attributes={"lastname"=>"", "firstname"=>"", "email"=>""}, @new_record=true>>
168
+ </pre>
169
+
170
+ *Kapoow!* Instant validation!
171
+
172
+ Because you specified the three columns as <code>:null => false</code>,
173
+ your ActiveRecord models will now automatically generated <code>validates_presence_of</code>
174
+ for each non-null field.
175
+
176
+ Ok, we're just warming up.
177
+
178
+ Your models normally require association commands (<code>has_many</code>, <code>belongs_to</code>, etc, as
179
+ demonstrated above) to have the brilliantly simple support that Rails/ActiveRecords are known for.
180
+
181
+ Let's just watch what Dr Nic's Magic Models can do without any effort at all...
182
+
183
+ <pre syntax="ruby">
184
+ >> person = Person.create(:firstname => "Nic", :lastname => "Williams", :email => "drnicwilliams@gmail.com")
185
+ >> group = Group.create(:name => "Magic Models Forum", :description => "http://groups.google.com/magicmodels")
186
+ >> membership = Membership.create(:person_id => person, :group_id => group)
187
+ >> person.memberships.length
188
+ => 1
189
+ >> membership.person
190
+ => <Person:0x38898e8 @attributes={"lastname"=>"Williams", "firstname"=>"Nic",
191
+ "id"=>"1", "email"=>"drnicwilliams@gmail.com"}>
192
+ >> group.memberships
193
+ => [<Membership:0x3c8cd70 @attributes={"group_id"=>"1", "id"=>"1", "person_id"=>"1"}>]
194
+ </pre>
195
+
196
+
197
+ The final association trick is a ripper. Automatic generation of <code>has_many :through</code> associations...
198
+
199
+ <pre syntax="ruby">
200
+ >> person.groups
201
+ => [<Group:0x39047e0 @attributes={"name"=>"Magic Models Forum", "id"=>"1", "description"=>nil}>]
202
+ >> group.people
203
+ =>
204
+ </pre>
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: dr_nic_magic_models
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.5
7
- date: 2006-07-28 00:00:00 +02:00
6
+ version: 0.7.0
7
+ date: 2006-08-07 00:00:00 +02:00
8
8
  summary: Invisible validations, assocations and Active Record models themselves!
9
9
  require_paths:
10
10
  - lib
@@ -12,7 +12,7 @@ email: drnicwilliams@gmail.com
12
12
  homepage: http://magicmodels.rubyforge.org
13
13
  rubyforge_project: magicmodels
14
14
  description: Associations and validations are automagically available to your ActiveRecord models. Model classes themselves are automagically generated if you haven't defined them already!
15
- autorequire: dr_nic
15
+ autorequire: dr_nic_magic_models
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: true
@@ -32,27 +32,30 @@ files:
32
32
  - install.rb
33
33
  - README
34
34
  - CHANGELOG
35
- - lib/dr_nic
36
- - lib/dr_nic.rb
37
35
  - lib/module.rb
36
+ - lib/dr_nic_magic_models
37
+ - lib/dr_nic_magic_models.rb
38
+ - lib/new_base.rb
38
39
  - lib/base.rb
39
- - lib/dr_nic/magic_models
40
- - lib/dr_nic/magic_models/validations.rb
41
- - lib/dr_nic/magic_models/schema.rb
42
- - lib/dr_nic/magic_models/version.rb
40
+ - lib/dr_nic_magic_models/associations.rb
41
+ - lib/dr_nic_magic_models/schema.rb
42
+ - lib/dr_nic_magic_models/validations.rb
43
+ - lib/dr_nic_magic_models/version.rb
43
44
  - test/connections
44
45
  - test/fixtures
45
46
  - test/abstract_unit.rb
46
47
  - test/dummy_test.rb
47
48
  - test/invisible_model_classes_test.rb
48
49
  - test/env_test.rb
50
+ - test/invisible_model_access_test.rb
51
+ - test/invisible_model_assoc_test.rb
49
52
  - test/connections/native_mysql
50
53
  - test/connections/native_mysql/connection.rb
51
54
  - test/fixtures/db_definitions
52
- - test/fixtures/reference_type.rb
53
- - test/fixtures/reference_types.yml
54
- - test/fixtures/reference_code.rb
55
- - test/fixtures/reference_codes.yml
55
+ - test/fixtures/groups.yml
56
+ - test/fixtures/group_tag.yml
57
+ - test/fixtures/group_memberships.yml
58
+ - test/fixtures/fun_users.yml
56
59
  - test/fixtures/db_definitions/mysql.sql
57
60
  - test/fixtures/db_definitions/mysql.drop.sql
58
61
  - website/index.txt
@@ -1,45 +0,0 @@
1
- module DrNic
2
- module MagicModels
3
- class Schema
4
- class << self
5
- def models
6
- @@models ||= nil
7
- load_schema if @@models.blank?
8
- @@models
9
- end
10
-
11
- def reset
12
- @@models = nil
13
- end
14
-
15
- def load_schema
16
- if conn = ActiveRecord::Base.connection
17
- @@models = DrNic::MagicModels::ModelHash.new
18
- conn.tables.inspect
19
- @@models.merge! conn.tables.inject({}) {|model_list,table_name| model_list[ActiveRecord::Base.class_name(table_name)] = table_name; model_list}
20
- end
21
- end
22
- end
23
- end
24
-
25
- class ModelHash < Hash
26
- def unenquire(class_id)
27
- @enquired ||= {}
28
- @enquired[class_id = class_id.to_s] = false
29
- end
30
-
31
- def enquired?(class_id)
32
- @enquired ||= {}
33
- result = @enquired[class_id.to_s]
34
- #@enquired[class_id = class_id.to_s] = true
35
- result
36
- end
37
-
38
- def [](class_id)
39
- enquired?(class_id = class_id.to_s)
40
- @enquired[class_id] = true
41
- super(class_id)
42
- end
43
- end
44
- end
45
- end
@@ -1,28 +0,0 @@
1
- module DrNic
2
- module MagicModels
3
- module Validations
4
- def self.append_features(base)
5
- super
6
- base.extend(ClassMethods)
7
- base.generate_validations
8
-
9
- # Currently only invoked on generated classes
10
- # How to include and invoke on all ARs? - hook into class loading??
11
- end
12
-
13
- module ClassMethods
14
- def generate_validations
15
- unless @@generated_validations ||= false
16
- @@generated_validations = true
17
- column_names = self.columns.select {|column| !column.null and !column.primary}.map {|column| column.name.to_sym}
18
- add_validation :validates_presence_of, column_names
19
- end
20
- end
21
-
22
- def add_validation(validation, column_names)
23
- self.send validation, *column_names
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,11 +0,0 @@
1
- module DrNic #:nodoc:
2
- module MagicModels #:nodoc:
3
- module VERSION #:nodoc:
4
- MAJOR = 0
5
- MINOR = 2
6
- TINY = 5
7
-
8
- STRING = [MAJOR, MINOR, TINY].join('.')
9
- end
10
- end
11
- end
@@ -1,7 +0,0 @@
1
- class ReferenceCode < ActiveRecord::Base
2
- set_primary_keys :reference_type_id, :reference_code
3
-
4
- belongs_to :reference_type, :foreign_key => "reference_type_id"
5
-
6
- validates_presence_of :reference_code, :code_label, :abbreviation
7
- end
@@ -1,28 +0,0 @@
1
- name_prefix_mr:
2
- reference_type_id: 1
3
- reference_code: 1
4
- code_label: MR
5
- abbreviation: Mr
6
- name_prefix_mrs:
7
- reference_type_id: 1
8
- reference_code: 2
9
- code_label: MRS
10
- abbreviation: Mrs
11
- name_prefix_ms:
12
- reference_type_id: 1
13
- reference_code: 3
14
- code_label: MS
15
- abbreviation: Ms
16
-
17
- gender_male:
18
- reference_type_id: 2
19
- reference_code: 1
20
- code_label: MALE
21
- abbreviation: Male
22
- gender_female:
23
- reference_type_id: 2
24
- reference_code: 2
25
- code_label: FEMALE
26
- abbreviation: Female
27
-
28
-
@@ -1,7 +0,0 @@
1
- class ReferenceType < ActiveRecord::Base
2
- set_primary_key :reference_type_id
3
- has_many :reference_codes, :foreign_key => "reference_type_id"
4
-
5
- validates_presence_of :type_label, :abbreviation
6
- validates_uniqueness_of :type_label
7
- end
@@ -1,9 +0,0 @@
1
- name_prefix:
2
- reference_type_id: 1
3
- type_label: NAME_PREFIX
4
- abbreviation: Name Prefix
5
-
6
- gender:
7
- reference_type_id: 2
8
- type_label: GENDER
9
- abbreviation: Gender