Skip to content

Commit

Permalink
Add behaviors to #content_for
Browse files Browse the repository at this point in the history
  • Loading branch information
denisdefreyne committed Nov 29, 2015
1 parent 598de14 commit 2517cba
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 15 deletions.
68 changes: 54 additions & 14 deletions lib/nanoc/helpers/capturing.rb
Expand Up @@ -33,18 +33,17 @@ def initialize

def []=(item, name, content)
@store[item.identifier] ||= {}
if @store[item.identifier][name]
return if @store[item.identifier][name] == content
raise "Content_for was called twice with the same key: #{name}, this would overwrite content for the first call"
else
@store[item.identifier][name] = content
end
@store[item.identifier][name] = content
end

def [](item, name)
@store[item.identifier] ||= {}
@store[item.identifier][name]
end

def reset_for(item)
@store[item.identifier] = {}
end
end

class ::Nanoc::Int::Site
Expand All @@ -60,16 +59,28 @@ def captures_store_compiled_items
end
end

# @overload content_for(name, &block)
# @overload content_for(name, params = {}, &block)
#
# Captures the content inside the block and stores it so that it can be
# referenced later on. The same method, {#content_for}, is used for
# getting the captured content as well as setting it. When capturing,
# the content of the block itself will not be outputted.
#
# By default, capturing content with the same name will raise an error if the newly captured
# content differs from the previously captured content. This behavior can be changed by
# providing a different `:existing` option to this method:
#
# * `:error`: When content already exists and is not identical, raise an error.
#
# * `:overwrite`: Overwrite the previously captured content with the newly captured content.
#
# * `:append`: Append the newly captured content to the previously captured content.
#
# @param [Symbol, String] name The base name of the attribute into which
# the content should be stored
#
# @option params [Symbol] existing Can be either `:error`, `:overwrite`, or `:append`
#
# @return [void]
#
# @overload content_for(item, name)
Expand All @@ -85,15 +96,44 @@ def captures_store_compiled_items
def content_for(*args, &block)
if block_given? # Set content
# Get args
if args.size != 1
raise ArgumentError, 'expected 1 argument (the name ' \
"of the capture) but got #{args.size} instead"
case args.size
when 1
name = args[0]
params = {}
when 2
name = args[0]
params = args[1]
else
raise ArgumentError, 'expected 1 or 2 argument (the name ' \
"of the capture, and optionally params) but got #{args.size} instead"
end
name = args[0]
existing_behavior = params.fetch(:existing, :error)

# Capture and store
# Capture
content = capture(&block)
@site.unwrap.captures_store[@item, name.to_sym] = content

# Prepare for store
store = @site.unwrap.captures_store
case existing_behavior
when :overwrite
store[@item, name.to_sym] = ''
when :append
store[@item, name.to_sym] ||= ''
when :error
if store[@item, name.to_sym] && store[@item, name.to_sym] != content
raise "a capture named #{name.inspect} for #{@item.identifier} already exists"
else
store[@item, name.to_sym] = ''
end
else
raise ArgumentError, 'expected :existing_behavior param to #content_for to be one of ' \
":overwrite, :append, or :error, but #{existing_behavior.inspect} was given"
end

# Store
@site.unwrap.captures_store_compiled_items << @item.unwrap
store[@item, name.to_sym] << content
else # Get content
# Get args
if args.size != 2
Expand All @@ -112,8 +152,8 @@ def content_for(*args, &block)
# item from which we use content. For this, we need to manually edit
# the content attribute to reset it. :(
# FIXME: clean this up
unless @site.unwrap.captures_store_compiled_items.include? item
@site.unwrap.captures_store_compiled_items << item
unless @site.unwrap.captures_store_compiled_items.include?(item)
@site.unwrap.captures_store.reset_for(item)
item.forced_outdated = true
@site.unwrap.compiler.reps[item].each do |r|
r.snapshot_contents = { last: item.content }
Expand Down
72 changes: 71 additions & 1 deletion test/helpers/test_capturing.rb
Expand Up @@ -101,7 +101,7 @@ def test_different_sites
assert_equal 'Content Two', content_for(@item, :b)
end

def test_content_for_duplicate_symbols
def test_content_for_with_existing_symbol
with_site do |_site|
# Prepare
File.open('lib/helpers.rb', 'w') do |io|
Expand All @@ -126,6 +126,76 @@ def test_content_for_duplicate_symbols
end
end

def test_content_for_with_existing_symbol_with_error_option
with_site do |_site|
# Prepare
File.open('lib/helpers.rb', 'w') do |io|
io.write 'include Nanoc::Helpers::Capturing'
end
File.open('content/includer.erb', 'w') do |io|
io.write '[<%= content_for(@items["/includee/"], :blah) %>]'
end
File.open('Rules', 'w') do |io|
io.write "compile '*' do ; filter :erb ; end\n"
io.write "route '*' do ; item.identifier + 'index.html' ; end\n"
end

File.open('content/includee.erb', 'w') do |io|
io.write '{<% content_for :blah do %>First content<% end %><% content_for :blah, existing: :error do %>Second content<% end %>}'
end

assert_raises do
Nanoc::CLI.run(%w(compile))
end
end
end

def test_content_for_with_existing_symbol_with_overwrite_option
with_site do |_site|
# Prepare
File.open('lib/helpers.rb', 'w') do |io|
io.write 'include Nanoc::Helpers::Capturing'
end
File.open('content/includer.erb', 'w') do |io|
io.write '[<%= content_for(@items["/includee/"], :blah) %>]'
end
File.open('Rules', 'w') do |io|
io.write "compile '*' do ; filter :erb ; end\n"
io.write "route '*' do ; item.identifier + 'index.html' ; end\n"
end

File.open('content/includee.erb', 'w') do |io|
io.write '{<% content_for :blah do %>First content<% end %><% content_for :blah, existing: :overwrite do %>Second content<% end %>}'
end

Nanoc::CLI.run(%w(compile))
assert_equal '[Second content]', File.read('output/includer/index.html')
end
end

def test_content_for_with_existing_symbol_with_append_option
with_site do |_site|
# Prepare
File.open('lib/helpers.rb', 'w') do |io|
io.write 'include Nanoc::Helpers::Capturing'
end
File.open('content/includer.erb', 'w') do |io|
io.write '[<%= content_for(@items["/includee/"], :blah) %>]'
end
File.open('Rules', 'w') do |io|
io.write "compile '*' do ; filter :erb ; end\n"
io.write "route '*' do ; item.identifier + 'index.html' ; end\n"
end

File.open('content/includee.erb', 'w') do |io|
io.write '{<% content_for :blah do %>First content<% end %><% content_for :blah, existing: :append do %>Second content<% end %>}'
end

Nanoc::CLI.run(%w(compile))
assert_equal '[First contentSecond content]', File.read('output/includer/index.html')
end
end

def test_dependencies
with_site do |_site|
# Prepare
Expand Down

0 comments on commit 2517cba

Please sign in to comment.