Hi I have to access a method from a module in a resuq job, I keep getting this error: method not accessible. Am I using the module incorrectly??
class TestResqueJob
include TestModule
#queue = :test_resque
def self.perform(params)
method_from_module
end
end
module TestModule
def method_from_module
puts "test"
end
end
It seems that you are trying to call an instance method inside a public method. I f you want your module methods to be class methods change include to extend
class TestResqueJob
extend TestModule
#queue = :test_resque
def self.perform(params)
method_from_module
end
end
this will make all the methods you have defined in the module as class methods
Related
I asked a more limited version of this question at In Crystal, what's the difference between inheritance and inclusion?, but I think I (and other readers) would benefit from a more comprehensive answer.
What are the differences between inheritance (with <), inclusion (with include), and extension (with extend) in Crystal classes?
Answer
Class inheritance
Inheritance with < duplicates instance attributes, instance methods, class attributes, and class methods from the inherited class into the current class.
Modules cannot inherit or be inherited.
class A
# Equivalent to `##foo = 1` with corresponding getter and setter class methods
##foo = 1
# Equivalent to `#foo = ` with corresponding getter and setter instance methods
#foo = 2
end
class B < A
end
pp A.foo == B.foo # true
pp A.new.foo == B.new.foo # true
The value of a class attribute in the superclass is not the same as the value in the subclass, but the types will be the same.
class C
class_property foo = 1
end
class D < C
end
D.foo = 9
pp C.foo == D.foo # false
A class can inherit from exactly one class.
Module inclusion
include duplicates instance attributes and instance methods from the included module into the current class or module.
Classes cannot be included.
It is possible to define class attributes and class methods on modules, but these are not duplicated by inclusion; they are ignored.
module BirdHolder
# Ignored by `include`
class_property bird = "123"
property bird = "456"
end
class Thing
include BirdHolder
end
pp Thing.new.bird # "456"
pp Thing.bird # Error: undefined method 'bird' for Thing1.class
A type (module or class) can include any number of modules.
Module extension
extend duplicates instance methods from the included module into the current class or module, but as class methods.
Classes cannot be extended.
Class attributes and class methods from the extended module are ignored.
module Talkative
# Ignored by `extend`
##stuff = "zxcv"
# Ignored by `extend`
def self.say_stuff
puts "stuff"
end
def say_stuff
puts ##stuff
end
end
class Thing
extend Talkative
##stuff = "asdf"
end
Thing.say_stuff # "asdf"
Note that ##stuff in the definition of the Talkative module refers to the class attribute of the extending class, not to the class attribute of Talkative itself.
It is not possible to extend a module that defines instance methods. This results in a compilation error.
A type (module or class) can extend exactly one module.
References
This information is based on:
Crystal Reference: Classes and Methods
Crystal Reference: Modules
Answer to my previous question by Johannes Müller
Assistance from users in the crystal-lang/crystal Gitter chatroom.
This answer is valid as of Crystal 1.0.0
In one of my test case the flow requires that a customer provision process wherein the call goes to the api.py file where in the response is saved from the function create_t_customer like following:
In api.py file it is using the method create_t_customer imported from file customer.py
response = create_t_customer(**data)
In customer.py file the code for function is
def create_t_customer(**kwargs):
t_customer_response = Customer().create(**kwargs)
return t_customer_response
I want to mock the function create_t_customer inside the unittest.
Current I have tried the following but it doesn't seem to be working
class CustomerTest(APITestCase):
#mock.patch("apps.dine.customer.create_t_customer")
def setUp(self,mock_customer_id):
mock_customer_id.return_value = {"customer":1}
But this is not able to mock the function.
You should mock it inside the file it is imported. For example you have declared create_t_customer in customer.py and using it in api.py. You should mock it from api instead of customer module like this.
class CustomerTest(APITestCase):
#mock.patch("x.y.api.create_t_customer")
def test_xyz(self, mock_customer_id):
mock_customer_id.return_value = {"customer":1}
This is a an example of the code:
module1.py is imported in the main.
In modul1.py, there is an init() function that creates classes from a previous imported library, and then, other functions uses this instance of the class, and the methods of that class.
ERROR: global name name1 not defined
module1.py:
from lib import class1, classs2
def init():
name1.class1()
def function():
name1.class1method1()
main.py:
import module1
init()
function()
I need some help, thanks
I think you may be getting confused between creating an object from a class definition and accessing the methods of the class. You are getting a not defined error because you have yet to define name1.
With the following adjustments, your code would work:
module1.py:
from lib import class1, classs2
def Init():
global name1
name1 = class1()
def function():
name1.class1method1()
main.py:
import module1
module1.Init()
module1.function()
That being said global variables are a bad idea, so the above code is for demonstration purposes only, not for actual use.
I am having trouble with Ruby class (constant) lookup within the context of a Rails engine gem.
I have a gem MyGem that is a Rails engine. It defines non-namespaced models that are expected to be overridden by the MainApp that would include the gem and namespaced modules, which are included in gem's and main_app's models to have a DRY way of defining reusable code.
Here is a sample code structure:
Two models
# in /app/models/user.rb
class User < ActiveRecord::Base
include MyGem::User::CommonExt
end
# in /app/models/comment.rb
class Comment < ActiveRecord::Base
include MyGem::Comment::CommonExt
end
Their two modules
# in /app/models/concerns/my_gem/user/common_ext.rb
module MyGem::User::CommonExt
def load_comment(id)
return Comment.find(id)
end
end
# in /app/models/concerns/my_gem/comment/common_ext.rb
module MyGem::Comment::CommonExt
def load_user(id)
return User.find(id)
end
end
Now, if I call
User.new.load_comment(1)
I get undefined method #find for MyGem::Comment::Module
I think I understand why this is happening - in the context of #load_comment definition, which is namespaced under MyGem, Comment constant lookup returns MyGem::Comment, rather than the more distant ::Comment
I would prefer not to have to prepend every model instance with ::.
Is there a file structure, model/class definition or configuration change I could use to make a call to Comment return the model Comment, not the MyGem::Comment module?
I would use inheritance instead of mixin in this case.
So in your gem/engine you could define your common class similar to this:
module MyGem
module Common
class Base < ActiveRecord::Base
# common functionality goes here
def load(record_type, id)
record_type.find(id)
end
end
end
end
Then in your main_app code:
class User < MyGem::Common::Base
...
end
Now you could do this:
User.new.load(Comment, 1)
This violates the Law of Demeter but hopefully it illustrates the point.
Doing it like this is DRY and has the added benefit that it prevents your gem from having to know about classes which are outside it's own scope.
I'm looking to chain an additional query onto a scope in a model. The scope is defined in a concern.
module Companyable
extend ActiveSupport::Concern
included do
scope :for_company, ->(id) {
where(:company_id => id)
}
end
end
class Order < ActiveRecord::Base
include Companyable
# I'd like to be able to do something like this:
scope :for_company, ->(id) {
super(id).where.not(:status => 'cancelled')
}
end
However, that understandably throws a NameError: undefined method 'for_company' for class 'Order'
Here's the solution I came up with in my case:
Rather than scope, just go with a regular class method since scope is just "syntactic sugar" for a class method. This is easier to deal with when you need to override using super. In your case it would look like this:
module Companyable
extend ActiveSupport::Concern
module ClassMethods
def for_company(id)
where(:company_id => id)
end
end
end
class Order < ActiveRecord::Base
include Companyable
def self.for_company(id)
super(id).where.not(:status => 'cancelled')
end
end