xli-hickey 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +1 -0
- data/LICENSE.TXT +203 -0
- data/README +115 -0
- data/Rakefile +97 -0
- data/TODO +53 -0
- data/hickey.gemspec +26 -0
- data/lib/hickey/acceptor.rb +25 -0
- data/lib/hickey/domain_detector/actions.rb +38 -0
- data/lib/hickey/domain_detector/associations.rb +80 -0
- data/lib/hickey/domain_detector/base.rb +55 -0
- data/lib/hickey/domain_detector/configurable.rb +38 -0
- data/lib/hickey/domain_detector/scopes.rb +30 -0
- data/lib/hickey/domain_detector.rb +17 -0
- data/lib/hickey.rb +22 -0
- data/test/belongs_to_association_test.rb +17 -0
- data/test/database_config.rb +20 -0
- data/test/enable_callbacks_test.rb +135 -0
- data/test/find_or_create_actions_test.rb +62 -0
- data/test/has_and_belongs_to_many_association_test.rb +10 -0
- data/test/has_many_association_test.rb +71 -0
- data/test/has_one_association_test.rb +53 -0
- data/test/model_association_test.rb +21 -0
- data/test/models/address.rb +5 -0
- data/test/models/author.rb +10 -0
- data/test/models/country.rb +4 -0
- data/test/models/project.rb +9 -0
- data/test/models/projects_member.rb +5 -0
- data/test/models/property_definition.rb +21 -0
- data/test/models/simple.rb +26 -0
- data/test/models/tag.rb +17 -0
- data/test/models/topic.rb +19 -0
- data/test/models/user.rb +9 -0
- data/test/models/writer.rb +9 -0
- data/test/schema.rb +88 -0
- data/test/single_model_test.rb +117 -0
- data/test/test_helper.rb +83 -0
- data/test/with_scope_test.rb +56 -0
- metadata +97 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Hickey
|
2
|
+
module DomainDetector
|
3
|
+
class Base
|
4
|
+
def visit(domain)
|
5
|
+
r = {}
|
6
|
+
domain.each do |key, value|
|
7
|
+
r[key] = value.accept_for_hickey(key, self)
|
8
|
+
end
|
9
|
+
r.size == 1 ? r.values.first : r
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit_hash(attribute, record)
|
13
|
+
owner = new_instance(attribute, record)
|
14
|
+
after_created = []
|
15
|
+
|
16
|
+
record.each do |key, value|
|
17
|
+
if reflection = owner.class.reflections[key]
|
18
|
+
after_created << send(reflection.macro, owner, reflection, value)
|
19
|
+
else
|
20
|
+
owner.send :write_attribute, key, value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#bypass new alias method chain of save! method
|
25
|
+
owner.save_with_validation!
|
26
|
+
|
27
|
+
after_created.each(&:call)
|
28
|
+
owner
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def new_instance(class_or_instance, record)
|
33
|
+
return class_or_instance unless ['Class', 'String', 'Symbol'].include?(class_or_instance.class.name)
|
34
|
+
compute_type(class_or_instance, record).new
|
35
|
+
end
|
36
|
+
|
37
|
+
def compute_type(class_name, record)
|
38
|
+
klass = class_name.is_a?(Class) ? class_name : class_name.to_s.classify.constantize
|
39
|
+
if (subclass_name = record[klass.inheritance_column.to_sym]).blank?
|
40
|
+
klass
|
41
|
+
else
|
42
|
+
begin
|
43
|
+
subclass_name.to_s.classify.constantize
|
44
|
+
rescue NameError
|
45
|
+
raise ActiveRecord::SubclassNotFound,
|
46
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{subclass_name}'. " +
|
47
|
+
"This error is raised because the column '#{klass.inheritance_column}' is reserved for storing the class in case of inheritance. " +
|
48
|
+
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
49
|
+
"or overwrite #{klass.name}.inheritance_column to use another column for that information."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hickey
|
2
|
+
module DomainDetector
|
3
|
+
module Configurable
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
@@configurations = {}
|
7
|
+
cattr_accessor :configurations, :instance_writer => false
|
8
|
+
alias_method_chain :new_instance, :configuration
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def new_instance_with_configuration(class_or_instance, record)
|
14
|
+
instance = new_instance_without_configuration(class_or_instance, record)
|
15
|
+
instance.instance_eval do
|
16
|
+
def valid_without_callbacks?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
unless configuration_of(instance)[:callbacks] == :all
|
21
|
+
callbacks = configuration_of(instance)[:callbacks] || []
|
22
|
+
instance.instance_eval <<-"end_eval"
|
23
|
+
alias :original_callback :callback
|
24
|
+
def callback(method)
|
25
|
+
[#{callbacks.collect(&:inspect).join(',')}].include?(method) ? original_callback(method) : true
|
26
|
+
end
|
27
|
+
end_eval
|
28
|
+
end
|
29
|
+
instance
|
30
|
+
end
|
31
|
+
|
32
|
+
def configuration_of(instance)
|
33
|
+
klass = instance.class
|
34
|
+
@@configurations[klass.name.underscore.to_sym] || @@configurations[klass.base_class.name.underscore.to_sym] || {}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Hickey
|
2
|
+
module DomainDetector
|
3
|
+
module Scopes
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:alias_method_chain, :visit_hash, :scopes)
|
6
|
+
base.send(:alias_method_chain, :new_instance, :scopes)
|
7
|
+
end
|
8
|
+
|
9
|
+
def visit_hash_with_scopes(attribute, record)
|
10
|
+
scopes.each do |foreign_key, owner|
|
11
|
+
record[foreign_key] = owner.id unless record[foreign_key]
|
12
|
+
end
|
13
|
+
returning visit_hash_without_scopes(attribute, record) do |instance|
|
14
|
+
scopes.delete instance.class.name.foreign_key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def new_instance_with_scopes(class_or_instance, record)
|
19
|
+
returning new_instance_without_scopes(class_or_instance, record) do |instance|
|
20
|
+
scopes[instance.class.name.foreign_key] = instance
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def scopes
|
26
|
+
@scopes ||= {}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'hickey/domain_detector/base'
|
2
|
+
require 'hickey/domain_detector/associations'
|
3
|
+
require 'hickey/domain_detector/configurable'
|
4
|
+
require 'hickey/domain_detector/actions'
|
5
|
+
require 'hickey/domain_detector/scopes'
|
6
|
+
|
7
|
+
Hickey::DomainDetector::Base.class_eval do
|
8
|
+
include Hickey::DomainDetector::BelongsToAssociation
|
9
|
+
include Hickey::DomainDetector::HasOneAssociation
|
10
|
+
include Hickey::DomainDetector::HasOneThroughAssociation
|
11
|
+
include Hickey::DomainDetector::HasManyAssociation
|
12
|
+
include Hickey::DomainDetector::HasManyThroughAssociation
|
13
|
+
include Hickey::DomainDetector::HasAndBelongsToManyAssociation
|
14
|
+
include Hickey::DomainDetector::Configurable
|
15
|
+
include Hickey::DomainDetector::Scopes
|
16
|
+
include Hickey::DomainDetector::Actions
|
17
|
+
end
|
data/lib/hickey.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'active_record'
|
4
|
+
rescue LoadError
|
5
|
+
require 'rubygems'
|
6
|
+
require 'active_record'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'hickey/acceptor'
|
10
|
+
require 'hickey/domain_detector'
|
11
|
+
|
12
|
+
module Hickey
|
13
|
+
def kiss(domain)
|
14
|
+
DomainDetector::Base.new.visit(domain)
|
15
|
+
end
|
16
|
+
|
17
|
+
def lipstick(domain={})
|
18
|
+
DomainDetector::Base.configurations.merge! domain
|
19
|
+
end
|
20
|
+
|
21
|
+
module_function :kiss, :lipstick
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class BelongsToAssociationTest < Test::Unit::TestCase
|
4
|
+
def test_create_associated_belongs_to_model
|
5
|
+
Hickey.kiss :projects_member => {:user => {:login => 'xli'}}
|
6
|
+
assert_not_nil projects_member.user
|
7
|
+
assert_equal 'xli', projects_member.user.login
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_create_associated_belongs_to_model_with_class_name
|
11
|
+
Hickey.kiss :topic => {:title => 'Bla bla...', :owner => {:login => 'xli'}}
|
12
|
+
|
13
|
+
topic = Topic.find(:first)
|
14
|
+
assert_not_nil topic.owner
|
15
|
+
assert_equal 'xli', topic.owner.login
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
RAILS_DEFAULT_LOGGER = Logger.new(File.expand_path(File.dirname(__FILE__)) + '/debug.log')
|
4
|
+
RAILS_DEFAULT_LOGGER.level = Logger::DEBUG
|
5
|
+
ActiveRecord::Base.logger = RAILS_DEFAULT_LOGGER
|
6
|
+
|
7
|
+
ActiveRecord::Base.configurations = {
|
8
|
+
'test' => {
|
9
|
+
:database => ":memory:",
|
10
|
+
:adapter => 'sqlite3',
|
11
|
+
:timeout => 500
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection 'test'
|
16
|
+
|
17
|
+
ActiveRecord::Base.silence do
|
18
|
+
ActiveRecord::Migration.verbose = false
|
19
|
+
load File.join(File.dirname(__FILE__), 'schema.rb')
|
20
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class EnableCallbacksTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def teardown
|
6
|
+
Hickey.lipstick.clear
|
7
|
+
Simple.public_instance_methods(false).each do |method|
|
8
|
+
next if method == 'id'
|
9
|
+
Simple.class_eval "def #{method};end"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_invoke_before_save_and_after_save_after_configured_all_callbacks
|
14
|
+
Hickey.lipstick(:simple => {:callbacks => :all})
|
15
|
+
Simple.class_eval do
|
16
|
+
before_save :create_user_before_save
|
17
|
+
after_save :create_user_after_save
|
18
|
+
def create_user_after_save
|
19
|
+
Hickey.kiss(:user => {:login => 'create_user_after_save'})
|
20
|
+
end
|
21
|
+
def create_user_before_save
|
22
|
+
Hickey.kiss(:user => {:login => 'create_user_before_save'})
|
23
|
+
end
|
24
|
+
def validate
|
25
|
+
raise 'should bypass'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Hickey.kiss(:simple => {})
|
30
|
+
|
31
|
+
assert_equal ['create_user_before_save', 'create_user_after_save'].sort, User.find(:all).collect(&:login).sort
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_invoke_before_validation_on_create_after_configured_all_callbacks
|
35
|
+
Hickey.lipstick(:simple => {:callbacks => :all})
|
36
|
+
Simple.class_eval do
|
37
|
+
before_validation_on_create :create_user_before_validation_on_create
|
38
|
+
def create_user_before_validation_on_create
|
39
|
+
Hickey.kiss(:user => {:login => 'create_user_before_validation_on_create'})
|
40
|
+
end
|
41
|
+
def validate
|
42
|
+
raise 'should bypass'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Hickey.kiss(:simple => {})
|
47
|
+
assert_equal ['create_user_before_validation_on_create'], User.find(:all).collect(&:login)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_invoke_before_validation_after_configured_all_callbacks
|
51
|
+
Hickey.lipstick(:simple => {:callbacks => :all})
|
52
|
+
Simple.class_eval do
|
53
|
+
before_validation :create_user_before_validation
|
54
|
+
def create_user_before_validation
|
55
|
+
Hickey.kiss(:user => {:login => 'create_user_before_validation'})
|
56
|
+
end
|
57
|
+
def validate
|
58
|
+
raise 'should bypass'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Hickey.kiss(:simple => {})
|
63
|
+
assert_equal ['create_user_before_validation'], User.find(:all).collect(&:login)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_invoke_before_validation_after_configured_all_callbacks
|
67
|
+
Hickey.lipstick(:simple => {:callbacks => :all})
|
68
|
+
Simple.class_eval do
|
69
|
+
after_validation :create_user_after_validation
|
70
|
+
def create_user_after_validation
|
71
|
+
Hickey.kiss(:user => {:login => 'create_user_after_validation'})
|
72
|
+
end
|
73
|
+
def validate
|
74
|
+
raise 'should bypass'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Hickey.kiss(:simple => {})
|
79
|
+
assert_equal ['create_user_after_validation'], User.find(:all).collect(&:login)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_should_not_callback_before_validation_on_create_if_pass_in_existed_model
|
83
|
+
simple = Hickey.kiss(:simple => {})
|
84
|
+
Hickey.lipstick(:simple => {:callbacks => :all})
|
85
|
+
Simple.class_eval do
|
86
|
+
before_validation_on_create :create_user_before_validation_on_create
|
87
|
+
def create_user_before_validation_on_create
|
88
|
+
Hickey.kiss(:user => {:login => 'create_user_before_validation_on_create'})
|
89
|
+
end
|
90
|
+
def validate
|
91
|
+
raise 'should bypass'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Hickey.kiss(simple => {})
|
96
|
+
assert_equal [], User.find(:all).collect(&:login)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_should_enable_configuration_of_invoking_all_callbacks_for_all_subclasses
|
100
|
+
Hickey.lipstick(:property_definition => {:callbacks => :all})
|
101
|
+
DatePropertyDefinition.class_eval do
|
102
|
+
after_validation :create_user_after_validation
|
103
|
+
def create_user_after_validation
|
104
|
+
Hickey.kiss(:user => {:login => 'create_user_after_validation'})
|
105
|
+
end
|
106
|
+
def validate
|
107
|
+
raise 'should bypass'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
Hickey.kiss(:property_definition => {:type => 'DatePropertyDefinition'})
|
112
|
+
|
113
|
+
assert_equal ['create_user_after_validation'], User.find(:all).collect(&:login)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_invoke_callback_specified_after_configured
|
117
|
+
Hickey.lipstick(:simple => {:callbacks => [:after_create, :before_create]})
|
118
|
+
Simple.class_eval do
|
119
|
+
before_create :create_user_before_create
|
120
|
+
after_create :create_user_after_create
|
121
|
+
def create_user_before_create
|
122
|
+
Hickey.kiss(:user => {:login => 'create_user_before_create'})
|
123
|
+
end
|
124
|
+
def create_user_after_create
|
125
|
+
Hickey.kiss(:user => {:login => 'create_user_after_create'})
|
126
|
+
end
|
127
|
+
def validate
|
128
|
+
raise 'should bypass'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
Hickey.kiss(:simple => {})
|
133
|
+
assert_equal ['create_user_after_create', 'create_user_before_create'].sort, User.find(:all).collect(&:login).sort
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class FindOrCreateActionsTest < Test::Unit::TestCase
|
4
|
+
def test_create_action
|
5
|
+
assert Hickey.kiss(:simple => {:create => {}})
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_create_multi_models
|
9
|
+
result = Hickey.kiss(:simple => {:create => {}}, :user => {:create => {:login => 'xli'}})
|
10
|
+
assert_equal({:simple => Simple.find(:first), :user => User.find(:first)}, result)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_create_association_model
|
14
|
+
Hickey.kiss(:project => {:identifier => 'hickey', :users => [{:create => {:login => 'xli', :admin => true}}]})
|
15
|
+
|
16
|
+
assert_equal 'xli', project.users.first.login
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_find_action
|
20
|
+
simple1 = Hickey.kiss(:simple => {})
|
21
|
+
simple2 = Hickey.kiss(:simple => {:find => {}})
|
22
|
+
assert_equal simple1, simple2
|
23
|
+
assert_equal 1, Simple.count(:all)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_find_by_attributes
|
27
|
+
Hickey.kiss(:user => {:login => 'mm'})
|
28
|
+
user1 = Hickey.kiss(:user => {:login => 'xli'})
|
29
|
+
user2 = Hickey.kiss(:user => {:find => {:login => 'xli'}})
|
30
|
+
assert_equal user1, user2
|
31
|
+
assert_equal 2, User.count(:all)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_should_find_model_without_association
|
35
|
+
Hickey.kiss(:project => {:identifier => 'hickey', :users => [{:login => 'xli', :admin => true}]})
|
36
|
+
|
37
|
+
project = Hickey.kiss(:project => {:find => {:identifier => 'hickey', :users => [{:login => 'xli', :admin => true}]}})
|
38
|
+
assert_equal 'hickey', project.identifier
|
39
|
+
assert_equal 'xli', project.users.first.login
|
40
|
+
assert_equal 1, Project.count(:all)
|
41
|
+
|
42
|
+
assert_equal 2, User.count(:all)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_find_model_with_finding_association
|
46
|
+
Hickey.kiss(:project => {:identifier => 'hickey', :users => [{:login => 'xli', :admin => true}]})
|
47
|
+
|
48
|
+
project = Hickey.kiss(:project => {:find => {:identifier => 'hickey', :users => [{:find => {:login => 'xli', :admin => true}}]}})
|
49
|
+
assert_equal 'hickey', project.identifier
|
50
|
+
assert_equal 'xli', project.users.first.login
|
51
|
+
assert_equal 1, Project.count(:all)
|
52
|
+
|
53
|
+
assert_equal 1, User.count(:all)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_find_or_create
|
57
|
+
Hickey.kiss(:simple => {:find_or_create => {}})
|
58
|
+
assert_equal 1, Simple.count(:all)
|
59
|
+
Hickey.kiss(:simple => {:find_or_create => {}})
|
60
|
+
assert_equal 1, Simple.count(:all)
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class HasAndBelongsToManyAssociationTest < Test::Unit::TestCase
|
4
|
+
def test_create_associated_has_and_belongs_to_many_models
|
5
|
+
Hickey.kiss :user => {:login => 'xli', :countries => [{:name => 'China'}]}
|
6
|
+
|
7
|
+
assert_equal 1, user.countries.size
|
8
|
+
assert_equal 'China', user.countries.first.name
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class HasManyAssociationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_create_associated_empty_models
|
6
|
+
Hickey.kiss(:project => {:identifier => 'hickey', :projects_members => []})
|
7
|
+
assert_equal [], project.projects_members
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_create_associated_many_existed_models
|
11
|
+
Hickey.kiss :project => {:identifier => 'hickey', :projects_members => [{}, {}]}
|
12
|
+
|
13
|
+
assert_equal 2, project.projects_members.size
|
14
|
+
assert_not_nil project.projects_members.first
|
15
|
+
assert_not_nil project.projects_members.last
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_option_class_name
|
19
|
+
Hickey.kiss :user => {:login => 'xli', :my_topics => [{:title => 'Bla bla...'}]}
|
20
|
+
assert_equal 1, user.my_topics.size
|
21
|
+
assert_equal 'Bla bla...', user.my_topics.first.title
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_option_through_models
|
25
|
+
Hickey.kiss :project => {:identifier => 'hickey', :users => [{:login => 'xli'}]}
|
26
|
+
assert_equal 1, project.projects_members.size
|
27
|
+
assert_not_nil project.projects_members.first.user
|
28
|
+
assert_equal 'xli', project.projects_members.first.user.login
|
29
|
+
|
30
|
+
assert_equal 'xli', project.users.first.login
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_option_foreign_key
|
34
|
+
Hickey.kiss :writer => {:login => 'xli', :addresses => [{:location => 'BeiJing'}, {:location => 'ShangHai'}]}
|
35
|
+
assert_equal 2, writer.addresses.size
|
36
|
+
assert_equal ['BeiJing', 'ShangHai'].sort, writer.addresses.collect(&:location).sort
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_option_as
|
40
|
+
Hickey.kiss :writer => {:topics => [{:title => 'Hello world'}, {:title => 'Hello world again'}]}
|
41
|
+
assert_equal ['Hello world', 'Hello world again'].sort, writer.topics.collect(&:title).sort
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_option_through_and_as
|
45
|
+
Hickey.kiss :writer => {:login => 'writer', :disscutions => [{:speaker => {:login => 'xli'}}, {:speaker => {:login => 'oo'}}]}
|
46
|
+
speakers = writer.disscutions.collect(&:speaker)
|
47
|
+
assert_equal ['writer', 'xli', 'oo'].sort, User.find(:all).collect(&:login).sort
|
48
|
+
assert_equal 2, speakers.size
|
49
|
+
speakers = [speakers.first.login, speakers.last.login]
|
50
|
+
assert_equal ['xli', 'oo'].sort, speakers.sort
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_specifying_type_attribute_for_single_table_inheritance
|
54
|
+
Hickey.kiss :project => {:all_property_definitions => [{:name => 'status', :type => 'EnumPropertyDefinition'}, {:name => 'owner', :type => 'UserPropertyDefinition'}]}
|
55
|
+
|
56
|
+
assert_equal ['status', 'owner'].sort, project.all_property_definitions.collect(&:name).sort
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_subclass_relationship_of_single_table_inheritance
|
60
|
+
Hickey.kiss :property_definition => {:type => 'EnumPropertyDefinition', :enum_values => [{:value => 'new'}, {:value => 'open'}]}
|
61
|
+
|
62
|
+
assert_equal ['new', 'open'].sort, property_definition.enum_values.collect(&:value).sort
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_should_raise_active_record_subclass_not_found_error_when_cant_find_subclass
|
66
|
+
assert_raise ActiveRecord::SubclassNotFound do
|
67
|
+
Hickey.kiss :property_definition => {:type => 'NotPropertyDefinition'}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class HasOneAssociationTest < Test::Unit::TestCase
|
4
|
+
def test_user_has_one_address
|
5
|
+
Hickey.kiss :user => {:address => {:location => 'BeiJing'}}
|
6
|
+
assert_equal 'BeiJing', user.address.location
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_with_option_foreign_key
|
10
|
+
Hickey.kiss :author => {:address => {:location => 'BeiJing'}}
|
11
|
+
assert_equal 'BeiJing', author.address.location
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_with_option_as_and_class_name
|
15
|
+
Hickey.kiss :author => {:working_topic => {:title => 'Hello world'}}
|
16
|
+
assert_equal 'Hello world', author.working_topic.title
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_with_option_through_has_one
|
20
|
+
Hickey.kiss :author => {:country => {:name => 'China'}}
|
21
|
+
assert_equal 'China', author.country.name
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_with_option_through_source
|
25
|
+
Hickey.kiss :author => {:living_country => {:name => 'China'}}
|
26
|
+
assert_equal 'China', author.living_country.name
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_with_option_through_source_type
|
30
|
+
Hickey.kiss :disscution => {:speaker => {:login => 'xli'}}
|
31
|
+
assert_equal 'xli', disscution.speaker.login
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_through_and_as
|
35
|
+
# fail('do we need this?')
|
36
|
+
end
|
37
|
+
|
38
|
+
#active_record couldn't work on has_one :through belongs to
|
39
|
+
def xtest_with_option_through_belongs_to
|
40
|
+
user = User.create(:login => 'xli')
|
41
|
+
DisscutionBelongsToTopic.create!(:owner => user)
|
42
|
+
assert_equal 'xli', d.owner.login
|
43
|
+
|
44
|
+
Hickey.kiss :disscution_belongs_to_topic => {:owner => {:login => 'xli'}}
|
45
|
+
assert_equal 'xli', disscution_belongs_to_topic.owner.login
|
46
|
+
end
|
47
|
+
|
48
|
+
#active_record couldn't work on has_one :through belongs to
|
49
|
+
def xtest_with_option_through_source_type
|
50
|
+
Hickey.kiss :disscution_belongs_to_topic => {:speaker => {:login => 'xli'}}
|
51
|
+
assert_equal 'xli', disscution_belongs_to_topic.speaker.login
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)) + '/test_helper'
|
2
|
+
|
3
|
+
class ModelAssociationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_should_return_same_with_models_loaded_from_db_after_created_models
|
6
|
+
project = Hickey.kiss :project => {:identifier => 'hickey', :projects_members => [:user => {:login => 'xli'}]}
|
7
|
+
|
8
|
+
db_project = Project.find(:first)
|
9
|
+
assert_equal project, db_project
|
10
|
+
assert_equal project.projects_members.size, db_project.projects_members.size
|
11
|
+
assert_equal project.projects_members.first.user, db_project.projects_members.first.user
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_create_associated_both_has_many_association_and_belongs_to_association_models
|
15
|
+
Hickey.kiss :project => {:identifier => 'hickey', :projects_members => [:user => {:login => 'xli'}]}
|
16
|
+
assert_equal 1, project.projects_members.size
|
17
|
+
assert_not_nil project.projects_members.first.user
|
18
|
+
assert_equal 'xli', project.projects_members.first.user.login
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Author < ActiveRecord::Base
|
2
|
+
set_table_name "users"
|
3
|
+
|
4
|
+
has_one :address, :foreign_key => 'user_id'
|
5
|
+
has_one :working_topic, :as => :writer, :class_name => 'Topic'
|
6
|
+
has_one :country, :through => :address
|
7
|
+
has_one :living_country, :through => :address, :source => :country
|
8
|
+
|
9
|
+
should_bypass_all_callbacks_and_validations
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Project < ActiveRecord::Base
|
2
|
+
has_many :projects_members
|
3
|
+
has_many :users, :through => :projects_members
|
4
|
+
has_many :admins, :through => :projects_members, :source => :user, :conditions => ["projects_members.admin = ?", true]
|
5
|
+
has_many :all_property_definitions, :class_name => 'PropertyDefinition'
|
6
|
+
has_many :tags
|
7
|
+
has_many :cards
|
8
|
+
should_bypass_all_callbacks_and_validations
|
9
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class PropertyDefinition < ActiveRecord::Base
|
2
|
+
belongs_to :project
|
3
|
+
end
|
4
|
+
|
5
|
+
class EnumPropertyDefinition < PropertyDefinition
|
6
|
+
has_many :enum_values, :foreign_key => 'property_definition_id'
|
7
|
+
should_bypass_all_callbacks_and_validations
|
8
|
+
end
|
9
|
+
|
10
|
+
class UserPropertyDefinition < PropertyDefinition
|
11
|
+
should_bypass_all_callbacks_and_validations
|
12
|
+
end
|
13
|
+
|
14
|
+
class EnumValue < ActiveRecord::Base
|
15
|
+
belongs_to :property_definition, :class_name => "EnumeratedPropertyDefinition", :foreign_key => "property_definition_id"
|
16
|
+
should_bypass_all_callbacks_and_validations
|
17
|
+
end
|
18
|
+
|
19
|
+
class DatePropertyDefinition < PropertyDefinition
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Simple < ActiveRecord::Base
|
2
|
+
end
|
3
|
+
|
4
|
+
class Prisoner < ActiveRecord::Base
|
5
|
+
set_table_name "users"
|
6
|
+
|
7
|
+
def login=(login)
|
8
|
+
raise 'unsupported operation'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SimpleObserver < ActiveRecord::Observer
|
13
|
+
|
14
|
+
observe Simple
|
15
|
+
def after_save(simple)
|
16
|
+
raise 'should be bypass'
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_create(simple)
|
20
|
+
raise 'should be bypass'
|
21
|
+
end
|
22
|
+
|
23
|
+
def after_update(simple)
|
24
|
+
raise 'should be bypass'
|
25
|
+
end
|
26
|
+
end
|
data/test/models/tag.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Tag < ActiveRecord::Base
|
2
|
+
has_many :taggings, :class_name => '::Tagging'
|
3
|
+
belongs_to :project
|
4
|
+
|
5
|
+
should_bypass_all_callbacks_and_validations
|
6
|
+
end
|
7
|
+
|
8
|
+
class Tagging < ActiveRecord::Base
|
9
|
+
belongs_to :tag
|
10
|
+
belongs_to :taggable, :polymorphic => true
|
11
|
+
should_bypass_all_callbacks_and_validations
|
12
|
+
end
|
13
|
+
|
14
|
+
class Card < ActiveRecord::Base
|
15
|
+
has_many :taggings, :as => :taggable
|
16
|
+
belongs_to :project
|
17
|
+
end
|