I know how you can add class methods and class-behaviour using self << class (eigenclass). But, when reading some source code, I saw another use:
class LetterAvatar
class << self
class Identity
end
end
end
How does this work? What does it do and when should one use it? What would be a (possibly more recognised) alternative way to write this?
I think they did so because they did not need this class anywhere else.
Without opening the singleton class the flow would look as following (assuming every method defined in metaclass from original code would be prefixed with self.):
They could have defined the Identity as
class LetterAvatar
class Identity
end
end
and then use the class in self.generate method as follows:
class LetterAvatar
# code omitted
def self.generate
identity = LetterAvatar::Identity.from_username(username)
# code omitted
end
# other class level methods defined with `self.`
end
But why doing so if the Identity class is actually used only (and need not to be accessed anywhere else) in the singleton class (in generate)?
The solution is IMO very elegant, haven't seen anything like this before.
Related
I am a beginner in ruby.
I've tried to run this code and it shows run time error.
What's wrong with this code?
class Calc
attr_accessor :val1, :val2
def initialize (val1,val2)
#val1=val1
#val2=val2
end
end
a=Calc.new(2,3)
a.add_two_numbers(3)
def add_two_numbers(v3)
return #val1+#val2+v3
end
The method add_two_numbers is not defined on the class Calc, however you are using it as if it is. This is the problem.
I would presume you got a NoMethodError.
Update: As pointed out in the comments, in actuallity, the method is defined on the Object class by default, which then gets auto inherited into all classes, but as private. This actually means that you will be getting the error saying that a private method is being called. The fix remains the same, since the overarching problem is a confusion in how to define classes and their methods.
The fix would be to define the method on the class, by putting it in the class body.
class Calc
attr_accessor :val1, :val2
def initialize (val1,val2)
#val1=val1
#val2=val2
end
def add_two_numbers(v3)
return #val1+#val2+v3
end
end
So you are defining a method outside of a class (which is want we don't want)
def add_two_numbers(v3)
return #val1+#val2+v3
end
You always want to make sure that you keep your classes and you logic as two separate entities in terms of organization. By that I mean:
Your classes in one file (calc.rb):
**class Calc
attr_accessor :val1, :val2
def initialize (val1,val2)
#val1=val1
#val2=val2
end
def add_two_numbers(v3)
return #val1+#val2+v3
end
end**
And your logic to access calc.rb in another file. Use require relative to access the logic inside the class file:
require_relative"/calc.rb"
a=Calc.new(2,3)
a.add_two_numbers(3)
Tip: When I was learning ruby the best way to keep them in two separate files for better organization.That way you know you don't have a method somewhere outside of the class. This would avoid your "no method error"
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
I'm going through the Ruby Koans Ruby Koans and I'm at a place in "about_class_methods.rb" where there is a discussion of setting up class methods, and the Koans talk about three ways.
The two major ways to write class methods are:
1:
class Demo (define/open class)
def self.method
end
2:
class << self
def class_methods
end
end
The koans also talk about a third method, I've never seen (that I remember):
def Demo.class_method_third_way
end
Q1 This third way is actually clearer to me than any other. Is there a reason I don't understand about why no one uses it?
Q2 Why am I wrong in thinking the syntax for 2 should be "self << def name end"? That is "Why is the syntax the way it is?" Does the class Object hold a reference to all Classes and this sticks in the method for the self class?
As always, thanks for your help and patience!
In (early) development classes get renamed as insight grows (not Person but Employee, not Job but one or more Roles etc.) This renaming is prone to errors if the class name is hardcoded in the class itself.
In class body, self refers exactly the class object being defined. That's why def self.some_method works the same as def Demo.some_method.
class Demo
puts self.object_id == Demo.object_id
end
#=> true
class << some_obj is the syntax to access the singleton class of some_obj. Refer to the Ruby doc:
The singleton class (also known as the metaclass or eigenclass) of an object is a class that holds methods for only that instance. You can access the singleton class of an object using class << object ... Most frequently you’ll see the singleton class accessed like this:
class C
class << self
# ...
end
# or
class << C
end
end
I met strange difficulty developing one project. I dont have enough experience with classes so this is why I ask here. I have one class which is initialized with one parameter and I need other classes to call that class functions but I cant until that class is initialized so I asking how I could do that.
Here is some example what I talking about:
class AVR
def initialize(device)
#device = device
#avr_conf = YAML::load(File.open("./devices/#{device}.yaml"))
end
def avr_conf
return #avr_conf
end
end
class IO
def setMode(a,b)
"#{AVR.avr_conf[a]} = #{b}"
end
end
You either: need an instance, or to make avr_conf a class method (and initialize differently).
With an instance:
avr = AVR.new(a_device)
avr.avr_conf[a]
With a config singleton (roughly):
class AVR
def self.class_initialize(device)
##avr_conf ... etc ...
end
def self.avr_conf
return ##avr_conf
end
end
Then class IO would need to use the updated version, however that's appropriate.
If IO isn't going to/can't get an instance, the class/singleton-config might make more sense, although that approach always makes me a little nervous.
You could have the dependent method simply throw an exception if the independent class is not yet initialized:
class IO
def setMode(a, b)
raise StandardError.new("AVR device is not initialized") unless AVR.avr_conf
AVR.avr_conf[a] = b
end
end
Note however that this solution requires the AVR class to be a singleton (or module) since the IO extension methods will need to know which instance should be modified.
There are two kinds of methods in Ruby classes - actually class and instance methods.
Class methods defines with self. prefix and there's no need to initialize class:
class AVR
def self.avr_conf
'something here'
end
end
So, in this case you must call: AVR.avr_conf to get 'something here' result.
But, in your case, #avr_conf variable defines in initialize method and you have to create a class instance with:
avr = AVR.new('something')
avr.avr_conf[a] = b
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.