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.
Files changed (54) hide show
  1. data/.gitignore +19 -0
  2. data/Rakefile +0 -7
  3. data/autotest/discover.rb +1 -0
  4. data/lib/ninja_model.rb +22 -26
  5. data/lib/ninja_model/adapters.rb +33 -43
  6. data/lib/ninja_model/adapters/abstract_adapter.rb +2 -10
  7. data/lib/ninja_model/adapters/adapter_manager.rb +17 -10
  8. data/lib/ninja_model/adapters/adapter_pool.rb +15 -17
  9. data/lib/ninja_model/adapters/adapter_specification.rb +3 -3
  10. data/lib/ninja_model/associations.rb +25 -106
  11. data/lib/ninja_model/associations/association_proxy.rb +119 -1
  12. data/lib/ninja_model/associations/belongs_to_association.rb +5 -1
  13. data/lib/ninja_model/attribute.rb +130 -0
  14. data/lib/ninja_model/{attributes.rb → attribute_methods.rb} +21 -42
  15. data/lib/ninja_model/base.rb +23 -20
  16. data/lib/ninja_model/callbacks.rb +2 -11
  17. data/lib/ninja_model/identity.rb +6 -11
  18. data/lib/ninja_model/persistence.rb +15 -30
  19. data/lib/ninja_model/predicate.rb +4 -4
  20. data/lib/ninja_model/rails_ext/active_record.rb +187 -0
  21. data/lib/ninja_model/railtie.rb +14 -8
  22. data/lib/ninja_model/reflection.rb +7 -14
  23. data/lib/ninja_model/relation.rb +5 -3
  24. data/lib/ninja_model/relation/finder_methods.rb +4 -8
  25. data/lib/ninja_model/relation/spawn_methods.rb +1 -1
  26. data/lib/ninja_model/validation.rb +6 -23
  27. data/lib/ninja_model/version.rb +1 -1
  28. data/ninja-model.gemspec +28 -0
  29. data/spec/ninja_model/adapters/abstract_adapter_spec.rb +45 -0
  30. data/spec/ninja_model/adapters/adapter_manager_spec.rb +69 -0
  31. data/spec/ninja_model/adapters/adapter_pool_spec.rb +210 -48
  32. data/spec/ninja_model/adapters_spec.rb +77 -0
  33. data/spec/ninja_model/attribute_methods_spec.rb +95 -0
  34. data/spec/ninja_model/attribute_spec.rb +129 -0
  35. data/spec/ninja_model/base_spec.rb +4 -52
  36. data/spec/ninja_model/identity_spec.rb +16 -32
  37. data/spec/ninja_model/persistence_spec.rb +130 -4
  38. data/spec/ninja_model/predicate_spec.rb +40 -6
  39. data/spec/ninja_model/query_methods_spec.rb +76 -74
  40. data/spec/ninja_model/reflection_spec.rb +63 -0
  41. data/spec/ninja_model/relation_spec.rb +213 -20
  42. data/spec/ninja_model/symbol_spec.rb +19 -0
  43. data/spec/ninja_model/validation_spec.rb +18 -0
  44. data/spec/spec_helper.rb +9 -0
  45. data/spec/support/matchers/convert.rb +30 -0
  46. metadata +85 -63
  47. data/lib/ninja_model/associations/active_record_proxy.rb +0 -53
  48. data/lib/ninja_model/associations/ninja_model_proxy.rb +0 -46
  49. data/lib/ninja_model/configuration.rb +0 -20
  50. data/lib/ninja_model/errors.rb +0 -5
  51. data/lib/ninja_model/log_subscriber.rb +0 -18
  52. data/lib/ninja_model/scoping.rb +0 -50
  53. data/spec/ninja_model/attributes_spec.rb +0 -85
  54. data/spec/ninja_model/scoping_spec.rb +0 -40
@@ -1,16 +1,11 @@
1
- require 'active_support'
2
-
3
1
  module NinjaModel
4
- module Identity
5
- extend ActiveSupport::Concern
6
- include ActiveModel::AttributeMethods
7
-
8
- included do
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
- module Persistence
5
- extend ActiveSupport::Concern
6
- include ActiveModel::AttributeMethods
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
- included do
18
- class_inheritable_accessor :persistence_adapter
19
- end
6
+ module Persistence
20
7
 
21
8
  def save(*)
22
9
  run_callbacks :save do
23
- create_or_update
24
- end
25
- end
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
- self.class.adapter.update(self)
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
- if self.class.adapter.destroy(self)
62
- @destroyed = true
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, :method, :value
6
+ attr_reader :attribute, :meth, :value
7
7
 
8
- def initialize(attribute, method, *args)
8
+ def initialize(attribute, meth, *args)
9
9
  @attribute = attribute
10
- @method = method
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 method
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
@@ -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 = NinjaModel::Configuration.create
4
+ config.ninja_model = ActiveSupport::OrderedOptions.new
8
5
 
9
- #config.generators.orm :ninja_model, :migration => false
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
- config.after_initialize do |app|
16
- config_path = File.join(Rails.root, app.config.ninja_model.config_file_path)
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
- module Reflection
3
- extend ActiveSupport::Concern
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
@@ -1,4 +1,6 @@
1
- require 'active_support/core_ext/object/blank'
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, :last, :all
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
- find_some(ids)
52
+ raise NotImplementedError, "Finding by multiple id's is not implemented"
57
53
  end
58
54
  end
59
55