REALbasic: Sharing common code between disparate subclasses - realbasic

I have two separate classes (A = a subclass of BevelButtom, B = a subclass of PushButton). Both A and B implement a number of identical methods in exactly the same way. Since both subclasses' superclasses are different and since RB doesn't support multiple inheritance, all I can do to tie these methods together is define a class interface, have both subclasses implement the interface, then copy/paste the method bodies in each subclass.
That offends my sensibilities. Is there a way in RB to extract this common logic elsewhere?
Thanks!

Use the Extends syntax from a module method to extend the class interface. You still need to use a class interface, but this way all the common code can be placed in the module instead of being duplicated across multiple classes.
Interface FooInterface
Sub Foo()
End Interface
Class Foo
Implements FooInterface
Sub Foo()
MsgBox("Foo!")
End Sub
End Class
Class Bar
Implements FooInterface
Sub Foo()
MsgBox("Bar!")
End Sub
End Class
Module FooExtensions
Sub Foobar(Extends FooImplementor As FooInterface)
MsgBox("Foobar!")
End Sub
End Module
The above FooBar method would be called like a class method of any class that implements the FooInterface class interface:
Dim myfoo As FooInterface = New Bar
myfoo.Foobar()
Note that extension methods don't count when the compiler is deciding whether a given class satisfies an interface.
This may not be workable, however, since the extension methods will only have access to the Interface rather than the actual class.
Alternatively, you could extend the RectControl class, though that would include all desktop controls, not just the PushButton and BevelButton.
A third option might be to use the BevelButton class exclusively.

Using an interface seems like the right approach, but rather than copying the method bodies to each subclass, I think it makes more sense to create a new class (say CommonButtonStuff) with the common code. Then you can call it in the implemented methods:
CommonButtonInterface
Sub Method1
Class CommonButtonHandler
Sub DoMethod1
MsgBox("Do it!")
End Sub
Class A Inherits From PushButton, Implements CommonButtonInterface
Private Property mCommonStuff As CommonButtonHandler
Sub Constructor
mCommonStuff = New CommonButtonHandler
End Sub
Sub Method1
mCommonStuff.DoMethod1
End Sub
Class B Inherits From BevelButton, Implements CommonButtonInterface
Private Property mCommonStuff As CommonButtonHandler
Sub Constructor
mCommonStuff = New CommonButtonHandler
End Sub
Sub Method1
mCommonStuff.DoMethod1
End Sub

Related

Subclassing a class that has a "factory" method

I have a class that has a "factory" method which returns new instances given a file_name. Depending on the type of file given it needs to construct the object differently. It also happens to be a swig generated class wrapping a c++ class, I am not sure that matters, but I am including that detail just in case it does. So I have this class defined somewhere, which has among other things this new_from_file method
class Wv::WvWaveList
def self.new_from_file file_name
...
Wv::WaveList.new
end
....
end
I wanted to add a method copy_wave, so my first thought was to subclass and add it there so something like this.
class MyWaveList < Wv::WvWaveList
def copy_wave
...
end
end
The problem is that new_from_file still returns a Wv::WaveList not a MyWaveList so I can't call copy_wave on instances returned by new_from_file
One simple solution is to just open the class up here and add the method
class Wv::WvWave
def copy_wave
...
end
end
Another solution would be to have MyWaveList have an instance of a Wv::WaveList and delegate all the appropriate calls to that instance.
So I am just wondering what the inheritance solution might be? I just don't see it right now.
I believe this should work
class Wv::WvWaveList
def self.new_from_file file_name
...
self.new
end
....
end
Because self.new_from_file was always calling Wv::WaveList.new, it was always instantiating objects with that class, even from subclasses. But by using self, you'll be able to call new_from_file on any subclass, and the objects will be of the correct class:
>> a = MyWaveList.new_from_file "some_file"
=> #<MyWaveList:0x007fd473004318 #file_name="some_file">
>> a.class
=> MyWaveList

What does `def self.function` name mean?

