A small test case :
class A
def self.print
puts "Hello A"
end
end
class B < A
end
A.print
B.print
This outputs :
Hello A
Hello A
I would like to block the inheritance of the print function defined in class A. Is it possible?
Output wanted :
Hello A
`<main>': undefined method `print' for B:Class (NoMethodError)
I found private_class_method but it's not exaclty what I'm looking for as it fails on A.print call.
class A
def self.print
puts "Hello A"
end
def self.inherited(klass)
class << klass
undef :print
end
end
end
class B < A
end
A.print
# Hello A
B.print
# private method `print' called for B:Class (NoMethodError)
class B < A
class << self
undef print
end
end
Declaring a method in a class << self block is the same as declaring it prefixed with self..
It also allows for the behavior that you want.
Related
Please explain me why i should define attr_list before attr? I can not understand why i should do that?
class Question
def self.attr_list
[:id, :name]
end
attr *self.attr_list
end
class Question
attr *self.attr_list
def self.attr_list
[:id, :name]
end
end
NoMethodError: undefined method `attr_list' for Question:Class
Unlike a def, a class is executed line by line immediately after you hit return to run your program:
class Dog
x = 10
puts x
end
--output:--
10
...
class Dog
puts x
x=10
end
--output:--
1.rb:2:in `<class:Dog>': undefined local variable or method `x'
In this line:
...
class Dog
def self.greet
puts 'hello'
end
greet
end
--output:--
hello
...
class Dog
greet
def self.greet
puts 'hello'
end
end
--output:--
1.rb:2:in `<class:Dog>': undefined local variable or method `greet'
Similarly, in this line:
attr *self.attr_list
you call self.attr_list(), yet the def comes after that line, so the method doesn't exist yet.
With a def, you can write this:
def do_math()
10/0
end
and you won't get an error until you call the method.
But by the time you create an instance of a class, all the code inside the class has already executed, creating the methods and constants that are defined inside the class.
By the way, you don't ever need to use attr because ruby 1.8.7+ has attr_accessor(reader and writer), attr_reader, and attr_writer.
I have a module that defines a method if it is not already defined. This is the case of ActiveRecord's attributes as theirs getters and setters are not defined as methods.
module B
def create_say_hello_if_not_exists
puts respond_to?(:say_hello)
define_method :say_hello do
puts 'hello'
end unless respond_to?(:say_hello)
end
end
class A
def say_hello
puts 'hi'
end
puts respond_to?(:say_hello, true)
extend B
create_say_hello_if_not_exists
end
A.new.say_hello
The expected result is hi, but ruby prints hello. Why?
Maybe related to Confused about "respond_to?" method
Try this.
module B
def create_say_hello_if_not_exists
puts method_defined?(:say_hello)
define_method :say_hello do
puts 'hello'
end unless method_defined?(:say_hello)
end
end
class A
def say_hello
puts 'hi'
end
puts method_defined?( :say_hello )
extend B
create_say_hello_if_not_exists
end
A.new.say_hello
The reason why respond_to?(:say_hello) is returning false is due to the fact class A has say_hello as instance method and since you are extending class B the create_say_hello_if_not_exists is declared as class method and it does not find say_hello.
Changing the code to the following would do the trick. I'm declaring say_hello in class A as class method and am calling it in a static manner.
module B
def create_say_hello_if_not_exists
puts respond_to?(:say_hello)
define_method :say_hello do
puts 'hello'
end unless respond_to?(:say_hello)
end
end
class A
def self.say_hello
puts 'hi'
end
extend B
create_say_hello_if_not_exists
end
A.say_hello
I have a class A, which I would like to anonymously extend and add a class method to the child class. E.g.:
class A
end
Class.new A do
def self.new_class_method
puts 'I am a class method'
end
end.new_class_method
=> I am a class method
The above example works well, unless you want to access some variables outside of the def self.new_class_method block. E,g,
greeting = 'hello'
Class.new A do
def self.new_class_method
puts greeting + ' I am a class method'
end
end.new_class_method
=> NameError: undefined local variable or method `greeting'
I am using Ruby 1.8.7, which is sad because I believe Ruby 1.9+ contains an analog to define_method which adds a class method. Does anyone have a work around for 1.8.7?
I have tested the below in Ruby 1.8.7 :-
greeting = 'hello'
class A
end
Class.new A do
meta_klass = class << self; self ;end
meta_klass.send(:define_method, :new_class_method) do
puts greeting + ' I am a class method'
end
end.new_class_method
# >> hello I am a class method
As Ruby 1.8.7 doesn't support Object#singleton_class, I used meta_klass = class << self; self ;end. This method is available since 1.9.2, I think.
You can also use extend() to pry open an object's singleton class. Calling extend(module) adds the methods in the module to the calling object's(i.e. the receiver's) singleton class. So if you call extend(module) when self=A, i.e. inside class A, then the module's methods will be inserted into A's singleton class, and the methods in A's singleton class are also known as class methods of A:
class A
end
greeting = "hello"
Class.new(A) do
extend(
Module.new do
define_method(:greet) do
puts greeting
end
end
)
end.greet
--output:--
hello
And you can rewrite that like this (although then it's not as tricky):
class A
end
greeting = "hello"
Class.new(A) do
m = Module.new do
define_method(:greet) do
puts greeting
end
end
extend(m)
end.greet
...which isn't much different than:
class A
end
greeting = "hello"
m = Module.new do
define_method(:greet) do
puts greeting
end
end
Class.new(A) do
extend(m)
end.greet
...which moves the closure out of the class, and doesn't seem very tricky at all because it only opens up two scope gates instead of three.
Also note, extend() is a public method, so it doesn't require the trickery of a private method, i.e. where you can't specify an explicit receiver, so you have to create a context in which self is the object you want to call the private method on. In other words, you can specify an explicit receiver for extend(). How about the class that is returned by Class.new(A)?
class A
end
greeting = "hello"
Class.new(A).extend(
Module.new do
define_method(:greet) do
puts greeting
end
end
).greet
--output:--
hello
Hey, tacking on ".greet" there works! Uh oh, that has the makings of a one liner:
class A
end
greeting = "hello"
Class.new(A).extend(Module.new {define_method(:greet) {puts greeting} }).greet
--output:--
hello
Yeech!
More generally,
class A
end
class Object
def meta_def name, &blk
(class << self; self; end).instance_eval { define_method name, &blk }
end
end
greeting = 'hello'
Class.new A do
meta_def :new_class_method do
puts greeting + ' I am a class method'
end
end.new_class_method
#=> hello I am a class method
If you find this useful, don't thank me, thank some lucky stiff (which I saw mentioned by Jay Fields).
Not sure if this will solve your problem, but changing Greeting to uppercase (making it a constant) would work...
class A
end
Greeting = 'hello'
Class.new A do
def self.new_class_method
puts Greeting + ' I am a class method'
end
end.new_class_method
For example:
class A
def A::f
end
end
What is A::f ?
I suppose it is neither class method nor instance method...
Using the double colons creates a class method. You can see this by doing a simple test:
class A
def A::f
puts "Called A::f"
end
end
puts "A.public_methods:"
puts A.public_methods(false)
puts
a = A.new
puts "a.public_methods:"
puts a.public_methods(false)
puts
puts "Attempt to call f"
A.f
a.f
Output:
A.public_methods:
f
allocate
new
superclass
a.public_methods:
Attempt to call f
Called A::f
NoMethodError: undefined method âfâ for #<A:0x0000010084f020>
http://marcricblog.blogspot.com/2007/11/ruby-double-colon.html
I would like to understand what class << self stands for in the next example.
module Utility
class Options #:nodoc:
class << self
def parse(args)
end
end
end
end
this
module Utility
class Options #:nodoc:
class << self
# we are inside Options's singleton class
def parse(args)
end
end
end
end
is equivalent to:
module Utility
class Options #:nodoc:
def Options.parse(args)
end
end
end
A couple examples to help you understand :
class A
HELLO = 'world'
def self.foo
puts "class method A::foo, HELLO #{HELLO}"
end
def A.bar
puts "class method A::bar, HELLO #{HELLO}"
end
class << self
HELLO = 'universe'
def zim
puts "class method A::zim, HELLO #{HELLO}"
end
end
end
A.foo
A.bar
A.zim
puts "A::HELLO #{A::HELLO}"
# Output
# class method A::foo, HELLO world
# class method A::bar, HELLO world
# class method A::zim, HELLO universe
# A::HELLO world
This is an eigenclass. This question's been asked before.