diff --git a/lib/her/model/orm.rb b/lib/her/model/orm.rb index fa91b2df..2db1d7a6 100644 --- a/lib/her/model/orm.rb +++ b/lib/her/model/orm.rb @@ -85,6 +85,20 @@ def destroy end module ClassMethods + @@relation_class = Relation + # get the default Relation class + # @ note if unspecified, will return {Her::Model::Relation} + # @private + def relation_class + @@relation_class + end + # set the default Relation class + # @note a custom relation class should inherit or behave like + # {Her::Model::Relation} + def use_relation(klass) + @@relation_class = klass + end + # Create a new chainable scope # # @example @@ -104,7 +118,7 @@ def scope(name, code) end # Add the scope method to the Relation class - Relation.instance_eval do + relation_class.instance_eval do define_method(name) { |*args| instance_exec(*args, &code) } end end @@ -197,7 +211,7 @@ def build(attributes = {}) private # @private def blank_relation - @blank_relation ||= Relation.new(self) + @blank_relation ||= relation_class.new(self) end end end diff --git a/spec/model/orm_spec.rb b/spec/model/orm_spec.rb index 5bf523a9..8b85fe0a 100644 --- a/spec/model/orm_spec.rb +++ b/spec/model/orm_spec.rb @@ -443,7 +443,7 @@ def friends context 'for children class' do before do class User < Foo::User; end - @spawned_models << :User + @spawned_classes << :User end it 'uses the custom method (PUT) instead of default method (POST)' do @@ -476,4 +476,47 @@ class User < Foo::User; end end end end + + context 'without custom relation' do + before do + spawn_model 'User' + #Her::Model::Relation.any_instance.stub(:fetch).and_return(:correct_relation_called) + end + + describe '.relation_class' do + it 'should default to Her::Model::Relation' do + User.relation_class.should == Her::Model::Relation + end + end + + describe 'scope and relation calls' do + it 'should use the default relation' do + User.scoped.class.should == Her::Model::Relation + end + end + + end + + context 'with custom relation' do + before do + spawn_relation 'CustomRelation' + spawn_model 'User' do + use_relation CustomRelation + end + end + + describe '.relation_class' do + it 'should be the custom relation' do + User.relation_class.should == CustomRelation + end + end + + describe 'scope and relation calls' do + it 'should use the custom relation' do + User.scoped.class.should == CustomRelation + end + end + + end + end diff --git a/spec/model/parse_spec.rb b/spec/model/parse_spec.rb index 4ef1bc32..90d72214 100644 --- a/spec/model/parse_spec.rb +++ b/spec/model/parse_spec.rb @@ -54,7 +54,7 @@ spawn_model("Foo::Model") { include_root_in_json true } class User < Foo::Model; end - @spawned_models << :User + @spawned_classes << :User end it "wraps params with the class name" do @@ -143,7 +143,7 @@ class User < Foo::Model collection_path "/users" end - @spawned_models << :User + @spawned_classes << :User end it "parse the data with the symbol" do diff --git a/spec/model/paths_spec.rb b/spec/model/paths_spec.rb index a1a08d16..6db1427f 100644 --- a/spec/model/paths_spec.rb +++ b/spec/model/paths_spec.rb @@ -138,7 +138,7 @@ spawn_model("Foo::Model") { include_root_in_json true } class User < Foo::Model; end - @spawned_models << :User + @spawned_classes << :User end it "builds path using the children model name" do diff --git a/spec/model/relation_spec.rb b/spec/model/relation_spec.rb index 4c166700..82bc89d1 100644 --- a/spec/model/relation_spec.rb +++ b/spec/model/relation_spec.rb @@ -67,7 +67,7 @@ end class User < Foo::Model; end - @spawned_models << :User + @spawned_classes << :User end it "propagates the scopes through its children" do diff --git a/spec/model/validations_spec.rb b/spec/model/validations_spec.rb index 6e7c7ce0..3c0d0988 100644 --- a/spec/model/validations_spec.rb +++ b/spec/model/validations_spec.rb @@ -31,7 +31,7 @@ def errors end class User < Foo::Model; end - @spawned_models << :User + @spawned_classes << :User end it "validates attributes when calling #valid?" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 415caf11..e2add542 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,15 +12,16 @@ RSpec.configure do |config| config.include Her::Testing::Macros::ModelMacros + config.include Her::Testing::Macros::RelationMacros config.include Her::Testing::Macros::RequestMacros config.before :each do - @spawned_models = [] + @spawned_classes = [] end config.after :each do - @spawned_models.each do |model| - Object.instance_eval { remove_const model } if Object.const_defined?(model) + @spawned_classes.each do |klass| + Object.instance_eval { remove_const klass } if Object.const_defined?(klass) end end end diff --git a/spec/support/macros/model_macros.rb b/spec/support/macros/model_macros.rb index 58b884f2..28197140 100644 --- a/spec/support/macros/model_macros.rb +++ b/spec/support/macros/model_macros.rb @@ -14,13 +14,13 @@ def spawn_model(klass, &block) submodel.class_eval(&block) if block_given? end - @spawned_models << base + @spawned_classes << base else Object.instance_eval { remove_const klass } if Object.const_defined?(klass) Object.const_set(klass, Class.new).send(:include, Her::Model) Object.const_get(klass).class_eval(&block) if block_given? - @spawned_models << klass.to_sym + @spawned_classes << klass.to_sym end end end diff --git a/spec/support/macros/relation_macros.rb b/spec/support/macros/relation_macros.rb new file mode 100644 index 00000000..4b9ec924 --- /dev/null +++ b/spec/support/macros/relation_macros.rb @@ -0,0 +1,28 @@ +module Her + module Testing + module Macros + module RelationMacros + # Create a class and automatically inherit Her::Model::Relation + def spawn_relation(klass, &block) + if klass =~ /::/ + base, submodel = klass.split(/::/).map{ |s| s.to_sym } + Object.const_set(base, Module.new) unless Object.const_defined?(base) + Object.const_get(base).module_eval do + remove_const submodel if constants.map(&:to_sym).include?(submodel) + submodel = const_set(submodel, Class.new(Her::Model::Relation)) + submodel.class_eval(&block) if block_given? + end + + @spawned_classes << base + else + Object.instance_eval { remove_const klass } if Object.const_defined?(klass) + Object.const_set(klass, Class.new(Her::Model::Relation)) + Object.const_get(klass).class_eval(&block) if block_given? + + @spawned_classes << klass.to_sym + end + end + end + end + end +end