Defining class methods

T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

It seems there are 3 ways of defining class methods (at least in common
usage):

1) Defining a method on self:

def self.method

2) Opening up self and defining the methods directly:

class << self
def method
...
end

3) Placing class methods into a module, and extending a class with that:

module ClassMethods
def method
...
end

extend ClassMethods

--

Which of these do you use and which do you prefer? Do you use all three? Do
you think class << self is fugly and confusing?

I used to use class << self quite frequently and have been shifting to using
modules when dealing with a large number of class methods. I can't really
say I'm a huge fan.
 
A

Anurag Priyam

It seems there are 3 ways of defining class methods (at least in common
usage):

1) Defining a method on self:

def self.method

2) Opening up self and defining the methods directly:

class << self
=A0def method
=A0...
end

3) Placing class methods into a module, and extending a class with that:

module ClassMethods
=A0def method
=A0...
end

extend ClassMethods

I use all three, depending on the situation. Generally, I use method 2
(class << self), but if I have an idea that I will be needing only
one, or two class methods (like Module.included) I use method 1 (def
self.foo). If it makes sense to separate the class methods from the
core definition of a class (like helper/utility functions), I define
them in a module in a separate file.

I do not find class << self to be ugly and confusing :).

I picked up the following pattern going through DataMapper's code (or,
was it Ruby Best Practices?).

module Foo
def instance_method; puts "im"; end

module ClassMethods
def class_method1; puts "cm" end
end

def self.included(klass)
klass.extend(ClassMethods)
end
end

class Moo
include Foo
end

Foo.class_method #=3D> cm
Foo.new.instance_method #=3D> im
Foo.new.class_method #=3D> NoMethodError

A use case of this pattern for me was defining a Helper module for
Sinatra (modular) app where some helpers will be used in the
request-response context, while some in the context of the class that
inherits from Sinatra::Base.

--=20
Anurag Priyam
http://about.me/yeban/
 
A

Avdi Grimm

This one. That way you can always tell simply by looking at the method
definition that it is a class/module-level method.
 
B

botp

It seems there are 3 ways of defining class methods (at least in common
usage):

1) Defining a method on self:
2) Opening up self and defining the methods directly:
3) Placing class methods into a module, and extending a class with that:

4) Explicit definition

def C.m
...
end

i usually use this one since
1 it's visibly specified. The definition matches the use.
2 don't need to press pgup just to see who is self :)
3 if i change class name, it self checks itself since i need to retype.
4 less prone to self abuse :)

best regards -botp


best regards -botp
 
B

botp

I avoid this one because it makes class renames more of a chore.

Indeed. and that's what i like i about it. makes me think more on the
value of naming :)

best regards -botp
 
J

John Feminella

It seems there are 3 ways of defining class methods (at least in common

There's lots of ways to add a class method; Ruby is not a very
prescriptive language. Two more interesting examples that are used:
there's `instance_eval` on a Class instance:

X = Class.new
X.instance_eval do
def foo; "calling #foo!"; end
end

X.foo
# => "calling #foo!"

or #class_eval on the class of your `Class` instance (which will be `Class`):

X.class.class_eval do
def bar; "calling #bar!"; end
end

X.bar
# => "calling #bar!"

It's not very complicated, but `class_eval` on a Class instance is
typically used only in some rather advanced (and/or cryptic)
metaprogramming, so you don't see it floating around a lot.

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/
 
S

Shadowfirebird

I don't mean it as a put-down; I suspect the only person I'm putting down is myself. But I don't find that class methods actually come up much in my Ruby coding; when I find myself coding one I tend to stop and think hard about whether I actually need it.

And when I do use one it's always your type (1). Why would I want to define a class method anywhere else but in the class? I do understand that for DSLs, all the rest of this syntax is really useful. But -- showing my ignorance here -- is it really of any practical value elsewhere?
 
A

Avdi Grimm

I don't mean it as a put-down; I suspect the only person I'm putting down=
is myself. =A0 But I don't find that class methods actually come up much i=
n my Ruby coding; when I find myself coding one I tend to stop and think ha=
rd about whether I actually need it.

Indeed. Class methods in Ruby are a code smell: not always wrong, but
you should always think about why you're choosing a class-level method
instead of instance-level.

I think most of the class/module-level methods I write are "macros" -
e.g. methods along the lines of Ruby's #attr_accessor.

--=20
Avdi Grimm
http://avdi.org
 
J

John Feminella

Indeed. Class methods in Ruby are a code smell: not always wrong, but
you should always think about why you're choosing a class-level method
instead of instance-level.

I don't know if I'd go so far as to say they're a code smell. Without
class methods a number of very useful Ruby DSLs wouldn't exist in
their current form (RSpec, Cucumber, Rails, etc., just to name a few).
I agree that they can be abused or misused, but that's true of pretty
much any construct in any language, isn't it?

I'd probably arrange my skepticism of a class method from lowest to
highest in this way, depending on its features:

* part of a DSL (`describe`, `Before`, `callback { ... }`, etc.)
* repository pattern (Widget.find(...))
* factory pattern (Widget.orange # =3D> <orange Widget instance>)
* method takes more than a parameter or two
* non-factory class method with variable args
* instance of the class method's class is in the arguments/params
list (often very questionable)

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/



n is myself. =C2=A0 But I don't find that class methods actually come up mu=
ch in my Ruby coding; when I find myself coding one I tend to stop and thin=
k hard about whether I actually need it.
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

And when I do use one it's always your type (1). Why would I want to define
a class method anywhere else but in the class? I do understand that for
DSLs, all the rest of this syntax is really useful. But -- showing my
ignorance here -- is it really of any practical value elsewhere?


Well, more specific than DSLs: metaprogramming, and DSLs that generate code.

Some of the more abject design patterns, such as the factory pattern, can
often be avoid thanks to a combination of Ruby's dynamism and class methods.

The class is also a great place to stick state shared by all instances of
that class, such as the configuration details for accessing a particular
network service.
 
S

Sean O'Halpin

It seems there are 3 ways of defining class methods (at least in common
usage):

1) Defining a method on self:

def self.method

2) Opening up self and defining the methods directly:

class << self
=A0def method
=A0...
end

3) Placing class methods into a module, and extending a class with that:

module ClassMethods
=A0def method
=A0...
end

extend ClassMethods

--

Which of these do you use and which do you prefer? Do you use all three? = Do
you think class << self is fugly and confusing?

I used to use class << self quite frequently and have been shifting to us= ing
modules when dealing with a large number of class methods. I can't really
say I'm a huge fan.

It depends on whether and how you want to allow methods to be
overridden. Using #extend and 'def self.xxx' are not the same, viz:

module A
def run
puts "A"
end
end

class Foo
extend A
end

class Bar
extend A
end

Foo.run # =3D> "A"
Bar.run # =3D> "A"

module B
def run
puts "B"
end
end

class Foo
def self.run
puts "foo"
end
end

Foo.extend(B)
Bar.extend(B)

Foo.run # =3D> "foo" - extend does not
override a def self.method
Bar.run # =3D> "B" - but it does override a
previously defined extension

class Foo
class << self
def run
puts "bar"
end
end
end

Foo.run # =3D> "bar" - using 'class << self;
def method' ... same as 'def self.method'

Personally, I've come to prefer using #extend.

Regards,
Sean
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,150
Members
46,696
Latest member
BarbraOLog

Latest Threads

Top