Can anyone explain to me what the meaning of adding self to the method definition is? Is it similar to the this keyword in java?
Contrary to other languages, Ruby has no class methods, but it has singleton methods attached to a particular object.
cat = String.new("cat")
def cat.speak
'miaow'
end
cat.speak #=> "miaow"
cat.singleton_methods #=> ["speak"]
def cat.speak creates a singleton method attached to the object cat.
When you write class A, it is equivalent to A = Class.new :
A = Class.new
def A.speak
"I'm class A"
end
A.speak #=> "I'm class A"
A.singleton_methods #=> ["speak"]
def A.speak creates a singleton method attached to the object A. We call it a class method of class A.
When you write
class A
def self.c_method
'in A#c_method'
end
end
you create an instance of Class(*). Inside the class definition, Ruby sets self to this new instance of Class, which has been assigned to the constant A. Thus def self.c_method is equivalent to def cat.speak, that is to say you define a singleton method attached to the object self, which is currently the class A.
Now the class A has two singleton methods, that we commonly call class methods.
A.singleton_methods
=> ["c_method", "speak"]
(*) technically, in this case where A has already been created by A = Class.new, class A reopens the existing class. That's why we have two singleton methods at the end. But in the usual case where it is the first definition of a class, it means Class.new.
In ruby self is somewhat similar to this in java, but when it comes to classes its more like the keyword static in java. A short example:
class A
# class method
def self.c_method
true
end
# instance method
def i_method
true
end
end
A.c_method #=> true
A.i_method #=> failure
A.new.i_method #=> true
A.new.c_method #=> failure
Update: Difference between static methods in java and class methods in ruby
Static methods in Java have two distinct features that makes them different from instance methods: a) they are static, b) they are not associated with an instance. (IOW: they really aren't like methods at all, they are just procedures.) In Ruby, all methods are dynamic, and all methods are associated with an instance. In fact, unlike Java where there are three different kinds of "methods" (instance methods, static methods and constructors), there is only one kind of method in Ruby: instance methods. So, no: static methods in Java are completely unlike methods in Ruby. – Jörg W Mittag 1 hour ago
When declaring a method, the self of the declaration is the declaring class/module, so effectively you are defining a class method. For the client, this works similar to a static method in java. The client would call the method on the class instead of an instance: MyClass.method
Here you can find some more details on class and instance methods.
EDIT: While the self keyword is akin to the this keyword in java, the effects of using self for class method declaration are similar to the effect of using the static keyword in java. The similarity is that static methods in java, like class methods in ruby are accessed using the class object iself instead of an instance of the class.
Please note that static does not stand for the opposite of dynamic. The choice of the name for this keyword is questionable (probably inherited from C) and rather should have been called perClass or similar to better reflect the meaning. The technical meaning is that all static members exist only once for each classloader.

moving class-level dynamic method creation into a module in ruby

I'm working on an application where I have a plugin-style architecture with multiple abstract classes that define an API, and specific implementations with subclasses that provide methods for the attributes defined on the abstract classes. Think of a generic database adapter with abstract classes like Connection, Table, Column, etc. and specific subclasses of these for a particular database.
In an attempt to be DRY, I declare the attributes of each abstract class (with default values) as a class constant Array called ATTRIBUTES. Since ruby doesn't support true abstract classes, I dynamically create methods that raise an exception if they're called on the abstract class. For example:
module MyApplication
class Operation
ATTRIBUTES = { name: '', parameters: [], type: :void }
ATTRIBUTES.keys.each do |a|
str = "Method '%s' called on abstract 'MyApplication::Operation' class"
define_method(a) { raise (str % a) }
define_method("#{a}=") { |x| raise (str % "#{a}=") }
end
end
end
I hard code the class name in the message because I can't use the name of the current class, since it might be a subclass of the abstract Operation class, and I want the message to be clear that the method being called is on the abstract class.
I have more than a handful of these abstract classes, and I've copied nearly the same code into each one to create these stub methods (only the attributes list and class name are different). I've tried numerous ways to put this code into a module that I can include (or extend?) from each abstract class, but my brain is now folded in on itself trying to sort out the meta-programming details of how to get this to work. :)
Does anyone have the magic bullet to pull this common, class-level (but instance method-making) code into a module to avoid repeating the same code over and over?
This should do what you want:
module PluginHelpers
def stub_required_methods(*method_names)
method_names.each do |method_name|
define_method(method_name) do
raise NotImplementedError, "Method #{__method__} must be implemented in #{self.class}"
end
end
end
end
class A
class B
class C
extend PluginHelpers
stub_required_methods(:foo, :bar)
end
end
end
# usage
A::B::C.new.foo # => NotImplementedError: Method foo must be implemented in A::B::C

class Class - instance vs. class methods

How is it that this works? When the following is run "hi from class" is printed twice. What is going on inside ruby to make this behave like this? Am I NOT in fact making an instance method for class
class Class
def foo
puts "hi from class"
end
end
Class.foo
x = Class.new
x.foo
I don't know whether you're aware of that, but when you do class Class ... end, you're not creating a new class named Class, you're reopening the existing class Class.
Since Class is the class that all classes are instances of that means that Class is an instance of itself. And because of that you can call any instance methods of Class directly on Class the same way you can on any other class.

Create property as method on class in Ruby

Rails has these cool properties that seem to be actually methods. For example:
class SomeController < ApplicationController
before_filter :authenticate!
end
What are these actually called and how would you create your own? For example, in one of my models I want to be able to have a dynamic property that selects an internal method for processing some results:
class MyModel < ActiveRecord::Base
active_method :some_class_method
end
How would I set this up so I can set active_method like that and be able to access the active_method symbol as an instance var?
Edit for elaboration:
So give this starter below, I need to figure out how to define "selected_method" so that it defines a accessor or instance variable so "called_selected_method" calls "method_b".
class MyClass
selected_method :method_b
def call_selected_method
end
private
def method_a
puts 'method_a'
end
def method_b
puts 'method_b'
end
end
c = MyClass.new
c.call_selected_method # should put 'method_b'
It's actually just a method call to a method defined on the class. before_filter is provided by a ruby Module, which is mixed in to ActionController.
Creating your own methods similar to before_filter is as easy as:
Define a class method on your Class
Call that method in any concrete implementations of your class.
Some example code:
class MyClass
class << self
def some_function(*args)
# your code here
end
end
some_function "foo"
end
If you wanted to abstract it further, you can put the class method in to a Module, and then include that module in to your class(es).
UPDATE:
In relation to your asking of how to get a call of some_function to set an instance variable on your class, you can't, as class methods cannot affect specific instances of that class.
I have to wonder, though... you're writing a method that will just act as a proxy to your other method, and would be hard-coded in to the class definition. That offers no benefit to you, and would just make your code redundantly complicated.

Resources