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
@@ -0,0 +1,19 @@
1
+ *~
2
+ *.cache
3
+ *.log
4
+ *.pid
5
+ tmp/**/*
6
+ doc/*
7
+ .DS_Store
8
+ db/*.sqlite3
9
+ doc/api
10
+ doc/app
11
+ doc/plugins
12
+ doc/*.dot
13
+ coverage/*
14
+ *.sw?
15
+ vendor/plugins/ns_web
16
+ Gemfile.lock
17
+ .bundle
18
+ *.gem
19
+ .rspec
data/Rakefile CHANGED
@@ -1,12 +1,9 @@
1
1
  require 'bundler'
2
- Bundler.setup
3
2
  Bundler::GemHelper.install_tasks
4
3
 
5
4
  require 'rake'
6
5
  require 'rake/rdoctask'
7
6
  require 'rspec/core/rake_task'
8
- require 'cucumber'
9
- require 'cucumber/rake/task'
10
7
 
11
8
  RSpec::Core::RakeTask.new(:spec) do |t|
12
9
  t.verbose = false
@@ -32,7 +29,3 @@ namespace :spec do
32
29
  t.rcov_opts << %w{--exclude gems\/,spec\/}
33
30
  end
34
31
  end
35
-
36
- Cucumber::Rake::Task.new(:features) do |t|
37
- t.cucumber_opts = "features --format progress"
38
- end
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { 'rspec2' }
@@ -1,29 +1,8 @@
1
- require 'active_support'
2
- require 'active_support/core_ext/hash/indifferent_access'
1
+ require 'active_model'
2
+ require 'active_support/core_ext'
3
3
 
4
4
  module NinjaModel
5
- extend ActiveSupport::Autoload
6
-
7
- autoload :Base
8
- autoload :Adapters
9
- autoload :Associations
10
- autoload :Attributes
11
- autoload :Callbacks
12
- autoload :Configuration
13
- autoload :Identity
14
- autoload :Persistence
15
- autoload :Predicate
16
- autoload :Reflection
17
- autoload :Relation
18
- autoload :Scoping
19
- autoload :Validation
20
-
21
- autoload_under 'relation' do
22
- autoload :QueryMethods
23
- autoload :FinderMethods
24
- autoload :SpawnMethods
25
- end
26
-
5
+ class NinjaModelError < StandardError; end
27
6
 
28
7
  class << self
29
8
  attr_accessor :logger
@@ -31,8 +10,25 @@ module NinjaModel
31
10
  def set_logger(logger)
32
11
  ::NinjaModel.logger = logger
33
12
  end
13
+
14
+ def ninja_model?(symbol)
15
+ klass = symbol.to_s.camelize
16
+ klass = klass.singularize
17
+ klass = klass.constantize
18
+ klass.ancestors.include?(NinjaModel::Base)
19
+ end
20
+
21
+ def configuration
22
+ Rails.application.config.ninja_model
23
+ end
24
+ end
25
+
26
+ class Base
34
27
  end
35
28
  end
36
29
 
37
- require 'ninja_model/railtie'
38
- require 'ninja_model/errors'
30
+ require 'ninja_model/base'
31
+ require 'ninja_model/core_ext/symbol'
32
+ if defined?(Rails)
33
+ require 'ninja_model/railtie'
34
+ end
@@ -1,18 +1,14 @@
1
- require 'active_support'
1
+ require 'ninja_model/adapters/abstract_adapter'
2
+ require 'ninja_model/adapters/adapter_manager'
3
+ require 'ninja_model/adapters/adapter_pool'
4
+ require 'ninja_model/adapters/adapter_specification'
2
5
 
3
6
  module NinjaModel
4
7
 
5
8
  module Adapters
6
- extend ActiveSupport::Concern
7
- extend ActiveSupport::Autoload
8
-
9
- autoload :AdapterSpecification
10
- autoload :AdapterManager
11
- autoload :AdapterPool
12
- autoload :AbstractAdapter
13
-
14
- class << self
15
- end
9
+ class AdapterNotSpecified < StandardError; end
10
+ class InvalidAdapter < StandardError; end
11
+ class InvalidSpecification < StandardError; end
16
12
  end
17
13
 
18
14
  class Base
@@ -20,47 +16,41 @@ module NinjaModel
20
16
  self.adapter_manager = NinjaModel::Adapters::AdapterManager.new
21
17
 
22
18
  def adapter
23
- self.class.adapter
19
+ self.class.retrieve_adapter
24
20
  end
25
21
 
26
- def self.set_adapter(spec = nil)
27
- case spec
28
- when nil
29
- raise AdapterNotSpecified unless defined?(Rails.env)
30
- set_adapter(Rails.env)
31
- when AdapterSpecification
32
- self.adapter_manager.create_adapter(name, spec)
33
- when Symbol, String
34
- if config = NinjaModel.configuration.specs[spec.to_s]
35
- set_adapter(config)
36
- else
37
- raise AdapterNotSpecified, "#{spec} is not configured"
38
- end
39
- else
40
- spec = spec.symbolize_keys
41
- unless spec.key?(:adapter) then raise AdapterNotSpecified, "configuration does not specify adapter" end
42
- begin
43
- require File.join(NinjaModel.configuration.adapter_path, "#{spec[:adapter]}_adapter")
44
- rescue LoadError => e
45
- raise "Please install (or create) the #{spec[:adapter]} adapter. Search path is #{NinjaModel.configuration.adapter_path}"
46
- end
47
- adapter_method = "#{spec[:adapter]}_adapter"
48
- if !respond_to?(adapter_method)
49
- raise AdapterNotFound, "ninja configuration specifies nonexistent #{spec[:adapter]} adapter"
50
- end
51
- shutdown_adapter
52
- set_adapter(AdapterSpecification.new(spec, adapter_method))
22
+ class << self
23
+ def register_adapter(name, klass)
24
+ Adapters::AdapterManager.register_adapter_class(name, klass)
53
25
  end
54
- end
55
26
 
56
- class << self
57
- def adapter
58
- retrieve_adapter
27
+ def set_adapter(spec = nil)
28
+ case spec
29
+ when nil
30
+ raise Adapters::AdapterNotSpecified unless defined?(Rails.env)
31
+ set_adapter(Rails.env)
32
+ when Adapters::AdapterSpecification
33
+ self.adapter_manager.create_adapter(name, spec)
34
+ when Symbol, String
35
+ if config = NinjaModel.configuration.specs[spec.to_s]
36
+ set_adapter(config)
37
+ else
38
+ raise Adapters::InvalidSpecification, "#{spec} is not configured"
39
+ end
40
+ else
41
+ spec = spec.symbolize_keys
42
+ raise Adapters::AdapterNotSpecified, "configuration does not specify adapter" unless spec.key?(:adapter)
43
+ adapter_name = spec[:adapter]
44
+ raise Adapters::InvalidAdapter, "configuration does not specify adapter" unless Adapters::AdapterManager.registered?(adapter_name)
45
+ shutdown_adapter
46
+ set_adapter(Adapters::AdapterSpecification.new(spec, adapter_name))
47
+ end
59
48
  end
60
49
 
61
50
  def retrieve_adapter
62
51
  adapter_manager.retrieve_adapter(self)
63
52
  end
53
+ alias :adapter :retrieve_adapter
64
54
 
65
55
  def shutdown_adapter(klass = self)
66
56
  adapter_manager.remove_adapter(klass)
@@ -1,14 +1,10 @@
1
1
  module NinjaModel
2
2
  module Adapters
3
3
  class AbstractAdapter
4
- class << self
5
- def instance
6
- @instance ||= new
7
- end
8
- end
4
+ attr_reader :config
9
5
 
10
6
  def initialize(config, logger = nil)
11
- @active = nil
7
+ @active = false
12
8
  @config, @logger = config, logger
13
9
  end
14
10
 
@@ -54,10 +50,6 @@ module NinjaModel
54
50
  def destroy(model)
55
51
  false
56
52
  end
57
-
58
- def raw_connection
59
- @connection
60
- end
61
53
  end
62
54
  end
63
55
  end
@@ -1,10 +1,23 @@
1
1
  module NinjaModel
2
2
  module Adapters
3
3
  class AdapterManager
4
+ class_attribute :registered
5
+ self.registered = {}
6
+ class << self
7
+ def registered?(name)
8
+ registered.key?(name.to_sym)
9
+ end
10
+
11
+ def register_adapter_class(name, klass)
12
+ registered[name.to_sym] = klass
13
+ end
14
+ end
15
+
4
16
  attr_reader :adapter_pools
5
17
 
6
18
  def initialize(pools = {})
7
19
  @adapter_pools = pools
20
+ @registered = {}
8
21
  end
9
22
 
10
23
  def create_adapter(name, spec)
@@ -13,13 +26,7 @@ module NinjaModel
13
26
 
14
27
  def release_active_adapters!
15
28
  @adapter_pools.each_value do |pool|
16
- pool.release_adapter
17
- end
18
- end
19
-
20
- def release_reloadable_adapters!
21
- @adapter_pools.each_value do |pool|
22
- pool.shutdown_reloadable_adapters!
29
+ pool.release_instance
23
30
  end
24
31
  end
25
32
 
@@ -31,7 +38,7 @@ module NinjaModel
31
38
 
32
39
  def retrieve_adapter(klass)
33
40
  pool = retrieve_adapter_pool(klass)
34
- (pool && pool.instance) or raise StandardError
41
+ (pool && pool.instance) or raise StandardError, "Pool is empty or instance is null"
35
42
  end
36
43
 
37
44
  def remove_adapter(klass)
@@ -58,8 +65,8 @@ module NinjaModel
58
65
  def call(env)
59
66
  @app.call(env)
60
67
  ensure
61
- unless env.key?('rake.test')
62
- NinjaModel::Base.clear_active_instances!
68
+ unless env.key?('rack.test')
69
+ NinjaModel::Base.adapter_manager.release_active_adapters!
63
70
  end
64
71
  end
65
72
  end
@@ -1,4 +1,5 @@
1
1
  module NinjaModel
2
+ class ConnectionTimeoutError < NinjaModelError; end
2
3
  module Adapters
3
4
  class AdapterPool
4
5
  attr_reader :spec, :instances
@@ -13,6 +14,10 @@ module NinjaModel
13
14
  @timeout = 3
14
15
  end
15
16
 
17
+ def connected?
18
+ !@instances.empty?
19
+ end
20
+
16
21
  def instance
17
22
  NinjaModel.logger.debug("instance called for #{current_instance_id}")
18
23
  @assigned_instances[current_instance_id] ||= checkout
@@ -31,8 +36,15 @@ module NinjaModel
31
36
  release_instance(instance_id) if fresh_instance
32
37
  end
33
38
 
34
- def connected?
35
- !@instances.empty?
39
+ def shutdown!
40
+ @assigned_instances.each do |name,conn|
41
+ checkin conn
42
+ end
43
+ @assigned_instances = {}
44
+ @instances.each do |inst|
45
+ inst.disconnect!
46
+ end
47
+ @instances = []
36
48
  end
37
49
 
38
50
  private
@@ -86,7 +98,7 @@ module NinjaModel
86
98
  end
87
99
 
88
100
  def new_instance
89
- NinjaModel::Base.send(spec.adapter_method, spec.config)
101
+ AdapterManager.registered[spec.name.to_sym].new(spec.config)
90
102
  end
91
103
 
92
104
  def current_instance_id
@@ -110,19 +122,5 @@ module NinjaModel
110
122
  inst
111
123
  end
112
124
  end
113
-
114
- class AdapterManagement
115
- def initialize(app)
116
- @app = app
117
- end
118
-
119
- def call(env)
120
- @app.call(env)
121
- ensure
122
- unless env.key?('rask.test')
123
- NinjaModel::Base.clear_active_instances!
124
- end
125
- end
126
- end
127
125
  end
128
126
  end
@@ -1,10 +1,10 @@
1
1
  module NinjaModel
2
2
  module Adapters
3
3
  class AdapterSpecification
4
- attr_accessor :config, :adapter_method
4
+ attr_reader :config, :name
5
5
 
6
- def initialize(config, adapter_method)
7
- @config, @adapter_method = config, adapter_method
6
+ def initialize(config, name)
7
+ @config, @name = config, name
8
8
  end
9
9
  end
10
10
  end
@@ -1,107 +1,27 @@
1
- require 'active_support/concern'
2
- require 'ninja_model/associations/active_record_proxy'
3
- require 'ninja_model/associations/ninja_model_proxy'
4
-
5
- module ActiveRecord
6
- module Associations
7
- module ClassMethods
8
- alias :has_one_without_ninja_model :has_one
9
- def has_one(association_id, options = {})
10
- if ninja_model?(:has_one, options[:class_name] || association_id)
11
- ninja_proxy.handle_association(:has_one, association_id, options)
12
- else
13
- has_one_without_ninja_model(association_id, options)
14
- end
15
- end
16
-
17
- def ninja_proxy
18
- read_inheritable_attribute(:ninja_proxy) || write_inheritable_attribute(:ninja_proxy, NinjaModel::Associations::NinjaModelProxy.new(self))
19
- end
20
-
21
- private
22
-
23
- def ninja_model?(macro, association)
24
- klass = association.to_s.camelize
25
- klass = klass.singularize unless [:has_one, :belongs_to].include?(macro)
26
- klass = klass.constantize
27
- klass.ancestors.include?(NinjaModel::Base)
28
- end
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
-
44
- module Reflection
45
- module ClassMethods
46
- alias :reflect_on_association_without_ninja_model :reflect_on_association
47
- def reflect_on_association(association)
48
- if read_inheritable_attribute(:ninja_proxy) && ninja_proxy.proxy_klass.reflections.include?(association)
49
- ninja_proxy.proxy_klass.reflect_on_association(association)
50
- else
51
- reflect_on_association_without_ninja_model(association)
52
- end
53
- end
54
- end
55
- end
56
- end
57
-
58
1
  module NinjaModel
59
- module Associations
60
- extend ActiveSupport::Concern
61
-
62
- autoload :AssociationProxy, 'ninja_model/associations/association_proxy'
63
- autoload :HasOneAssociation, 'ninja_model/associations/has_one_association'
64
- autoload :HasManyAssociation, 'ninja_model/associations/has_many_association'
65
- autoload :BelongsToAssociation, 'ninja_model/associations/belongs_to_association'
66
2
 
67
-
68
- module ClassMethods
3
+ class Base
4
+ class << self
69
5
  def has_one(association_id, options = {})
70
- if ninja_model?(:has_one, options[:class_name] || association_id)
71
- reflection = create_has_one_reflection(association_id, options)
72
- association_accessor_methods(reflection, HasOneAssociation)
73
- #association_constructor_method(:build, reflection, HasOneAssociation)
74
- #association_constructor_method(:create, reflection, HasOneAssociation)
75
- #configure_dependency_for_has_one(reflection)
76
- else
77
- #puts "Setting up has_one proxy for #{association_id}"
78
- proxy.handle_association(:has_one, association_id, options)
79
- end
6
+ reflection = create_has_one_reflection(association_id, options)
7
+ association_accessor_methods(reflection, Associations::HasOneAssociation)
8
+ # TODO: Implement the build/create association methods
9
+ #association_constructor_method(:build, reflection, HasOneAssociation)
10
+ #association_constructor_method(:create, reflection, HasOneAssociation)
11
+ #configure_dependency_for_has_one(reflection)
80
12
  end
81
13
 
82
14
  def belongs_to(association_id, options = {})
83
- if ninja_model?(:belongs_to, options[:class_name] || association_id)
84
- reflection = create_belongs_to_reflection(association_id, options)
85
- association_accessor_methods(reflection, BelongsToAssociation)
86
- #association_constructor_method(:build, reflection, BelongsToAssociation)
87
- #association_constructor_method(:create, reflection, BelongsToAssociation)
88
- else
89
- proxy.handle_association(:belongs_to, association_id, options)
90
- end
15
+ reflection = create_belongs_to_reflection(association_id, options)
16
+ association_accessor_methods(reflection, Associations::BelongsToAssociation)
17
+ # TODO: Implement the build/create association methods
18
+ #association_constructor_method(:build, reflection, BelongsToAssociation)
19
+ #association_constructor_method(:create, reflection, BelongsToAssociation)
91
20
  end
92
21
 
93
22
  def has_many(association_id, options = {})
94
- if ninja_model?(:has_many, association_id)
95
- reflection = create_has_many_reflection(association_id, options)
96
- collection_accessor_methods(reflection, HasManyAssociation)
97
- #collection_accessor_methods(reflection, HasManyAssociation)
98
- else
99
- proxy.handle_association(:has_many, association_id, options)
100
- end
101
- end
102
-
103
- def proxy
104
- read_inheritable_attribute(:proxy) || write_inheritable_attribute(:proxy, ActiveRecordProxy.new(self))
23
+ reflection = create_has_many_reflection(association_id, options)
24
+ collection_accessor_methods(reflection, Associations::HasManyAssociation)
105
25
  end
106
26
 
107
27
  private
@@ -112,7 +32,6 @@ module NinjaModel
112
32
 
113
33
  def create_has_many_reflection(association, options = {})
114
34
  create_reflection(:has_many, association, options, self)
115
- #options[:extend] = create_extension_modules(association, extension
116
35
  end
117
36
 
118
37
  def create_belongs_to_reflection(association, options = {})
@@ -126,7 +45,7 @@ module NinjaModel
126
45
  if association.nil?
127
46
  association = association_proxy_class.new(self, reflection)
128
47
  retval = association.reload
129
- if retval.nil? and association_proxy_class == BelongsToAssociation
48
+ if retval.nil? and association_proxy_class == Associations::BelongsToAssociation
130
49
  association_instance_set(reflection.name, nil)
131
50
  return nil
132
51
  end
@@ -151,7 +70,7 @@ module NinjaModel
151
70
  end
152
71
 
153
72
  redefine_method("set_#{reflection.name}_target") do |target|
154
- return if target.nil? and association_proxy_class == BelongsToAssociation
73
+ return if target.nil? and association_proxy_class == Associations::BelongsToAssociation
155
74
  association = association_proxy_class.new(self, reflection)
156
75
  association.target = target
157
76
  association_instance_set(reflection.name, association)
@@ -174,6 +93,14 @@ module NinjaModel
174
93
  end
175
94
  end
176
95
  end
96
+ end
97
+
98
+ module Associations
99
+
100
+ autoload :AssociationProxy, 'ninja_model/associations/association_proxy'
101
+ autoload :HasOneAssociation, 'ninja_model/associations/has_one_association'
102
+ autoload :HasManyAssociation, 'ninja_model/associations/has_many_association'
103
+ autoload :BelongsToAssociation, 'ninja_model/associations/belongs_to_association'
177
104
 
178
105
  def association_instance_get(name)
179
106
  ivar = "@#{name}"
@@ -186,13 +113,5 @@ module NinjaModel
186
113
  def association_instance_set(name, association)
187
114
  instance_variable_set("@#{name}", association)
188
115
  end
189
-
190
- def method_missing(method, *args)
191
- if self.class.read_inheritable_attribute(:proxy) && proxy.respond_to?(method)
192
- proxy.send(method, *args)
193
- else
194
- super
195
- end
196
- end
197
116
  end
198
117
  end