ninja-model 0.4.2 → 0.5.1

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