ninja-model 0.4.2 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/Rakefile +0 -7
- data/autotest/discover.rb +1 -0
- data/lib/ninja_model.rb +22 -26
- data/lib/ninja_model/adapters.rb +33 -43
- data/lib/ninja_model/adapters/abstract_adapter.rb +2 -10
- data/lib/ninja_model/adapters/adapter_manager.rb +17 -10
- data/lib/ninja_model/adapters/adapter_pool.rb +15 -17
- data/lib/ninja_model/adapters/adapter_specification.rb +3 -3
- data/lib/ninja_model/associations.rb +25 -106
- data/lib/ninja_model/associations/association_proxy.rb +119 -1
- data/lib/ninja_model/associations/belongs_to_association.rb +5 -1
- data/lib/ninja_model/attribute.rb +130 -0
- data/lib/ninja_model/{attributes.rb → attribute_methods.rb} +21 -42
- data/lib/ninja_model/base.rb +23 -20
- data/lib/ninja_model/callbacks.rb +2 -11
- data/lib/ninja_model/identity.rb +6 -11
- data/lib/ninja_model/persistence.rb +15 -30
- data/lib/ninja_model/predicate.rb +4 -4
- data/lib/ninja_model/rails_ext/active_record.rb +187 -0
- data/lib/ninja_model/railtie.rb +14 -8
- data/lib/ninja_model/reflection.rb +7 -14
- data/lib/ninja_model/relation.rb +5 -3
- data/lib/ninja_model/relation/finder_methods.rb +4 -8
- data/lib/ninja_model/relation/spawn_methods.rb +1 -1
- data/lib/ninja_model/validation.rb +6 -23
- data/lib/ninja_model/version.rb +1 -1
- data/ninja-model.gemspec +28 -0
- data/spec/ninja_model/adapters/abstract_adapter_spec.rb +45 -0
- data/spec/ninja_model/adapters/adapter_manager_spec.rb +69 -0
- data/spec/ninja_model/adapters/adapter_pool_spec.rb +210 -48
- data/spec/ninja_model/adapters_spec.rb +77 -0
- data/spec/ninja_model/attribute_methods_spec.rb +95 -0
- data/spec/ninja_model/attribute_spec.rb +129 -0
- data/spec/ninja_model/base_spec.rb +4 -52
- data/spec/ninja_model/identity_spec.rb +16 -32
- data/spec/ninja_model/persistence_spec.rb +130 -4
- data/spec/ninja_model/predicate_spec.rb +40 -6
- data/spec/ninja_model/query_methods_spec.rb +76 -74
- data/spec/ninja_model/reflection_spec.rb +63 -0
- data/spec/ninja_model/relation_spec.rb +213 -20
- data/spec/ninja_model/symbol_spec.rb +19 -0
- data/spec/ninja_model/validation_spec.rb +18 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/matchers/convert.rb +30 -0
- metadata +85 -63
- data/lib/ninja_model/associations/active_record_proxy.rb +0 -53
- data/lib/ninja_model/associations/ninja_model_proxy.rb +0 -46
- data/lib/ninja_model/configuration.rb +0 -20
- data/lib/ninja_model/errors.rb +0 -5
- data/lib/ninja_model/log_subscriber.rb +0 -18
- data/lib/ninja_model/scoping.rb +0 -50
- data/spec/ninja_model/attributes_spec.rb +0 -85
- data/spec/ninja_model/scoping_spec.rb +0 -40
data/lib/ninja_model/identity.rb
CHANGED
@@ -1,16 +1,11 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
|
3
1
|
module NinjaModel
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
class_inheritable_accessor :primary_key
|
10
|
-
self.primary_key = :id
|
11
|
-
undef_method(:id) if method_defined?(:id)
|
12
|
-
end
|
2
|
+
class Base
|
3
|
+
class_inheritable_accessor :primary_key
|
4
|
+
self.primary_key = :id
|
5
|
+
undef_method(:id) if method_defined?(:id)
|
6
|
+
end
|
13
7
|
|
8
|
+
module Identity
|
14
9
|
def to_param
|
15
10
|
send(self.class.primary_key).to_s if persisted?
|
16
11
|
end
|
@@ -1,34 +1,15 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
|
3
1
|
module NinjaModel
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
def get(rel)
|
10
|
-
end
|
11
|
-
|
12
|
-
def persist_with(adapter)
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
2
|
+
class Base
|
3
|
+
define_model_callbacks :save, :create, :update, :destroy
|
4
|
+
end
|
16
5
|
|
17
|
-
|
18
|
-
class_inheritable_accessor :persistence_adapter
|
19
|
-
end
|
6
|
+
module Persistence
|
20
7
|
|
21
8
|
def save(*)
|
22
9
|
run_callbacks :save do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def create_or_update
|
28
|
-
if new_record?
|
29
|
-
create
|
30
|
-
else
|
31
|
-
update
|
10
|
+
result = new_record? ? create : update
|
11
|
+
changed_attributes.clear if result
|
12
|
+
result
|
32
13
|
end
|
33
14
|
end
|
34
15
|
|
@@ -42,7 +23,9 @@ module NinjaModel
|
|
42
23
|
end
|
43
24
|
|
44
25
|
def update
|
45
|
-
|
26
|
+
run_callbacks :update do
|
27
|
+
self.class.adapter.update(self)
|
28
|
+
end
|
46
29
|
end
|
47
30
|
|
48
31
|
def new_record?
|
@@ -58,10 +41,12 @@ module NinjaModel
|
|
58
41
|
end
|
59
42
|
|
60
43
|
def destroy
|
61
|
-
|
62
|
-
|
44
|
+
run_callbacks :destroy do
|
45
|
+
if self.class.adapter.destroy(self)
|
46
|
+
@destroyed = true
|
47
|
+
end
|
48
|
+
@destroyed
|
63
49
|
end
|
64
|
-
@destroyed
|
65
50
|
end
|
66
51
|
|
67
52
|
def reload
|
@@ -3,11 +3,11 @@ module NinjaModel
|
|
3
3
|
|
4
4
|
PREDICATES = [:eq, :ne, :gt, :gte, :lt, :lte, :in]
|
5
5
|
|
6
|
-
attr_reader :attribute, :
|
6
|
+
attr_reader :attribute, :meth, :value
|
7
7
|
|
8
|
-
def initialize(attribute,
|
8
|
+
def initialize(attribute, meth, *args)
|
9
9
|
@attribute = attribute
|
10
|
-
@
|
10
|
+
@meth = meth
|
11
11
|
@valued = !args.blank?
|
12
12
|
@value = args.blank? ? nil : args.first
|
13
13
|
end
|
@@ -22,7 +22,7 @@ module NinjaModel
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test(suspect)
|
25
|
-
case
|
25
|
+
case meth
|
26
26
|
when :eq
|
27
27
|
suspect.eql?(value)
|
28
28
|
when :ne
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Base
|
5
|
+
class << self
|
6
|
+
def has_one_with_ninja_model(association_id, options = {})
|
7
|
+
if NinjaModel.ninja_model?(options[:class_name] || association_id)
|
8
|
+
ninja_proxy.handle_association(:has_one, association_id, options)
|
9
|
+
else
|
10
|
+
has_one_without_ninja_model(association_id, options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
alias_method_chain :has_one, :ninja_model
|
14
|
+
|
15
|
+
def reflect_on_association_with_ninja_model(association)
|
16
|
+
if read_inheritable_attribute(:ninja_proxy) && ninja_proxy.proxy_klass.reflections.include?(association)
|
17
|
+
ninja_proxy.proxy_klass.reflect_on_association(association)
|
18
|
+
else
|
19
|
+
reflect_on_association_without_ninja_model(association)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method_chain :reflect_on_association, :ninja_model
|
24
|
+
|
25
|
+
def ninja_proxy
|
26
|
+
read_inheritable_attribute(:ninja_proxy) || write_inheritable_attribute(:ninja_proxy, NinjaModel::Associations::NinjaModelProxy.new(self))
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(method, *args)
|
32
|
+
begin
|
33
|
+
super
|
34
|
+
rescue NoMethodError => ex
|
35
|
+
if self.class.read_inheritable_attribute(:ninja_proxy) && ninja_proxy.respond_to?(method)
|
36
|
+
ninja_proxy.send(method, *args)
|
37
|
+
else
|
38
|
+
raise ex
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module NinjaModel
|
46
|
+
|
47
|
+
class Base
|
48
|
+
class << self
|
49
|
+
def has_one_with_active_record(association_id, options = {})
|
50
|
+
if ninja_model?(:has_one, options[:class_name] || association_id)
|
51
|
+
has_one_without_active_record(association_id, options)
|
52
|
+
else
|
53
|
+
proxy.handle_association(:has_one, association_id, options)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
alias_method_chain :has_one, :active_record
|
58
|
+
|
59
|
+
def belongs_to_with_active_record(association_id, options = {})
|
60
|
+
if ninja_model?(:belongs_to, options[:class_name] || association_id)
|
61
|
+
belongs_to_without_active_record(association_id, options)
|
62
|
+
else
|
63
|
+
proxy.handle_association(:belongs_to, association_id, options)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
alias_method_chain :belongs_to, :active_record
|
68
|
+
|
69
|
+
def has_many_with_active_record(association_id, options = {})
|
70
|
+
if ninja_model?(:has_many, association_id)
|
71
|
+
has_many_without_active_record(association_id, options)
|
72
|
+
else
|
73
|
+
proxy.handle_association(:has_many, association_id, options)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
alias_method_chain :has_many, :active_record
|
78
|
+
|
79
|
+
def proxy
|
80
|
+
read_inheritable_attribute(:proxy) || write_inheritable_attribute(:proxy, Associations::ActiveRecordProxy.new(self))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def method_missing(method, *args)
|
85
|
+
if self.class.read_inheritable_attribute(:proxy) && proxy.respond_to?(method)
|
86
|
+
proxy.send(method, *args)
|
87
|
+
else
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module Associations
|
94
|
+
class ActiveRecordProxy
|
95
|
+
def initialize(ninja_model)
|
96
|
+
@klass = ninja_model
|
97
|
+
@klass.class_eval do
|
98
|
+
def proxy
|
99
|
+
@proxy ||= begin
|
100
|
+
self.class.proxy.instance(self)
|
101
|
+
end
|
102
|
+
@proxy.attributes = self.attributes.delete_if { |k,v| k.eql?('id') }
|
103
|
+
@proxy
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
@proxy_klass = ninja_model.parent.const_set("#{@klass.model_name}Proxy", Class.new(ActiveRecord::Base))
|
108
|
+
@proxy_klass.class_eval do
|
109
|
+
cattr_accessor :columns
|
110
|
+
self.columns = []
|
111
|
+
def self.column(name, sql_type = nil, default = nil)
|
112
|
+
self.columns << ActiveRecord::ConnectionAdapters::Column.new(name, nil, sql_type.to_s, default)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
@klass.model_attributes.each do |attr|
|
117
|
+
@proxy_klass.send :column, attr.name, attr.type, attr.default
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def instance(obj)
|
122
|
+
proxy = @proxy_klass.new
|
123
|
+
proxy.send :init_with, {'attributes' => obj.attributes}
|
124
|
+
proxy
|
125
|
+
end
|
126
|
+
|
127
|
+
def handle_association(macro, association_id, options)
|
128
|
+
unless macro.eql?(:belongs_to)
|
129
|
+
options = {:foreign_key => derive_foreign_key}.merge(options)
|
130
|
+
end
|
131
|
+
|
132
|
+
@proxy = nil
|
133
|
+
@proxy_klass.send macro, association_id, options
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def derive_foreign_key
|
139
|
+
"#{@klass.name.underscore}_id".to_sym
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class NinjaModelProxy
|
144
|
+
attr_reader :proxy_klass
|
145
|
+
def initialize(active_record)
|
146
|
+
@klass = active_record
|
147
|
+
@klass.class_eval do
|
148
|
+
def ninja_proxy
|
149
|
+
@ninja_proxy ||= begin
|
150
|
+
self.class.ninja_proxy.instance(self)
|
151
|
+
end
|
152
|
+
@ninja_proxy.attributes = self.attributes.delete_if { |k,v| k.eql?('id') }
|
153
|
+
@ninja_proxy
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
@proxy_klass = active_record.parent.const_set("#{@klass.model_name}Proxy", Class.new(NinjaModel::Base))
|
158
|
+
|
159
|
+
@klass.columns_hash.each_pair do |k,v|
|
160
|
+
@proxy_klass.send :attribute, k, v.type, v.default, @proxy_klass
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def instance(obj)
|
165
|
+
proxy = @proxy_klass.new
|
166
|
+
proxy.send :instantiate, {'attributes' => obj.attributes}
|
167
|
+
proxy
|
168
|
+
end
|
169
|
+
|
170
|
+
def handle_association(macro, association_id, options)
|
171
|
+
unless macro.eql?(:belongs_to)
|
172
|
+
options = {:foreign_key => derive_foreign_key}.merge(options)
|
173
|
+
end
|
174
|
+
|
175
|
+
@proxy = nil
|
176
|
+
@proxy_klass.send macro, association_id, options
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def derive_foreign_key
|
182
|
+
"#{@klass.name.underscore}_id".to_sym
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
data/lib/ninja_model/railtie.rb
CHANGED
@@ -1,27 +1,33 @@
|
|
1
|
-
require 'ninja_model'
|
2
|
-
require 'rails/all'
|
3
|
-
|
4
1
|
module NinjaModel
|
5
2
|
class Railtie < Rails::Railtie
|
6
3
|
|
7
|
-
config.ninja_model =
|
4
|
+
config.ninja_model = ActiveSupport::OrderedOptions.new
|
8
5
|
|
9
|
-
|
6
|
+
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
|
7
|
+
"NinjaModel::Adapters::AdapterManagement"
|
10
8
|
|
11
9
|
initializer 'ninja_model.logger' do |app|
|
12
10
|
NinjaModel::set_logger(Rails.logger)
|
13
11
|
end
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
initializer 'ninja_model_extend_active_record' do |app|
|
14
|
+
ActiveSupport.on_load(:active_record) do
|
15
|
+
require 'ninja_model/rails_ext/active_record'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
initializer 'ninja_model_load_specs' do |app|
|
20
|
+
config_path = File.join(app.paths.config.to_a.first, "ninja_model.yml")
|
17
21
|
if File.exists?(config_path)
|
18
22
|
require 'erb'
|
19
23
|
require 'yaml'
|
20
24
|
app.config.ninja_model.specs = YAML::load(ERB.new(IO.read(config_path)).result)
|
21
|
-
NinjaModel::Base.set_adapter
|
22
25
|
else
|
23
26
|
NinjaModel.logger.warn "[ninja-model] *WARNING* Unable to find configuration file at #{config_path}"
|
24
27
|
end
|
25
28
|
end
|
29
|
+
|
30
|
+
config.after_initialize do |app|
|
31
|
+
end
|
26
32
|
end
|
27
33
|
end
|
@@ -1,13 +1,10 @@
|
|
1
1
|
module NinjaModel
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
module ClassMethods
|
2
|
+
class Base
|
3
|
+
class << self
|
6
4
|
def create_reflection(macro, name, options, ninja_model)
|
7
5
|
case macro
|
8
6
|
when :has_many, :belongs_to, :has_one
|
9
|
-
reflection = AssociationReflection.new(macro, name, options, ninja_model)
|
10
|
-
when :composed_of
|
7
|
+
reflection = Reflection::AssociationReflection.new(macro, name, options, ninja_model)
|
11
8
|
end
|
12
9
|
write_inheritable_hash :reflections, name => reflection
|
13
10
|
reflection
|
@@ -25,9 +22,12 @@ module NinjaModel
|
|
25
22
|
end
|
26
23
|
|
27
24
|
def reflect_on_association(association)
|
28
|
-
reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil
|
25
|
+
reflections[association].is_a?(Reflection::AssociationReflection) ? reflections[association] : nil
|
29
26
|
end
|
30
27
|
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Reflection
|
31
31
|
|
32
32
|
class MacroReflection
|
33
33
|
def initialize(macro, name, options, ninja_model)
|
@@ -77,13 +77,6 @@ module NinjaModel
|
|
77
77
|
@association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
|
78
78
|
end
|
79
79
|
|
80
|
-
def check_validity!
|
81
|
-
check_validity_of_inverse!
|
82
|
-
end
|
83
|
-
|
84
|
-
def check_validity_of_inverse!
|
85
|
-
end
|
86
|
-
|
87
80
|
def collection?
|
88
81
|
@collection
|
89
82
|
end
|
data/lib/ninja_model/relation.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'ninja_model/relation/query_methods'
|
2
|
+
require 'ninja_model/relation/finder_methods'
|
3
|
+
require 'ninja_model/relation/spawn_methods'
|
2
4
|
|
3
5
|
module NinjaModel
|
4
6
|
class Relation
|
@@ -58,13 +60,13 @@ module NinjaModel
|
|
58
60
|
size.zero?
|
59
61
|
end
|
60
62
|
|
61
|
-
protected
|
62
|
-
|
63
63
|
alias :inspect! :inspect
|
64
64
|
def inspect
|
65
65
|
to_a.inspect
|
66
66
|
end
|
67
67
|
|
68
|
+
protected
|
69
|
+
|
68
70
|
def method_missing(method, *args, &block)
|
69
71
|
if Array.method_defined?(method)
|
70
72
|
to_a.send(method, *args, &block)
|
@@ -1,18 +1,14 @@
|
|
1
1
|
module NinjaModel
|
2
|
+
class RecordNotFound < NinjaModelError; end
|
2
3
|
module FinderMethods
|
3
4
|
def first(*args)
|
4
5
|
if args.any?
|
6
|
+
apply_finder_options(args.first).limit(1).to_a.first
|
5
7
|
else
|
6
8
|
find_first
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
|
-
def last(*args)
|
11
|
-
if args.any?
|
12
|
-
else
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
12
|
def all(*args)
|
17
13
|
args.any? ? apply_finder_options(args.first).to_a : to_a
|
18
14
|
end
|
@@ -24,7 +20,7 @@ module NinjaModel
|
|
24
20
|
apply_finder_options(options).find(*args)
|
25
21
|
else
|
26
22
|
case args.first
|
27
|
-
when :first, :
|
23
|
+
when :first, :all
|
28
24
|
send(args.first)
|
29
25
|
else
|
30
26
|
find_with_ids(*args)
|
@@ -53,7 +49,7 @@ module NinjaModel
|
|
53
49
|
result = find_one(ids.first)
|
54
50
|
expects_array ? [result] : result
|
55
51
|
else
|
56
|
-
|
52
|
+
raise NotImplementedError, "Finding by multiple id's is not implemented"
|
57
53
|
end
|
58
54
|
end
|
59
55
|
|