I have a class that is defined in the module.
module Mod
class Zed
include DataMapper::Resource
end
end
For testing, I define factory.
#/factories/zed.rb
FactoryGirl.define do
factory :zed do
#code
end
end
But when I start testing I get an error.
describe 'Zed' do
it "should have ..." do
FactoryGirl.create(:zed)
end
end
Error:
Failure/Error: FactoryGirl.create(:zed)
NameError:
uninitialized constant Zed
How to test a class that is included in the module?
Thanks.
You should specify class when defining a factory like this:
FactoryGirl.define do
factory :zed, class: Mod::Zed do
#code
end
end
Related
I have the following tests, written using RSpec
spec/services/aquatic/factory_spec.rb
describe Hobby::Aquatic::Factory do
let(:factory) { Hobby::Aquatic::Factory.instance }
describe "singleton" do
it "should be the same object" do
Hobby::Aquatic::Factory.instance.should be factory
end
it "raise error if given junk" do
expect {factory.hobby("junk")}.to raise_error
end
end
end
spec/services/aquatic/hobbies_spec.rb
describe Hobby::Aquatic do
it "creates fishing" do
expect { Hobby::Aquatic::Fishing.new }.to_not raise_error
end
end
and have defined the following module / classes
app/services/aquatic/factory.rb
require 'singleton'
module Hobby
module Aquatic
class Factory
include Singleton
def self.instance
##instance ||= new
end
def hobby(name)
return Fishing.new if name == "fishing"
return Surfing.new if name == "surfing"
raise ArgumentError, "Unknown hobby for supplied name"
end
end
end
end
app/services/aquatic/hobbies.rb
module Hobby
module Aquatic
class Fishing
end
class Surfing
end
end
end
When I run the tests the Factory tests all pass fine, but the test of the Hobby::Aquatic::Fishing object results in:
Failure/Error: expect { Hobby::Aquatic::Fishing.new }.to_not raise_error
expected no Exception, got #<NameError: uninitialized constant Hobby::Aquatic::Fishing> …
What have I done wrong?
add require_relative 'hobbies' below require 'singleton' to fix this.
I am not sure why Rails is loading the factory but not the hobbies automagically but this works.
I'm learning the object model of Ruby. I've written this script:
#/usr/bin/ruby
module MyModule
class MyBase
def class_b_method
puts "class_b_method called"
end
end
class MyClass < MyBase
attr_accessor :name
class_b_method
def set_name(name)
#name = "My name is #{name}"
end
def display_name
return #name
end
end
end
obj = MyModule::MyClass.new
obj.set_name "Martin"
puts obj.display_name
Running the code above I get this error:
module.rb:13: undefined local variable or method `class_b_method' for MyModule::MyClass:Class (NameError)
I'm trying to call the parent method within the class MyClass. What I'm doing wrong?
Inside class MyClass,self is MyClass.But you define class_b_method as an instance method inside class MyBase,i.e. method which can be called by the instances of the class MyBase,can't be invoked by the class itself. so self.class_b_method throws an legitimate error.To make your code workable write the method as below:
class MyBase
def self.class_b_method
puts "class_b_method called"
end
end
I am trying to create an accessor for a class instance variable. I am calling the attr_accessor method from a module which is included in the class. See the code below:
module Persistence
def self.included(mod)
mod.extend ClassMethods
# Add accessor for class instance variable
class << mod
attr_accessor :persistent_data
end
end
module ClassMethods
def X
persistent_data = 'data'
end
end
end
The above code works. However when I change the code which calls attr_accessor, to this:
mod.instance_eval do
attr_accessor :persistent_data
end
I get NoMethodError: undefined method `persistent_data='
Shouldn't both ways work the same or is my understanding wrong here? I am using REE 1.8.7
module Test
def self.model_method
puts "this is a module method"
end
end
class A
include Test
end
A.model_method
this will be error with:
undefined method `model_method' for A:Class (NoMethodError)
But when I use metaclass of A. it works:
module Test
def model_method
puts "this is a module method"
end
end
class A
class << self
include Test
end
end
A.model_method
Can someone explain this?
If you want to have both class methods and instance methods mixed into a class when including a module, you may follow the pattern:
module YourModule
module ClassMethods
def a_class_method
puts "I'm a class method"
end
end
def an_instance_method
puts "I'm an instance method"
end
def self.included(base)
base.extend ClassMethods
end
end
class Whatever
include YourModule
end
Whatever.a_class_method
# => I'm a class method
Whatever.new.an_instance_method
# => I'm an instance method
Basically to over-simplify it, you extend to add class methods and you include to add instance methods. When a module is included, it's #included method is invoked, with the actual class it was included in. From here you can extend the class with some class methods from another module. This is quite a common pattern.
See also: http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
Including a module is analogous to copying its instance methods over.
In your example, there are no instance methods to copy to A. model_method is actually an instance method of Test's singleton class.
Given:
module A
def method
end
end
This:
module B
include A
end
Is analogous to this:
module B
def method
end
end
When you think of it this way, this makes perfect sense:
module B
class << self
include A
end
end
B.method
Here, the methods are being copied to the B module's singleton class, which makes them the "class methods" of B.
Note that this is exactly the same thing as:
module B
extend A
end
In reality, the methods are not being copied; there is no duplication. The module is simply included in the method lookup list.
class Product < ActiveRecord::Base
set_table_name 'produce'
end
module ActiveRecord
class Base
def self.set_table_name name
define_attr_method :table_name, name
end
def self.define_attr_method(name, value)
singleton_class.send :alias_method, "original_#{name}", name
singleton_class.class_eval do
define_method(name) do
value
end
end
end
end
I'd like to understand how set_table_name becomes defined in this example.
Why is singleton_class.send needed here?
And why is class_eval called on singleton_class instead of on self?
The reason for using "singleton_class" is because you do not want to modify the ActiveRecord::Base class, but the Product class.
More info about metaptogramming and singleton class here: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html