-1

How can we do:

instance = Object.allocate  ## Doesn't call initialize(). Object is just a sample class.
...
# Somewhere instance would get itself initialized. I do magic.
...
instance.initialized?  ## There's no method like that.

?

Of course I ask this not wanting to use flags anywhere. I want to know a general solution for default behaviours like it would work even for a simple instance of Object.

konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • 1
    Basically, this is equivalent to asking if there's a way to tell if a do-nothing method has been called. `Object#initialize` does nothing (you may override it in subclasses to provide special initialization behavior for your objects), so there's no way to tell whether or not it's been called. – Ajedi32 Jun 27 '14 at 15:00
  • @Ajedi32 I actually worry more about library classes which we can't always modify or is not always good to modify. I must make sure the instance would properly call initialize() of it. – konsolebox Jun 27 '14 at 15:10
  • 1
    I'd suggest you take a look at this http://stackoverflow.com/questions/7137238/how-can-i-intercept-method-call-in-ruby – Ajedi32 Jun 27 '14 at 15:25
  • I really question the use case of this. Why the restriction of "not wanting to use flags"? I'm pretty sure that this is impossible without using flags, monkey patching classes, or something similar. – Max Jun 27 '14 at 19:59
  • @Max Yes sorry. I actually just mean that I wouldn't explicitly add the flag on a natural class declaration. I also hope that not another subclass goes between the class and the instance to not make things a bit inefficient. I got some ideas from the link Ajedi32 provided but I'm still yet to understand them significantly. – konsolebox Jun 27 '14 at 20:16
  • Again, what is your use case? Unless you _really_ know what you're doing, messing with the innards of Ruby like this is not a good way to go about things. – Max Jun 27 '14 at 21:17
  • @Max See my found answer to my question. – konsolebox Jun 27 '14 at 22:38

1 Answers1

0

So I actually ended up with this solution. I'm still open for suggestions.

class ::Object
  def object(name, klass = Object, &block)
    instance = klass.allocate
    if instance.method(:initialize).owner == BasicObject
      instance.instance_exec(&block) if block_given?
    else
      raise "No block given." unless block_given?
      instance.instance_exec do
        def initialize(*args)
          @__initialized = true
          super
        end
      end
      instance.instance_exec(&block)
      instance.instance_exec do
        raise "Instance of #{klass} needs to be initialized." unless @__initialized
        remove_instance_variable :@__initialized
      end
    end
    (self.is_a?(Module) ? self : self.class).const_set(name, instance)
  end
end

I could use it like

object :Hey, SomeClassWithInitialize do
  puts "Perhaps sometimes I'd be doing some things first before initializing."

  initialize

  puts "And other things after initializing."

  def hey!
    puts "Hey!"
  end
end

Hey.hey!

Update: Turns out that there really is no function in Ruby that declares a flag that initialize is called. All calls from rb_obj_call_init to rb_obj_dummy does nothing significant to this.

̶I̶ ̶m̶a̶y̶ ̶j̶u̶s̶t̶ ̶c̶o̶n̶s̶i̶d̶e̶r̶ ̶u̶s̶i̶n̶g̶ ̶s̶i̶m̶p̶l̶e̶ ̶s̶i̶n̶g̶l̶e̶t̶o̶n̶s̶ ̶f̶o̶r̶ ̶i̶n̶s̶t̶a̶n̶c̶e̶s̶ ̶t̶h̶a̶t̶ ̶d̶o̶e̶s̶n̶'̶t̶ ̶i̶n̶h̶e̶r̶i̶t̶ ̶a̶n̶y̶t̶h̶i̶n̶g̶,̶ ̶a̶n̶d̶ ̶̶S̶i̶n̶g̶l̶e̶t̶o̶n̶#̶i̶n̶s̶t̶a̶n̶c̶e̶̶ ̶f̶o̶r̶ ̶a̶n̶y̶t̶h̶i̶n̶g̶ ̶t̶h̶a̶t̶ ̶d̶o̶e̶s̶ ̶o̶v̶e̶r̶ ̶t̶h̶i̶s̶ ̶m̶e̶t̶h̶o̶d̶ ̶b̶u̶t̶ ̶i̶t̶ ̶w̶o̶u̶l̶d̶ ̶o̶n̶l̶y̶ ̶b̶e̶ ̶c̶o̶n̶c̶l̶u̶d̶e̶d̶ ̶w̶h̶e̶n̶ ̶I̶ ̶a̶c̶t̶u̶a̶l̶l̶y̶ ̶u̶s̶e̶ ̶o̶n̶e̶.̶ Classes declared with Singleton does not inherit. I forgot.

Using an alias and an extra method was actually not needed.

konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • 2
    This is some... interesting code. 1) `class ::Object` is redundant - a loose `def` would accomplish the same thing. 2) I'm pretty sure `instance.method(:initialize).receiver` is always going to be `instance`. 3) The alias is unnecessary and pollutes the singleton - you can store the initialize method in a variable outside the `instance_exec` and invoke it inside, since blocks are closures. 4) Why all the `instance_exec` and `const_set`? You're basically treating instances like classes. Why? Why??? – Max Jun 28 '14 at 03:33
  • @Max The main reason why I do this is to simulate static classes in C++, but still able to work well with inheritance. I find this method more efficient than known singleton tricks in Ruby. I intended to do `class ::Object` explicitly just to tell the programmer that the function is really intended to be declared as an extension in Object. Yes I checked - `instance.method(:initialize).receiver` really does always show `instance` so I still need more efficient tricks to have it done well. I'm unable to move the alias outside yet. It doesn't make the code work. How exactly is it done? – konsolebox Jun 28 '14 at 06:25
  • I plan to port my [project](http://sourceforge.net/p/playshell/code/ci/master/tree/) to Ruby just to learn significantly from the language and get some stable practice methods on my own. To keep modular coding easy I have to have a function like that. I don't want declaring classes and declaring instances of singletons separately. – konsolebox Jun 28 '14 at 06:27