Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

MyClass objects have a, b, and c instance variables (forgive my vague abstractions). Additionally, when writing these classes, I want to be able to set a, b, and c, but I don't want my users to be able to.

class MyClass
  attr_accessor :a, :b, :c
  private :a=, :b=, :c=
end

I would like MyClass to be instantiated via either of 2 ways such that I would like to be able to call the following:

f = MyClass.create_from_foo foo_data
b = MyClass.create_from_bar bar_data

and get instances of MyClass in f and b. f and b are indistinguishable once instantiated, but of course were created in different ways. After these calls, both f and b have an a, b, and c.

I would not like MyClass to be instantiated through new. Since these 2 ways of creating are both equally valid, I feel like "preferring" foo_data over bar_data or vice versa isn't an implication I'd like to make. Therefore, I feel like I should privatize new and only allow instances of MyClass to be created by these class methods to try to level the playing field. In other words, I'm trying to avoid this:

#don't want this
f = MyClass.new foo_data
b = MyClass.create_from_bar bar_data #not quite "fair" to bar_data

So, let me start to write these create_from_<type> class methods:

class MyClass

  #from earlier
  attr_accessor :a, :b, :c
  private :a=, :b=, :c=

  private_class_method :new

  def MyClass.create_from_foo foo_data
    #some parsing of foo_data and computation of a, b, and c
    myclass = MyClass.new
    myclass.a = a
    myclass.b = b
    #...
  end

  def MyClass.create_from_bar bar_data
    #again, computation of bar_data
    myclass.a = a
    myclass.b = b
    #...
  end
end

Now, if you've been following along, you'd notice I can't do this! I blocked myself out!

  • I privatized new because I didn't want my users to make MyClass objects this way. I want them to use the class methods. And in the class method definition space, I'm basically a user.
  • I privatized a=, b=, and c= because I don't want my users to change this stuff. (It would break my real world example). Again, however, I'm a user when defining a class method.

So, this is what I'm working with. How can I create instances of a "restrictive" class in class methods?

share|improve this question

2 Answers

up vote 4 down vote accepted

You were a bit tangled, you can do it a little simplier.

class MyClass
  attr_reader :a, :b, :c

  private_class_method :new

  def initialize(a,b)
    @a = a
    @b = b
  end

  def self.create_from_foo foo_data
    #some parsing of foo_data and computation of a, b, and c
    myclass = new(a,b)
    #...
  end

  def self.create_from_bar bar_data
    #again, computation of bar_data
    myclass = new(a,b)
    #...
  end
end
share|improve this answer
Clean and clear! Thanks! – t-mart Feb 13 '12 at 5:35

It is perfectly possible to call the private class methods from other class methods. However in Ruby you can't call private methods (other than setters) with an explicit receiver.

So if you just write new instead of MyClass.new, it will work fine.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.