Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add behaviors to #content_for #744

Merged
merged 1 commit into from
Nov 29, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 54 additions & 14 deletions lib/nanoc/helpers/capturing.rb
Original file line number Diff line number Diff line change
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
96 changes: 95 additions & 1 deletion test/helpers/test_capturing.rb
Original file line number Diff line number Diff line change
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,100 @@ 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_content_for_with_existing_symbol_with_unrecognised_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, existing: :donkey do %>First content<% end %>}'
end

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

def test_dependencies
with_site do |_site|
# Prepare
Expand Down