I have some namespaces that contain duck-type classes, and they all inherit from Base namespace, like below:
module Base
class Client
def self.greet
puts Wrapper
end
def do_stuff
puts Wrapper
end
end
class Wrapper
end
end
module Website
class Client < Base::Client
end
class Wrapper < Base::Wrapper
end
end
Website::Client.greet
Website::Client.new.do_stuff
---output---
Base::Wrapper
Base::Wrapper
I would like the above code to print (and reference) Website::Wrapper instead, is there a way to accomplish this by changing my inheritance structure?
If a constant named Wrapper is in the top-level namespace you can write ::Wrapper to refer to it, but usually just writing Wrapper is sufficient.
In Website::Client, if I attempt to call another class such as
Wrapper, it will call Base::Wrapper...
I'm not seeing that:
module Base
class Client
end
class Wrapper
end
end
module Website
class Wrapper < Base::Wrapper
end
class Client < Base::Client
p Wrapper #=>Website::Wrapper
def self.greet #Create class method
p Wrapper #=>Website::Wrapper
end
def do_stuff
p Wrapper #=>Website::Wrapper
end
end
end
Website::Client.greet
Website::Client.new.do_stuff
--output:--
Website::Wrapper
Website::Wrapper
Website::Wrapper
Can you modify that example to show the problem you are having?
Response to modified question:
Is this just bad practice?
Wouldn't it be surprising to call Base::Client.greet and get Website::Wrapper?
Is there an easy way to have methods called in the subclass default to
that class' namespace?
What do you mean by that? There is no class method named greet defined in Website::Client's singleton class. If you want to override Base::Client.greet you can do that.
Also, you are writing Website::Client when you call Website::Client.greet, so you already know from which class the method call originates...but inside Base::Client.greet, you can add the line puts self, and that will identify the object that called the method, which is the class Website::Client.
Related
I'm near the finish of the Ruby track in Code Academy, and I'm curious about a peculiar thing: I was under the impression that a class is a repository of constants, methods, etc... and that in order to access most of them, you would first need to create an instance of that class or in some cases the methods of themselves can be invoked (as in they are all technically part of the global object). And then I saw something like this:
#Worked
Time.now
I understood as this as the method [now] of instance of class [Time] being invoked. I then tried to invoke the method on its own:
#Failed
now
and that failed, and I assumed that while a method can be created in the general scope [as part of the global object], if it relies on initialized variables of "parent" class, it cannot be called on its own, because it would not know which object to search for those initialized variables. Following that I created a test class:
class Clock
def initialize
#hours = 1
#minutes = 30
end
def showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
#this worked
watch = Clock.new
watch.showTime
#this failed
showTime
I then just created a basic method (assuming it's in the global level)
def mymethod
puts "The mighty METHOD!"
end
#Works
mymethod
and calling this method the way I did, without referencing the global object worked. So... the questions I have are as follows:
How can [Time.now] be called in this fashion? Shouldn't there be an instance of Time first created?
Why can't I call the method [now] on its own? Am I right that it relies on resources that it cannot find when called this way?
Why could I not call the method showTime on its own? But if I define any method on the "global" level I can access it without referencing the global object
First of all, your intuition is correct.
Every methods must be an instance method of some receiver.
Global methods are defined as private instance methods on Object class and hence seem to be globally available. Why? From any context Object is always in the class hierarchy of self and hence private methods on Object are always callable without receiver.
def fuuuuuuuuuuun
end
Object.private_methods.include?(:fuuuuuuuuuuun)
# => true
Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class class and may have singleton methods.
class A
class << self # the singleton class
def example
end
end
end
A.singleton_class.instance_methods.include?(:example)
# => true
Alternative ways of defining class methods are
class A
def self.example
end
end
# or
def A.example
end
Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name) as follows
str = "hello"
def str.square_size
size * size
end
str.square_size
# => 25
"any other string".square_size
# => raises NoMethodError
Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on Enumerable) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again.
This is known as a class method. If CodeAcademy didn't cover it, that's a shame. Here's some examples:
# basic way
class Foo
def self.bar; :ok; end
end
Foo.bar # => :ok
# alternate syntax
class Foo
class << self
def bar; :ok; end
end
end
# alternate syntax, if Foo class already exists
def Foo.bar; :ok; end
# alternate approach if Foo class already exists
Foo.class_exec do
def bar; :ok; end
end
# to define a class method on an anonymous 'class' for a single instance
# you won't need to use this often
Foo.new.singleton_class.class_exec do
def bar; :ok; end
end
# to define a class method on an instance's actual class
Foo.new.class.class_exec do
def bar; :ok; end
end
Another way to get class methods is to extend a module.
module FooMethods
def bar; :ok; end
end
module Foo
extend FooMethods
end
Foo.bar # => :ok
Note that with Modules, the methods are always defined as instance methods. This way they can be either extended into class scope or included into instance scope. Modules can also have class methods, using the exact same syntax / examples as shown above with classes. However there's not such as easy to load a module's class methods via include or extend.
How can [Time.now] be called in this fashion? Shouldn't there be an
instance of Time first created?
The Time.now method is a class method, not an instance method and therefore can be called directly on the Time class rather than an instance of it Time.new
Class methods are defined on the class themselves using the self keyword:
class Time
def self.now
# code
end
end
Time.now # works
Why can't I call the method [now] on its own? Am I right that it
relies on resources that it cannot find when called this way?
When you call a method "on its own" you're actually implicitly calling it on self:
self.now
The above is the same as just doing:
now
Why could I not call the method showTime on its own? But if I define
any method on the "global" level I can access it without referencing
the global object
You defined the showTime method on a specific class so you have to send that method to that class. When you define a method in the "global" scope you're implicitly defining it on self and the subsequent call to mymethod is actually self.mymethod so it will work.
Time.now is a class method.
To define a class method, you need to define the method with self. : def self.method_name
class Clock
#hours = 1
#minutes = 30
def self.showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
Clock.showTime
#=> The time is: 1:30
If you want to call now on its own, you can do so inside Time class :
class Time
puts now
#=> 2017-01-19 22:17:29 +0100
end
I have this module with a method:
module MySqlConnection
def database_connect(application)
# Code in here
end
end
I have a second module with a class that uses database_connect:
module ResetPopups
class PopupsOff
include MySqlConnection
def self.reset_popup
database_connect("#{APP}")
end
end
end
When I call:
ResetPopups::PopupsOff.reset_popup
I get an undefined method database_connect. Why does this happen?
include adds module methods as instance methods, while extend adds them as singleton methods. Since you want to use this in the context of class (singleton context), you need to use extend:
extend MySqlConnection
module ResetPopups
class PopupsOff
extend MySqlConnection
def self.reset_popup
database_connect("#{APP}")
end
end
end
would work
What is hapening here, is that you include MySqlConnection, which makes method defined in it (database_connect) instance methods. But you use this module in the class scope, calling the database_connect on the class.
I have some problem with extending class with instance method after separate module is included into separate class
module ActsAsCommentable
def self.included(commentable)
Thread.class_eval do
def commentable
p "disqusable is #{commentable}"
p "disqusable class is #{commentable}"
end
end
end
end
class Thread
#some code...
end
class Asset
include ActsAsCommentable
end
And now I want to call this method somelike this:
thread = Thread.new
thread.commentable
The problem is, of course is that there is no binding with include method for class eval, and I could save variables that I want to pass into class eval in ActsAsCommentable module, but I dont want to. Is there a better way?
I tried to do instead
module ActsAsCommentable
def self.included(commentable)
class << Thread
define_method :commentable do
p "disqusable is #{commentable}"
p "disqusable class is #{commentable}"
end
end
end
end
But As I guessed this creates instance method for singletone object of class and therefore I can call it only through
Thread.commentable
And again, no binding...
If I understand you correctly, you need to be able to access the commentable variable inside your Thread extension, right?
If so, just change this:
Thread.class_eval do
To this:
Thread.class_exec(commentable) do |commentable|
And it should work.
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.
i've got a module that wants to use data provided by the class that included it - but at the class level, not the instance level.
the goal is to have class 'metadata' provided to a module that the class includes, so that the module can use the metadata during the included call.
this works:
module Bar
def value
#value
end
def baz
puts "the value is: #{value}"
end
end
module Foo
def self.included(mod)
mod.extend(Bar)
mod.baz
end
end
class MyClass
#value = "my class defined this"
include Foo
end
the output of this code is
the value is: my class defined this
i'm not sure if the use of #value is good or not... it seems odd to me that i require this to be set before the include Foo happens, not from a technical perspective (i know why it's required to be done in this order) but from an idiomatic or usability perspective.
... is there a better way / more idiomatic way of accomplishing this?
If you really want to use the class metadata in the moment you're including a module, given the 'included' method runs on its own scope, it's best to have a class method providing the metadata to it.
Also, if the metadata is not going to be manipulated, its better to declare it as a constant.
module Bar
def self.included(base)
puts "the value is: #{base.metadata}"
end
end
class MyClass
VALUE = "MyClass metadata"
def self.metadata
VALUE
end
include Bar
end
class OtherClass
VALUE = "OtherClass metadata"
def self.metadata
VALUE
end
include Bar
end
Of course you can declare the metadata anyway you want, as long as its accessible by a class method to your Module.
Also, its not common to do these kind of metadata manipulation in the module's 'included' method and the necessity of ordering your statements on the class level is a bit brittle, so you might want to try to find a different solution to your original problem instead.
If you want to the class to pass an argument to the mixin, then why not use one of the Ruby constructs that actually does allow passing an argument?
class Object
private
def Bar(metadata)
Module.new do
include Bar
define_singleton_method(:included) do |base|
puts "the value is: #{metadata}"
end
end
end
end
module Bar
# put common behavior here
end
class MyClass
include Bar 'MyClass metadata'
end
class OtherClass
include Bar 'OtherClass metadata'
end
This is a pretty common idiom that is for example used by the delegate library in the stdlib.