Question

Sorry for the vague question title, but I have no clue what causes the following:

module Capistrano
  class Configuration
    def puts string
      ::Kernel.puts 'test'
    end
  end
end

Now when Capistrano calls puts, I don't see "test", but I see the original output.

However, when I also add this:

module Kernel
  def puts string
    ::Kernel.puts 'what gives?'
  end
end

Now, suddenly, puts actually returns "test", not "what gives?", not the original content, but "test".

Is there a reasonable explanation why this is happening (besides my limited understanding of the inner-workings of Ruby Kernel)?

Things that look off to me (but somehow "seem to work"):

  • I would expect the first block to return 'test', but it didn't
  • I would expect the combination of the two blocks to return 'what gives?', but it returns 'test'?
  • The way I override the Kernel.puts seems like a never-ending loop to me?
Was it helpful?

Solution

module Capistrano
  class Configuration
    def puts string
      ::Kernel.puts 'test'
    end
    def an_thing
      puts "foo"
    end
  end
end

Capistrano::Configuration.new.an_thing

gives the output:

test

The second version also gives the same output. The reason is that you're defining an instance level method rather than a class level method (this post seems to do a good job explaining the differences). A slightly different version:

module Kernel
  def self.puts string
    ::Kernel.puts 'what gives?'
  end
end

does the following. Because it is causing infinite recursion, like you expected.

/tmp/foo.rb:14:in `puts': stack level too deep (SystemStackError)
    from /tmp/foo.rb:14:in `puts'
    from /tmp/foo.rb:4:in `puts'
    from /tmp/foo.rb:7:in `an_thing'
    from /tmp/foo.rb:18

shell returned 1

OTHER TIPS

I use an answer rather than a comment because of its editing capabilities. You can edit it to add more information and I may delete it later.

Now when Capistrano calls puts, I don't see "test", but I see the original output.

It's difficult to answer your question without seeing how Capistrano calls puts and which one. I would say it's normal if puts displays its parameter, using the original Kernel#puts (it is not clear what you call original output, I must suppose you mean the string given to puts).

  • I would expect the first block to return 'test', but it didn't

The only way I see to call the instance method puts defined in the class Configuration in the module Capistrano is :

Capistrano::Configuration.new.puts 'xxx'

or

my_inst_var = Capistrano::Configuration.new

and somewhere else

my_inst_var.puts 'xxx'

and of course it prints test. Again, without seeing the puts statement whose result surprises you, it's impossible to tell what's going on.

  • I would expect the combination of the two blocks to return 'what gives?', but it returns 'test'?

The second point is mysterious and I need to see the code calling puts, as well as the console output.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top