How come in Ruby it's possible to directly have an if statement directly in the class declaration? AKA:
class ApplicationController < ActionController::Base
if foo
bar = "x"
end
end
I know there is some class instance variables, since the Class inherits from Object, is it the same thing?
I just need some clarification about this whole thing :)
Thanks!
How come in Ruby it's possible to directly have an if statement directly in the class declaration
Because it's not a class "declaration", it's a class body, i.e. it's executable code just like a method body, a block body, a loop body or a script body.
The body of a class declaration is code just like everything else in Ruby. That's how you can use methods like attr_accessor, private and include — those are all just methods of the class. It's part of Ruby's philosophy of pervasive object orientation.
Without any problem. Class declaration code normally gets executed, with self = class itself, no problem defining local variables such as foo. Just remember that you are not in the class instance, but in the class itself.
class ApplicationController < ActionController::Base
foo = true
if foo
bar = "x"
end
puts bar
end
Should print "x"
Related
Looking through the sourcecode of the redis-store RubyGem, I stumbled upon this syntax I hadn't seen before:
class Foo < self
# ...
end
My Google-Fu apparently isn't powerful enough, because I've been able to find nothing that describes what this does.
What I'm guessing this does, is somehow reopening Foo, extending it with itself as superclass, thereby making it possible to override methods that can call the original definition as super. Am I close?
class Foo < Bar
end
Is how you tell Ruby that Foo inherits from Bar.
Within a class definition, self refers to the class itself:
# prints Foo
class Foo
puts self
end
So
class Foo
class Bar < self
end
end
Just says that Bar is nested under Foo and it inherits from it.
The main thing that you seem to be messing is just this: the superclass portion of a Ruby class definition is an arbitrary Ruby expression.
So, something like this is perfectly legal:
class Foo < if rand < 0.5 then Bar else Qux end end
Obviously, this doesn't make sense, but for example, in _why the lucky stiff's brilliant little web micro framework Camping, routes are defined like this:
class Edit < R '/post/(\d+)/edit'
and Migrations are defined like this:
class BlogInitialSchemaCreation < V 1.0
In ActiveRecord, migrations are defined like this:
class CreateProducts < ActiveRecord::Migration[5.0]
All of this simply uses the fact that whatever is to the right of the < in a class definition can by any arbitrary Ruby expression which is evaluated when the class definition is evaluated.
When creating models for the sequel database gem in ruby a syntax like this is used:
class Users < Sequel::Model(:users) # <= what method is getting called here?
# other stuff...
end
Where :users is the name of the table.
I would like to pass an argument to the base class like this when the child class is defined for one of my own classes, but I can't work out how to do it. I don't know what this syntax is called, and I couldn't find any examples of it in my googling. I tried looking at the source for Sequel::Model as well, but its such a big class I couldn't find the relevant section.
Does anyone how what this syntax is and how it works?
It's a common trick to make a normal class/module method call look like a parameterized type.
There is actually a module method Sequel::Model which takes a single argument and returns a class (see the source code).
Have you considered using the #inherited hook of Class?
http://ruby-doc.org/core-2.0.0/Class.html#method-i-inherited
From the docs in the link above:
class Foo
def self.inherited(subclass)
puts "New subclass: #{subclass}"
end
end
class Bar < Foo
end
class Baz < Bar
end
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.
I want to create a function that messes around with the classes passed to it. What would be the most idiomatic way to reopen those classes to add functionality? Here's what I mean:
def class_messer(target_object)
#would like to reopen class here with something like:
class target_object.class
#add methods
end
end
Obviously that syntax doesn't work. I could get the target_object's class and eval some strings, but that feels gross. Is there a more idiomatic way to do this?
I think you're looking for class_eval. If you want to reopen a class and you do not have the constant as is, but a reference, you can call class_eval on it and pass a block (or even a string) of code to be evaluated in that classes context.
def class_messer(target_object)
# assuming that target_object is an instance of desired class
target_object.class.class_eval do
#add methods
end
end
target_object.class.class_exec do
# add methods
end
Maybe it's not correct to change class, for example, if you had an instance of Array class and changed its class, then this change could impact on other instances of Array class. So instead use singleton class of instance and the definition of method will be:
target_object.send(:define_method, :new_method) do
#...
end
or
class << target_object
def new_method
#...
end
end
You can also do this:
class << target_object.class
end
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.