i have a method in the first class
class1
def method(param_test)
if !organization.empty?
organization = test(param_test)
end
end
end
Class 2 inherits from Class 1
class2 < class1
end
I would like to modify the line organization = test(param_test)
without having to copy the whole method in the class2
it's possible?
I would separate the logic into two methods like this:
# in the parent class
def method(param_test)
if !organization.empty?
organization = fallback(param_test)
end
end
def fallback(param)
test(param)
end
And then just override the one method in the child class like this:
# in the child class
def fallback(param)
# logic to return the expected response
end
An alternative might be to change the test method in the subclass. But how that might look like depends on the specific use case and the internals of the test method.
Related
What is the correct structure to be able to call a class from another class?
I can call MyObject.new by using MyModule::MyClass::MyObject.new()
However, I would prefer to call it using:
MyModule::MyClass.myobject.new()
How do I structure my code to by able to do this?
module MyModule
class MyClass
class MyObject
def initialize(value)
#value = value
end
def method1
"This is a #{value}"
end
end
end
end
You need to define a method myobject on MyClass which returns MyObject...
module MyModule
class MyClass
class MyObject
end
def self.myobject; return MyObject; end
end
end
If I understand you correctly, you have a variable of some class and want to create a new object of the same class. Assuming that your classes all have an empty constructor, you could do a
myobject.class.new()
If you want to also have the new object the same internal state as the other one, write a method
class MyMethod
def clone
...
end
end
which performs this task.
The Answers here are right, but don't do this it's not standard and will be confusing for anyone who reads your code.
MyModule::MyClass.my_object_instance
class MyClass
def self.my_object_instance
MyObject.new
end
end
this could be better to create a factory method that returns a new instance of the class if want a shorter way to create an instance of the class.
I have a model directory structure like this:
/alerts
base_alert.rb
panic_alert.rb
hardware_alert.rb
alert.rb
With the /alerts/x_alert.rb models setup like this:
class base_alert < ActiveRecord::Base
...
end
class panic_alert < base_alert
...
end
class hardware_alert < base_alert
...
end
etc.
Is there any way to call create on alert.rb in the top directory, and, based on a parameter passed, it would create one of the children instead of alert.rb.
I.E. Alert.create({type:"panic_alert"})
And it would create and return one of the panic_alert types of alerts?
By making few changes to the class definitions, like subclassing the Alert from ActiveRecord::Base rather than BaseAlert, you could achieve what you are trying to accomplish.
Following are the updated classes:
# app/models/alert.rb
class Alert < ActiveRecord::Base
end
# app/models/alerts/base_alert.rb
module Alerts
class BaseAlert < ::Alert
end
end
# app/models/alerts/panic_alert.rb
module Alerts
class PanicAlert < BaseAlert
end
end
# app/models/alerts/hardware_alert.rb
module Alerts
class HardwareAlert < BaseAlert
end
end
Following are few ways to create the subclasses from the base class:
#panic_alert = Alert.create!(
type: 'Alerts::PanicAlert', #this has to be string
#other attributes
)
#alert = Alert.new
#alert.type = 'Alerts::PanicAlert' #this has to be string
# assign other attributes, if necessary
#alert.save
#alert = Alert.new
#panic_alert = #alert.becomes(Alerts::PanicAlert) #this has to be class
# assign other attributes, if necessary
#panic_alert.save
You can use the constantize or the safe_constantize methods to do that. What they do is take a string and try to return the class the string refers to. For instance:
"BaseAlert".safe_constantize
=> BaseAlert
or
def method_name(alert_type)
alert_type.safe_constantize.create()
end
The difference between the two is constantize will throw an error if there isn't a match for the string, while safe_constantize will just return nil. Remember, if you pass in a underscored string (say panic_alert) then you would have to camelize it.
What seems like a lifetime ago I created StiFactory for this. That said, I don't find much use for STI these days (hence the lack of maintenance).
I have a class that inherits from another class. The setup of the superclass is as follows:
class Creator::BaseResource < Creator::Base
def request_attributes(action = :create)
"super"
end
end
And the subclass:
class Creator::Resource::HypervisorGroup < Creator::BaseResource
def request_attributes(action = :create)
"sub"
end
end
Now, if I have an instance of "Creator::BaseResource", and there is a DB column named "resource_class" which contains "Resource::HypervisorGroup" that makes it known that its a subclass, I would like to be able to say object.request_attributes and get "super" returned, in this example.
The code is far more complicated than this, obviously, but that's the gist of what I want to accomplish. Is it possible? Thank you.
What about that :
class Creator::Resource::HypervisorGroup < Creator::BaseResource
def request_attributes(action = :create, use_super=false)
super and return if use_super
"sub"
end
end
And then, you can call object.request_attributes(:create, true) to get the superclass method called
I have a model:
class Mymodel < ActiveRecord :: Base
attr_accessible :the_date, :the_time, :the_event
def the_date
...
end
def the_time
...
end
def the_event
...
end
...
end
My controller holds a array of methods names, which is used by view:
class Mycontroller < ApplicationController
#methods=['the_date', 'the_time', 'the_event']
...
end
in my view index.html.haml, I would like to dynamically access the model methods:
%td
-index=SOME_USER_INPUT
=mymodel.#methods[index] /IT DOES NOT WORK HERE!!
But, I can not dynamically call the model methods in this way: mymodel.#methods[index], how to have dynamical method call based on my sample code??
#methods is an instance variable of your controller, not of your model. Assuming you want to call the method, try this:
=mymodel.send(#methods[index])
Hey guys.
How do I know the methods that a child class overrided in my super class?
I have this:
class Test
def self.inherited(child)
# child.overrided_methods???
end
def self.foo
end
def self.bar
end
end
def Child < Test
def self.bar
puts "bar"
end
end
The method self.inherited is called when a subclass of Test is loaded. So I get the reference to this subclass in child, but I don't know how to get the methods that were overrided by this subclass.
Any ideas?
--
Arsen suggested the use of self.method_added(name) instead of self.inherited(child), but this method catches only instance methods and I want to catch class methods. Does anyone know another methods that does the same thing but with class methods?
In the last case I'll consider using a singleton and convert all this class methods to instance methods then the problem is solved.
For instance methods there is an Object::method_added(name) method you can override, similar to 'inherited' you have used:
class test
def self.method_added(name)
puts "method_added(#{name.inspect})"
super
end
end
irb(main):002:0> class Child < Test; def foo; end; end
method_added(:foo)
=> nil
You can then compare a received name to a list of your methods:
Test.instance_methods.include?(name.to_s)
With class methods this approach does not work (even if you do things like class << self magic), but a helpful fellow knew the answer: http://www.ruby-forum.com/topic/120416 :
class Test
def self.singleton_method_added(name)
puts "Class method added #{name.inspect}"
end
end
This is only the first part of the problem, because you need to know which class defined the method (it will be self) and whether the method is a new one, or overridden one. Experiment with this code:
class Test
def self.singleton_method_added(name)
if self == Test
puts "My own class method added: #{self.name}.#{name.inspect}"
elsif Test.methods(false).include?(name.to_s)
puts "Class method overriden: #{self.name}.#{name.inspect}"
elsif Test.methods(true).include?(name.to_s)
puts "My parent's class method overriden: #{self.name}.#{name.inspect}"
else
puts "New class method added: #{self.name}.#{name.inspect}"
end
end
end
Maybe a first step to the solution:
By calling child.instance_method(:bar) (if child refers to the class) or child.method(:bar) (if it refers to an instance of Child) you can get an UnboundMethod or Method object representing your method:
a = Test.instance_method(:foo)
b = Child.instance_method(:foo)
Unfortunately, a == b evaluates to false, although both refer to the same method.
def overridden_methods
klass = self.class
klass.instance_methods.select {|m| klass.instance_method(m).owner == klass}
end
Change according to your needs.