Crystal: abstract static method - crystal-lang

Is it possible to define abstract static methods?
I'm trying:
abstract struct MyStruct
abstract def self.myfun # ERR
abstract def MyStruct::myfun # ERR
end

I faced the same problem and figured out a (in my opinion) nicer solution:
abstract class Something
module ClassMethods
abstract def some_abstract_class_method
end
extend ClassMethods
abstract def some_abstract_instance_method
end
The documentation mentions that module methods can be made abstract as well, so this builds on top of that.
Implementing this class without implementing the class method some_abstract_class_method will raise an error, as expected.

Abstract class methods don't appear to be a language feature:
abstract class Abstract
abstract self.doit
end
# => Syntax error in /home/bmiller/test.cr:23: unexpected token: self
However you could always delegate to an instance:
abstract class Parent
def self.instance
##instance ||= new
end
def self.doit
instance.doit
end
abstract def doit
end
class Child < Parent
def doit
"ok"
end
end
p Parent.doit # => can't instantiate abstract class Parent
p Child.doit # => "ok"

Related

Correct way to replace Django Model class with an equivalent+decorated subclass

I'm writing a decorator intended to add functionality to decorated Django Model classes. Something like this:
class NewFunctionality:
#classmethod
def fun1(cls):
...
#property
def prop1(self):
...
def add_functionality(Decorated):
class NewClass(Decorated, NewFunctionality):
class Meta(getattr(Decorated, 'Meta', object)):
app_label = Decorated._meta.app_label
NewClass.__name__ = Decorated.__name__
NewClass.__doc__ = Decorated.__doc__
return NewClass
#add_functionality
class MyModel(models.Model):
...
This seems to work until there are two decorated model classes, when I get an error Conflicting 'modelclass' models in application 'my_app'.
This is apparently due to the registry of models that Django keeps, which clearly has some automagic that doesn't appreciate new model classes being made, even if they are direct replacements of the existing one.
Is there anything I can do to accomplish this, other than by monkeypatching the decorated class, adding each needed method?
Edit
I've avoided the error by making the wrapper class into a proxy class of the decorated class:
def add_functionality(Decorated):
class NewClass(Decorated, NewFunctionality):
class Meta(getattr(Decorated, 'Meta', object)):
app_label = Decorated._meta.app_label
proxy = True
NewClass.__name__ = Decorated.__name__
NewClass.__doc__ = Decorated.__doc__
return NewClass
I also replace the use of the class keyword, using builtins.type, as in:
def add_functionality(Decorated):
return type(
Decorated.__name__,
(NewFunctionality, Decorated,),
{
'Meta': type('Meta', (object,), {
'app_label': Decorated._meta.app_label,
'proxy': True,
'__module__': Decorated.__module__,
}
)
I really like this as it seemingly completely replaces the decorated class. Now, however, I'm getting the following warning from Django:
.venv/lib/python3.9/site-packages/django/db/models/base.py:321
/home/tyler/orm-cache/django-ormsgpack/.venv/lib/python3.9/site-packages/django/db/models/base.py:321: RuntimeWarning: Model 'my_app.atestmodel' was already registered. Reloading models is not advised as it can lead to inconsistencies, most notably with related models.
new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
If anyone can shed light onto how I might utilize the Django api to properly overwrite the registered model, I'd love to hear it!
thanks

Django model - interface design to avoid need of passing object in CHILD class calling method defined in PARENT class

I am using django 2.0.8 and Python 3.5. I have written a base class which encapsulates behavior in a base class.
When using the interface in the child class, I find that I have to pass the object of the child class to the parent - which is not only ugly, is error prone.
I do not want to use composition (instead of an interface), because AFAIK fields in django models are saved to the DB - that aside, I prefer the sub classing approach, since all the functionality can remain in the base class.
Is there any way I can (in the parent class), find/obtain the instance (or at least the name of the class and it's id) that invoked the method call?
Here is my code:
class Likeable(models.Model):
likes = GenericRelation(Like)
def action_is_permissible(self, actionable_object, actor):
ct = ContentType.objects.get_for_model(actionable_object)
object_id = actionable_object.id
found_objects = Like.objects.filter(content_type=ct, object_id=object_id, liker=actor)
return ((len(found_objects) == 0), ct, object_id, found_objects)
def add_like(self, actionable_object, actor):
can_add, ct, object_id, found_objects = self.action_is_permissible(actionable_object, actor)
if can_add:
like = self.likes.create(content_type=ct, object_id=object_id, liker=actor)
else:
# do nothing
return
class Meta:
abstract = True
class Foo(Likeable):
name = models.CharField(max_length=255,default='')
objects = models.Manager()
Example use (imports omitted)
foo = Foo.objects.get(id=1)
p = User.objects.get(id=1)
foo.add_like(foo, p) # <- nasty API calling convention
You can access it using self.
self refers to the object which is calling.
Ref: What is the purpose of self?
EDIT (code changes):
class Likeable(models.Model):
def add_like(self, actor):
# update `actionable_object` to `self`
foo.add_like(p)

Calling a method from a class method in ApplicationRecord

I'm having a strange issue
I have the implementation below:
In a controller
Event.search(search_params)
class Event < ApplicationRecord
def self.search(params)
find_events(params)
end
private
def find_events(params)
events = Event.upcoming
events = events.where("name like ?", "%#{params['name']}%")
events
end
end
When executed I get this error:
NoMethodError (undefined method `find_events' for #<Class:0x007fadcd00a690>)
What is wrong with my code?
You have to declare the class method with
def self.find_events
You cannot call an instance method from a class method without an instance object attached to that method.

Get the AbstractClass of a model

how could i get the AbstractClass of a Model in Django?
I tried to do it with type but type gives me the BaseModel class of django or the type of the model itself.
def go_for_the_bases(model):
while hasattr(model, '_meta'):
model = model.__base__
if hasattr(model, '_meta') and model._meta.abstract == True:
yield model
You can user mro() which stands for Method Resolution Order.
ClassName.mro()
which gives the tuple of the class, its base, its base's base, ...., and so on till we reach object.
You can loop over it and check for className._meta.abstract is True till you reach the abstract class.

How to make a str var callable

What i want is to make a string var callable. I just have a list with different models_names and i want to call their create methods like this way.
class Object_model_a:
#def ...
class Object_model_b:
#def ...
class Object_model_c:
#def ...
list = ('Object_model_a', 'Object_model_b', 'Object_model_c')
x = list[0]() # this must create a new instance of Object_model_a
This is possible to develop using php like this way:
$hi = 'Hello'
$Hello = 'Hi!!'
echo $$hi
>> Hi!!
Anyone knows if this is possible using django?? This will simplify a lot my code.
Thanks a lot!
You could use Django's get_model helper function, which takes the app name and model name and returns the model class.
from django.db.models import get_model
list = ('Object_model_a', 'Object_model_b', 'Object_model_c')
model = get_model('my_app_name', list[0]) # returns Object_model_a class
instance = model() # creates a model instance
If for whatever reason you have a string that represents a particular class, the correct way to use that to instantiate an object of that class is to place your classes in a dict, keyed by the strings, then just invoke the class.
classes = dict((c.__name__, c) for c in (Object_model_a, Object_model_b, Object_model_c))
instance = classes['Object_model_a']()
Obviously, you don't need to use the classname as the key.
Thanks for all your comments, this is the way i've solved this requirement.
def create_object_instance(model_name, id=None):
for model in get_models():
if str(model.__name__).lower() == str(model_name).lower():
if id:
try:
return model.objects.get(id=id)
except ObjectsDoesNotExist:
return None
else:
return model.objects.all()
return None