Ruby ERB - create a content_for method

I am currently working on an ERB View class for a gem. With this class, I would like to have some helper methods for ERB templates.
This is normal for basic helpers such as h(string). I found erbhgem that help me understand how context works.
But now I'm trying to create a method content_for, for example, in Rails or Sinatra.

The first time I used a simple one Procto capture a view block, and then just called a method callto print it. At first, it worked quite well. But after I finished watching, I saw what the wired think, some materials are printed several times. Therefore, I review the Sinatra ContentFor helper to understand how they did it, and I copy some methods of this helper. I have no errors, but the block return is always empty ... and I really don't know why.

My knowledge of ERB is not good enough to know how ERB buffering works.

the code

Here is the gist that explains the status of my code. I extracted the code from my library and simplified it a bit.

https://gist.github.com/nicolas-brousse/ac7f5454a1a45bae30c52dae826d587f/66cf76c97c35a02fc6bf4a3bc13d8d3b587356de

What I need?

, content_for , Rails Sinatra.

!

+4
1

, , , , . , , .

, ERB. eoutvar .

erb = ERB.new(str, nil, "<>", "@_erbout")

capture, content_for .

(gist)

def content_for(key, content = nil, &block)
  block ||= proc { |*| content }
  content_blocks[key.to_sym] << capture_later(&block)
end

def content_for?(key)
  content_blocks[key.to_sym].any?
end

def yield_content(key, default = nil)
  return default if content_blocks[key.to_sym].empty?
  content_blocks[key.to_sym].map { |b| capture(&b) }.join
end

def capture(&block)
  @capture = nil
  @_erbout, _buf_was = '', @_erbout
  result = yield
  @_erbout = _buf_was
  result.strip.empty? && @capture ? @capture : result
end

def capture_later(&block)
  proc { |*| @capture = capture(&block) }
end
0

Source: https://habr.com/ru/post/1651911/


All Articles