Is a singleton method necessarily public? If not, when would a private/protected singleton method be useful?
Singleton methods do not necessarily need to be public. Private/protected singleton methods are useful in the same situations as regular private/protected methods - for example as a helper method that you do not intend to be called outside of the class.
class Foo
end
f = Foo.new
class << f
def foo
helper
# other stuff
end
private
def helper
end
end
You can make a singleton method private if you want:
class Foo
end
f = Foo.new
def f.bar
"baz"
end
f.singleton_class.send :private, :bar
f.bar # => NoMethodError: private method `bar' called for #<Foo:0x007f8674152a00>
f.send :bar # => "baz"
whether or not this is actually useful depends on what you're doing.
You can make a singleton method private if you want:
class Foo
def self.bar
# ...
end
private_class_method :bar
end
Could they be useful? Hmmm. For Ruby 2.2
ObjectSpace.each_object(Module).flat_map { |m|
m.singleton_class.private_methods(false) }.size
#=> 900
Most are private methods of classes' singleton classes:
ObjectSpace.each_object(Class).flat_map { |c|
c.singleton_class.private_methods(false) }.size
#=> 838
[Edit: The following is an edit of my original post, to present more useful information.)
I am puzzled by one thing. Let:
a = ObjectSpace.each_object(Class).map { |c|
[c, c.singleton_class.private_methods(false)] }.to_h
b = ObjectSpace.each_object(Class).map { |c|
[c, c.private_methods(false)] }.to_h
def diff(a,b)
a.map {|k,v| b.key?(k) ? [k,v-b[k]] : [k,v] }.reject { |_,a| a.empty?}.to_h
end
I expected diff(a,b) == diff(b,a) == {}. Let's see:
diff(a,b)
#=> {}
diff(b,a)
#=> {Gem::Specification=>[:skip_during, :deprecate],
# Complex=>[:convert],
# Rational=>[:convert],
# Random=>[:state, :left],
# Time=>[:_load]}
Hmmmm.
Related
I have the following code where I set attr_reader and attr_writer manually.
class Pairs
attr_reader :pair, :asks, :bids, :isFrozen, :seq, :main_currency, :sub_currency
attr_writer :pair, :asks, :bids, :isFrozen, :seq
def initialize (key, args)
#pair = key
#main_currency, #sub_currency = key.split('_')
args.each {|k,v|
if numeric?(v) then v=v.to_f end
self.instance_variable_set("##{k}".to_sym, v)
}
end
private
def numeric?(string)
Float(string) != nil rescue false
end
end
Is there a way to automatically set them based on the keys of the arguments, like I'm automatically filling #k with v? Can I set attr_reader for each #k?
I suppose something like:
self.attr_reader("##{k}")
or even better for all objects of the class, something like:
Pairs << attr_reader("##{k}")
I am going to assume that you may be creating this with many keys specific to different Hash if this is the case then rather than clutter the individual instances with unneeded readers for non existent keys let's use the singleton_class for this.
So your final Pairs class could look something like
class Pairs
attr_reader :main_currency, :sub_currency
attr_accessor :pair, :asks, :bids, :isFrozen, :seq
def initialize (key, args)
#pair = key
#main_currency, #sub_currency = key.split('_')
args.each do |k,v|
singleton_class.send(:attr_reader,k)
instance_variable_set("##{k}", convert_numeric(v))
end
# Alternatively:
# args.each do |k,v|
# val = convert_numeric(v)
# define_singleton_method(k) {val}
# end
end
private
def convert_numeric(val)
Float(Rational(val)) rescue val
end
end
TL;DR
For Example: (using #mudasobwa's approach)
class C
def extend_self_with_reader name
self.class.send :attr_reader, name
end
def initialize *keys
keys.each(&method(:extend_self_with_reader))
end
end
This causes subsequent readers to clutter the instance and bleed across instances:
a = C.new(:a,:b)
a.a #=> nil
b = C.new
b.a #=> nil
c = C.new(:r)
c.a #=> nil
c.r #=> nil
a.methods.sort - Object.methods
#=> [:a, :b, :extend_self_with_reader, :r]
a.r #=> nil (hmmmmm)
Instead localize these readers buy using the singleton_class of the instance like:
class C
def initialize *keys
singleton_class.send(:attr_reader, *keys)
end
end
Then
a = C.new(:a,:b)
a.a #=> nil
b = C.new
b.a #=> NoMethodError: undefined method `a'
c = C.new(:r)
c.a #=> NoMethodError: undefined method `a'
c.r #=> nil
a.r #=> NoMethodError: undefined method `r'
a.methods.sort - Object.methods
#=> [:a,:b]
b.methods.sort - Object.methods
#=> []
Using the singleton_class localizes these readers to the instance of the object rather than bleeding them into the Class definition. If attr_reader is not a requirement then this would also be sufficient:
keys.each {|k| define_singleton_method(k) {}}
I doubt I understood the question, but from what I get you want to dynamically extend your class with attribute readers at runtime.
This method would do:
def extend_self_with_reader name
self.class.send :attr_reader, name
end
Test:
class C
def extend_self_with_reader name
self.class.send :attr_reader, name
end
def initialize *keys
puts keys.inspect
keys.each(&method(:extend_self_with_reader))
end
end
cc = C.new(*%i|a b c|)
cc.a #⇒ nil
Perhaps look into define_method.
I'm not 100% sure that I understand the problem, but check this out:
hash = { a: 1, b: 2, c: 3 }
hash.keys.each do |key|
define_method(key) do
hash[key]
end
end
There are now methods for a, b, and c:
a => 1
b => 2
c => 3
That essentially makes an attr_reader for all the keys in the hash. You could do something similar for an attr_writer.
I want to modify the existing module A from a library:
module A
class << self
def foo
bar('Baz')
end
private
def bar(val)
val.upcase
end
end
end
A.foo
=> "BAZ"
module B
extend A
def self.bar(val)
val.downcase
end
end
B.foo # hoping for 'baz', but instead:
NoMethodError: undefined method `foo' for B:Module
Is there a way to re-use method .foo from A and only modify method .bar?
extend A doesn't work, because foo and bar are no instance methods of A, but of A's singleton class. To re-use those methods, you have to either create a copy of A as mudasobwa described, or you can use a refinement of A's singleton class like this:
module B
extend(refine(A.singleton_class) do
def bar(val)
val.downcase
end
end)
end
B.foo # => "baz"
You cannot use extend A.singleton_class as extend doesn't accept a class as argument. refine returns a module which is exactly what's needed.
Assuming you have A declared as above, the following code would do:
▶ B = A.clone
#⇒ B
▶ (class << B; self; end).send :define_method, :bar do |val|
val.downcase
end
▶ A.foo
#⇒ "BAZ"
▶ B.foo
#⇒ "baz"
There probably should be less tricky way, but I can’t yet figure it out.
I have a class that have an instance method, that returns a hash. I can't change the code of that class directly, but I can extend it with modules. I need to add some new keys to the returning hash of the method. Something like this:
class Processor
def process
{ a: 1 }
end
end
module ProcessorCustom
def process
super.merge(b: 2) # Not works :(
end
end
Processor.send :include, ProcessorCustom
processor = Processor.new
processor.process # returns { a: 1 }, not { a: 1, b: 2 }
How can I do that? Thanks.
You could call prepend instead of include:
Processor.prepend(ProcessorCustom)
processor = Processor.new
processor.process
#=> {:a=>1, :b=>2}
prepend and include result in different ancestor order:
module A; end
module B; end
module C; end
B.ancestors #=> [B]
B.include(C)
B.ancestors #=> [B, C]
B.prepend(A)
B.ancestors #=> [A, B, C]
Alternatives
Depending on your use-case, you could also extend a specific instance: (this doesn't affect other instances)
processor = Processor.new
processor.extend(ProcessorCustom)
processor.process
#=> {:a=>1, :b=>2}
Or use SimpleDelegator to implement a decorator pattern:
require 'delegate'
class ProcessorCustom < SimpleDelegator
def process
super.merge(b: 2)
end
end
processor = ProcessorCustom.new(Processor.new)
processor.process #=> {:a=>1, :b=>2}
I think the first option to consider would be the one requiring the least work by the reader to comprehend; and in Object Oriented software that would be a subclass to specialize the behavior of the superclass. I would deviate from this if, and only if, there were a compelling reason to do so.
How about this?:
#!/usr/bin/env ruby
class Processor
def foo
{ x: 3 }
end
end
class MyProcessor < Processor
def foo
super.merge({ y: 7 })
end
end
p MyProcessor.new.foo # outputs: {:x=>3, :y=>7}
I think it's better to create a proxy than to pollute the original class.
class Proxy
def initialize(target)
#target = target
end
# add some syntactic sugar
singleton_class.class_eval { alias [] new }
def process
#target.process.merge!(b: 2)
end
end
Proxy[Processor.new].process #=> {a: 1, b: 2}
You can even create your own dynamic proxy.
class DynamicProxy < BasicObject
def initialize(target)
#target = target
end
# again, add some syntactic sugar
singleton_class.class_eval { alias [] new }
def method_missing(name, *args, &block)
super unless #target.respond_to?(name)
# Do something before calling the target method
result = #target.send(name, *args, &block)
# Do something after calling the target method
end
def respond_to_missing?(name, include_private = false)
#target.respond_to?(name, include_private)
end
end
To hide the detail of creating Processor instance, you can make a simple factory to handle the creation.
module ProcessorFactory
def self.create
DynamicProxy[Processor.new]
end
end
Then you can do your job
ProcessorFactory.create.process
I'm looking for a way of making a method "personal" - note NOT PRIVATE to a class
here is an example - by "personal" I mean the behaviour of method "foo"
class A
def foo
"foo"
end
end
class B < A
def foo
"bar"
end
end
class C < B
end
a=A.new; b=B.new;c=C.new
I'm looking for a way of producing the following behaviour
a.foo #=> "foo"
b.foo #=> "bar"
c.foo #=> "foo" (ultimate base class method called)
Instead of creating 'personal' methods, change your inheritance structure.
It appears that you want the C class to have only some of the same functionality of the B class while not making changes to the A class.
class A
def foo
"foo"
end
end
class BnC < A
end
class B < BnC
def foo
"bar"
end
end
class C < BnC
end
a=A.new; b=B.new;c=C.new
There's no standard way of doing this. It circumvents how inheritance works. You could implement B's method to do the logic like this:
def foo
instance_of?(B) ? "bar" : super
end
And you could of course define a method on Class that would do this for you similar to public and private.
class Class
def personal(*syms)
special_class = self
syms.each do |sym|
orig = instance_method(sym)
define_method(sym) {|*args| instance_of?(special_class) ? orig.bind(self).call(*args) : super}
end
end
end
Then you can personal :foo in B just like you'd private :foo.
(This isn't at all optimized and I didn't implement the zero-argument behavior that public and private have because frankly it's a huge PITA to do right and even then it's a hack.)
Seems like it could be confusing, but here's one option:
class A
def foo
"foo"
end
end
class B < A
def initialize #when constructing, add the new foo method to each instance
def self.foo
"bar"
end
end
end
class C < B
def initialize #when constructing, do nothing
end
end
More generally, using a similar approach, you can always add a method to a given instance, which of course has no effect on inherited classes or indeed on other instances of the same class.
If you give us specifics of what you're ultimately trying to accomplish we can probably be more helpful.
Answering this is a bit tricky since I don't really see what you want to accomplish in practice, but you could try something like
class C < B
def foo
self.class.ancestors[-3].instance_method(:foo).bind(self).call
end
end
(The ancestors[-3] assumes that A inherits from Object and Kernel and your intent was to access the method from the topmost non-builtin class. Of course you could substitute self.class.ancestors[-3] with just A, or figure out the class from the Array ancestors yourself, etc.)
In practice it would be simpler to alias the original in class B if you can modify it (i.e. alias :foo_from_A :foo in class B < A before the new def foo, then you can call foo_from_A in C). Or just redefine what you want in C. Or design the whole class hierarchy differently.
You can write a shortcut function to handle personalizing methods.
def personalize(*methodNames)
old_init = instance_method(:initialize)
klass = self
modul = Module.new {
methodNames.each { |m|
define_method(m, klass.instance_method(m)) if klass.method_defined?(m)
}
}
methodNames.each { |m|
remove_method(m) if method_defined?(m)
}
define_method(:initialize) { |*args|
# I don't like having to check instance_of?, but this is the only way I
# could thing of preventing the extension of child classes. At least it only
# has to happen once, during initialization.
extend modul if instance_of?(klass)
old_init.bind(self).call(*args)
}
self
end
class A
def foo
"foo"
end
end
class B < A
def foo
"bar"
end
def bam
'bug-AWWK!'
end
personalize :foo, :bam, :nometh
end
class C < B
end
a=A.new; b=B.new; c=C.new
a.foo #=> "foo"
b.foo #=> "bar"
b.bam #=> "bug-AWWK!"
c.foo #=> "foo"
C.instance_method(:foo) # => #<UnboundMethod: C(A)#foo>
c.bam #throws NoMethodError
Sometimes you don't really want an "is a" (inheritance) relationship. Sometimes what you want is "quacks like a." Sharing code among "quacks like a" classes is easily done by using modules to "mix in" methods:
#!/usr/bin/ruby1.8
module BasicFoo
def foo
"foo"
end
end
class A
include BasicFoo
end
class B
def foo
"bar"
end
end
class C
include BasicFoo
end
p A.new.foo # => "foo"
p B.new.foo # => "bar"
p C.new.foo # => "foo"
Is there any difference if you define Foo with instance_eval: . . .
class Foo
def initialize(&block)
instance_eval(&block) if block_given?
end
end
. . . or with 'yield self':
class Foo
def initialize
yield self if block_given?
end
end
In either case you can do this:
x = Foo.new { def foo; 'foo'; end }
x.foo
So 'yield self' means that the block after Foo.new is always evaluated in the context of the Foo class.
Is this correct?
Your two pieces of code do very different things. By using instance_eval you're evaluating the block in the context of your object. This means that using def will define methods on that object. It also means that calling a method without a receiver inside the block will call it on your object.
When yielding self you're passing self as an argument to the block, but since your block doesn't take any arguments, it is simply ignored. So in this case yielding self does the same thing as yielding nothing. The def here behaves exactly like a def outside the block would, yielding self does not actually change what you define the method on. What you could do is:
class Foo
def initialize
yield self if block_given?
end
end
x = Foo.new {|obj| def obj.foo() 'foo' end}
x.foo
The difference to instance_eval being that you have to specify the receiver explicitly.
Edit to clarify:
In the version with yield, obj in the block will be the object that is yielded, which in this case is is the newly created Foo instance. While self will have the same value it had outside the block. With the instance_eval version self inside the block will be the newly created Foo instance.
They are different. yield(self) does not change the value of self inside the block, while instance_eval(&block) does.
class Foo
def with_yield
yield(self)
end
def with_instance_eval(&block)
instance_eval(&block)
end
end
f = Foo.new
f.with_yield do |arg|
p self
# => main
p arg
# => #<Foo:0x100124b10>
end
f.with_instance_eval do |arg|
p self
# => #<Foo:0x100124b10>
p arg
# => #<Foo:0x100124b10>
end
You just can drop the self keyword
class Foo
def initialize
yield if block_given?
end
end
Update from comments
Using yield there is a bit new to my taste, specially when used outside irb.
However there is a big and significant difference between instance_eval approach and yield approach, check this snippet:
class Foo
def initialize(&block)
instance_eval(&block) if block_given?
end
end
x = Foo.new { def foo; 'foo'; end }
#=> #<Foo:0xb800f6a0>
x.foo #=> "foo"
z = Foo.new #=> #<Foo:0xb800806c>
z.foo #=>NoMethodError: undefined method `foo' for #<Foo:0xb800806c>
Check this one as well:
class Foo2
def initialize
yield if block_given?
end
end
x = Foo2.new { def foo; 'foo'; end } #=> #<Foo:0xb7ff1bb4>
x.foo #=> private method `foo' called for #<Foo2:0xb8004930> (NoMethodError)
x.send :foo => "foo"
z = Foo.new #=> #<Foo:0xb800806c>
z.send :foo => "foo"
As you can see the difference is that the former one is adding a singleton method foo to the object being initialized, while the later is adding a private method to all instances of Object class.